home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: SysTools
/
SysTools.zip
/
ft-beta.zip
/
freetype
/
lib
/
ttfile2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-06
|
24KB
|
875 lines
/*******************************************************************
*
* ttfilemap.c 1.3
*
* Memory-Mapped file component ( replaces ttfile.c ).
*
* Copyright 1996, 1997 by
* David Turner, Robert Wilhelm, and Werner Lemberg
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
* NOTES :
*
* This implementation relies on the ANSI libc. You may wish to
* modify it to get rid of the libc and go straight to the your
* platform's stream routines.
*
* The same source code can be used for thread-safe and re-entrant
* builds of the library.
*
* Changes between 1.3 and 1.2 :
*
* - all functions report error values now
*
* - the stream semantics have also changed
*
******************************************************************/
#include "ttconfig.h"
const char _ttfile2_to_satisfy_ANSI_C_[] = "";
/* ANSI C prevents the compilation of empty units. We thus introduce */
/* a dummy external to get rid of compiler warnings/errors. */
/* Note that gcc's -ansi -pedantic do not report any error here.. */
/* Watcom, VC++ or Borland C++ do however.. */
#ifdef HAVE_MMAP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/mman.h>
#ifndef MAP_FILE
#define MAP_FILE 0x00
#endif
/*
* The prototype for munmap() is not provided on SunOS. This needs to
* have a check added later to see if the GNU C library is being used.
* If so, then this prototype is not needed.
*/
#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
extern int munmap( caddr_t addr, int len );
#endif
#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include "freetype.h"
#include "tttypes.h"
#include "tterror.h"
#include "ttengine.h"
#include "ttmutex.h"
#include "ttmemory.h"
#include "ttfile.h" /* our prototypes */
const TFileFrame Null_FileFrame = { NULL, 0, 0 };
/* This definition is mandatory for each file component !! */
struct filemap {
char* base; /* base address of mapped file */
int refcount; /* reference count for mmaped region */
long size; /* stream size in file */
long offset; /* offset in file */
};
typedef struct filemap TFileMap;
#define ADDRESS(_map) (unsigned char*)((_map)->base + (_map)->offset)
typedef struct _TStream_Rec
{
TFileMap* map;
long pos; /* cursor in mapped file */
} TStream_Rec;
typedef TStream_Rec* PStream_Rec;
#define STREAM2REC(x) ((TStream_Rec*)(x).z)
#define REC2STREAM(x) ((TT_Stream)(x))
/* The TFile_Component structure holds all the data that was */
/* previously declared static or global in this component */
/* */
/* It is accessible through the 'engine.file_component' */
/* variable in re-entrant builds, or directly through the */
/* static 'files' variable in other builds */
/* */
struct _TFile_Component
{
TT_Error dummy_error;
#ifndef TT_CONFIG_REENTRANT
TMutex lock; /* used by the thread-safe build only */
PStream_Rec stream; /* current stream */
TFileFrame frame; /* current frame */
#endif /* reentrant */
};
typedef struct _TFile_Component TFile_Component;
#ifdef TT_CONFIG_REENTRANT
#define files (*((TFile_Component*)engine.file_component))
/* a simple macro to access the file component's data */
#define CUR_Stream STREAM2REC(stream) /* re-entrant macros */
#define CUR_Frame (*frame)
#define STREAM_VARS stream,
#define STREAM_VAR stream
#else
#define CUR_Stream files.stream /* thread-safe macros */
#define CUR_Frame files.frame
#define STREAM_VARS /* void */
#define STREAM_VAR /* void */
static TFile_Component files;
/* the 'files' variable is only defined in non-reentrant builds */
#endif /* REENTRANT */
/* The macro CUR_Stream denotes the current input stream */
/* Note that for the re-entrant version, the 'stream' name has been */
/* chosen according to the macro STREAM_ARGS */
/* The macro CUR_Frame denotes the current file frame */
/* Note that for the re-entrant version, the 'frame' name has been */
/* chosen according to the macro FRAME_ARGS */
/* The macro STREAM_VAR is used when calling public functions */
/* that need an 'optional' stream argument */
/*******************************************************************
*
* Function : TTFile_Init
*
* Description : Init the File component
*
******************************************************************/
TT_Error TTFile_Init()
{
#ifdef TT_CONFIG_REENTRANT
TT_Error error;
/* in re-entrant builds, we need to allocate the file component */
/* data on the fly before anything else.. */
if ( ALLOC( engine.file_component, sizeof(TFile_Component) ))
return error;
#else /* non re-entrant builds */
engine.file_component = (void*)&files;
MUTEX_Create( files.lock );
files.stream = NULL;
ZERO_Frame( files.frame );
/* We don't need any frame cache :-) */
#endif
files.dummy_error = TT_Err_Ok;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TTFile_Done
*
* Description : Finalize the File component
*
******************************************************************/
TT_Error TTFile_Done()
{
#ifndef TT_CONFIG_REENTRANT
/* no frame cache */
MUTEX_Destroy( files.lock );
engine.file_component = NULL;
#else
FREE( engine.file_component );
#endif
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : AllocateMap
*
* Description : Allocate a new map from the table
*
* Output : pointer to new stream rec. NULL in case of failure
*
******************************************************************/
static
TFileMap* Allocate_Map()
{
TFileMap* result;
if ( MEM_Alloc( result, sizeof(TFileMap) ))
return NULL;
result->refcount = 1;
return result;
}
/*******************************************************************
*
* Function : ReleaseMap
*
* Description : Release a used map to the table if reference i
* counter reaches zero
*
* Input : map
*
* Output : None.
*
* Note : Called by TT_Close_File
*
******************************************************************/
static
void Release_Map ( TFileMap* map )
{
map->refcount--;
if ( map->refcount <= 0 )
{
munmap ( (char*)map->base, map->size );
FREE( map );
}
}
/*******************************************************************
*
* Function : TT_Open_Stream
*
* Description : opens the font file and saves the total file size.
*
* Input : filepathname pathname of the file to open
* stream address of target TT_Stream structure
*
* Output : error code.
* The target stream is set to NULL in case of failure.
*
******************************************************************/
TT_Error TT_Open_Stream( const char* filepathname,
TT_Stream* stream )
{
TT_Error error;
int file;
PStream_Rec stream_rec;
TFileMap* map;
struct stat stat_buf;
if ( ALLOC( *stream, sizeof(TStream_Rec) ) )
return error;
map = Allocate_Map();
if ( !map )
{
error = TT_Err_Out_Of_Memory;
goto Memory_Fail;
}
stream_rec = STREAM2REC(*stream);
file = open( filepathname, O_RDONLY );
if ( file < 0 )
goto File_Fail;
if ( fstat( file, &stat_buf ) < 0 )
goto Map_Fail;
map->offset = 0;
map->size = stat_buf.st_size + map->offset;
map->base = mmap( NULL,
map->size,
PROT_READ,
MAP_FILE | MAP_PRIVATE,
file,
0 );
if ( (long)map->base == -1 )
goto Map_Fail;
close( file );
stream_rec->map = map;
stream_rec->pos = 0;
#ifndef TT_CONFIG_REENTRANT
CUR_Stream = stream_rec;
#endif
return TT_Err_Ok;
Map_Fail :
close(file);
File_Fail :
error = TT_Err_Could_Not_Open_File;
FREE( map );
Memory_Fail :
FREE( *stream );
return error;
}
#ifdef TT_CONFIG_REENTRANT
/*******************************************************************
*
* Function : TT_Duplicate_Stream
*
* Description : Duplicate a stream for a new instance record
*
* Input : input_stream source stream to duplicate
* copy address of target duplicate stream
*
* Output : error code.
* The target stream is set to NULL in case of failure.
*
* Note : This function is only available to re-entrant builds of
* the engine.
*
******************************************************************/
TT_Error TT_Duplicate_Stream( TT_Stream input_stream,
TT_Stream* copy )
{
TT_Error error;
PStream_Rec stream_rec;
PStream_Rec copy_rec;
stream_rec = STREAM2REC(input_stream);
if ( ALLOC( copy_rec, sizeof(TStream_Rec) ) )
return error;
HANDLE_Set( *copy, copy_rec );
copy_rec->map->refcount++;
copy_rec->pos = 0;
return TT_Err_Ok;
}
#endif /* REENTRANT */
/*******************************************************************
*
* Function : TT_Close_Stream
*
* Description : Closes a stream.
*
* Input :
*
* Output : SUCCESS (always)
*
******************************************************************/
TT_Error TT_Close_Stream( TT_Stream* stream )
{
PStream_Rec rec = STREAM2REC(*stream);
Release_Map( rec->map );
FREE( rec );
HANDLE_Set( *stream, NULL );
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Use_Stream
*
* Description : copy or duplicate a given stream
*
* Input : org_stream original stream
* stream target stream ( copy or duplicate )
* error target error
*
* Output :
*
******************************************************************/
TT_Error TT_Use_Stream( TT_Stream org_stream,
TT_Stream* stream )
{
#ifndef TT_CONFIG_REENTRANT
MUTEX_Lock( files.lock );
/* lock file mutex */
*stream = org_stream;
/* copy the stream */
return TT_Err_Ok;
#else
return TT_Duplicate_Stream( org_stream, stream );
#endif
}
/*******************************************************************
*
* Function : TT_Done_Stream
*
* Description : forgets or discards a 'used' stream
*
* Input : stream the stream to forget
*
* Output : error code
*
******************************************************************/
TT_Error TT_Done_Stream( TT_Stream* stream )
{
#ifndef TT_CONFIG_REENTRANT
HANDLE_Set( *stream, NULL );
MUTEX_Release( files.lock );
return TT_Err_Ok;
#else
return TT_Close_Stream(stream);
#endif
}
/*******************************************************************
*
* Function : TT_Seek_File
*
* Description : Seeks the file cursor to a different position.
*
* Input : position new position in file
*
* Output : error code
*
******************************************************************/
TT_Error TT_Seek_File( STREAM_ARGS long position )
{
if ( position > CUR_Stream->map->size )
return TT_Err_Invalid_File_Offset;
CUR_Stream->pos = position;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Skip_File
*
* Description : Skips forward the file cursor.
*
* Input : distance number of bytes to skip
*
* Output : see TT_Seek_File
*
******************************************************************/
TT_Error TT_Skip_File( STREAM_ARGS long distance )
{
return TT_Seek_File( STREAM_VARS CUR_Stream->pos + distance );
}
/*******************************************************************
*
* Function : TT_Read_File
*
* Description : Reads a chunk of the file and copies it to memory.
*
* Input : buffer target buffer
* count length in bytes to read
*
* Output : error code
*
******************************************************************/
TT_Error TT_Read_File( STREAM_ARGS void* buffer, long count )
{
if ( CUR_Stream->pos + count > CUR_Stream->map->size )
return TT_Err_Invalid_File_Read;
MEM_Copy( buffer, ADDRESS(CUR_Stream->map) + CUR_Stream->pos, count );
CUR_Stream->pos += count;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Read_At_File
*
* Description : Reads file at a specified position.
*
* Input : position position to seek to before read
* buffer target buffer
* count number of bytes to read
*
* Output : error code
*
******************************************************************/
TT_Error TT_Read_At_File( STREAM_ARGS long position,
void* buffer,
long count )
{
TT_Error error;
if ( (error = TT_Seek_File( STREAM_VARS position )) ||
(error = TT_Read_File( STREAM_VARS buffer, count )) )
return error;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_File_Pos
*
* Description : Returns current file seek pointer.
*
* Input : none
*
* Output : current file position
*
******************************************************************/
Long TT_File_Pos( STREAM_ARG )
{
return CUR_Stream->pos;
}
/*******************************************************************
*
* Function : TT_Access_Frame
*
* Description : Notifies the component that we're going to read
* 'size' bytes from the current file position.
* This function should load/cache/map these bytes
* so that they will be addressed by the GET_xxx
* functions easily.
*
* Input : size number of bytes to access.
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes: The function fails if the byte range is not within the
* the file, or if there is not enough memory to cache
* the bytes properly (which usually means that aSize is
* too big in both cases).
*
******************************************************************/
TT_Error TT_Access_Frame( STREAM_ARGS FRAME_ARGS int size )
{
if ( CUR_Frame.address != NULL )
return TT_Err_Nested_Frame_Access;
if ( CUR_Stream->pos + size > CUR_Stream->map->size )
return TT_Err_Invalid_Frame_Access;
CUR_Frame.size = size;
CUR_Frame.address = ADDRESS(CUR_Stream->map) + CUR_Stream->pos;
CUR_Frame.cursor = CUR_Frame.address;
CUR_Stream->pos += size;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Check_And_Access_Frame
*
* Description : Notifies the component that we're going to read
* aSize bytes from the current file position.
* This function should load/cache/map these bytes
* so that they will be addressed by the GET_xxx
* functions easily.
*
* Input : size number of bytes to access.
*
* Output : SUCCESS on success. FAILURE on error.
*
* Notes: The function truncates aSize if the byte range is not
* within the file.
*
* It will fail if there is not enough memory to cache
* the bytes properly (which usually means that aSize is
* too big).
*
* It will fail if you make two consecutive calls
* to TT_Access_Frame(), without a TT_Forget_Frame() between
* them.
*
* The only difference with TT_Access_Frame() is that we
* check that the frame is within the current file. We
* otherwise truncate it.
*
******************************************************************/
TT_Error TT_Check_And_Access_Frame( STREAM_ARGS FRAME_ARGS int size )
{
Long readBytes;
if ( CUR_Frame.address != NULL )
return TT_Err_Nested_Frame_Access;
readBytes = CUR_Stream->map->size - CUR_Stream->pos;
if ( size > readBytes )
size = readBytes;
CUR_Frame.size = size;
CUR_Frame.address = ADDRESS(CUR_Stream->map) + CUR_Stream->pos;
CUR_Frame.cursor = CUR_Frame.address;
CUR_Stream->pos += size;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TT_Forget_Frame
*
* Description : Releases a cached frame after reading.
*
* Input : None
*
* Output : SUCCESS on success. FAILURE on error.
*
******************************************************************/
TT_Error TT_Forget_Frame( FRAME_ARG )
{
if ( CUR_Frame.address == NULL )
return TT_Err_Nested_Frame_Access;
CUR_Frame.address = NULL;
CUR_Frame.cursor = NULL;
CUR_Frame.size = 0;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : GET_Byte
*
* Description : Extracts a byte from the current file frame.
*
* Input : None or current frame
*
* Output : Extracted Byte
*
* NOTES : We consider that the programmer is intelligent enough
* not to try to get a byte that is out of the frame. Hence,
* we provide no bounds check here. (A misbehaving client
* could easily page fault using this call.)
*
******************************************************************/
unsigned char Get_Byte( FRAME_ARG )
{
return (unsigned char)(*CUR_Frame.cursor++);
}
/*******************************************************************
*
* Function : GET_Char
*
* Description : Extracts a signed byte from the current file frame.
*
* Input : None or current frame
*
* Output : Extracted char
*
* NOTES : We consider that the programmer is intelligent enough
* not to try to get a byte that is out of the frame. Hence,
* we provide no bounds check here. (A misbehaving client
* could easily page fault using this call.)
*
******************************************************************/
char Get_Char( FRAME_ARG )
{
return (char)(*CUR_Frame.cursor++);
}
/*******************************************************************
*
* Function : GET_Short
*
* Description : Extracts a short from the current file frame.
*
* Input : None or current frame
*
* Output : Extracted short
*
* NOTES : We consider that the programmer is intelligent enough
* not to try to get a byte that is out of the frame. Hence,
* we provide no bounds check here. (A misbehaving client
* could easily page fault using this call.)
*
******************************************************************/
short Get_Short( FRAME_ARG )
{
short getshort;
getshort = ((short)CUR_Frame.cursor[0] << 8) |
(short)CUR_Frame.cursor[1];
CUR_Frame.cursor += 2;
return getshort;
}
/*******************************************************************
*
* Function : GET_UShort
*
* Description : Extracts an unsigned short from the frame.
*
* Input : None or current frame
*
* Output : Extracted ushort
*
* NOTES : We consider that the programmer is intelligent enough
* not to try to get a byte that is out of the frame. Hence,
* we provide no bounds check here. (A misbehaving client
* could easily page fault using this call.)
*
******************************************************************/
unsigned short Get_UShort( FRAME_ARG )
{
unsigned short getshort;
getshort = ((unsigned short)CUR_Frame.cursor[0] << 8) |
(unsigned short)CUR_Frame.cursor[1];
CUR_Frame.cursor += 2;
return getshort;
}
/*******************************************************************
*
* Function : GET_Long
*
* Description : Extracts a long from the frame.
*
* Input : None or current frame
*
* Output : Extracted long
*
* NOTES : We consider that the programmer is intelligent enough
* not to try to get a byte that is out of the frame. Hence,
* we provide no bounds check here. (A misbehaving client
* could easily page fault using this call.)
*
******************************************************************/
long Get_Long( FRAME_ARG )
{
long getlong;
getlong = ((long)CUR_Frame.cursor[0] << 24) |
((long)CUR_Frame.cursor[1] << 16) |
((long)CUR_Frame.cursor[2] << 8 ) |
(long)CUR_Frame.cursor[3];
CUR_Frame.cursor += 4;
return getlong;
}
/*******************************************************************
*
* Function : GET_ULong
*
* Description : Extracts an unsigned long from the frame.
*
* Input : None
*
* Output : Extracted ulong
*
* NOTES : We consider that the programmer is intelligent enough
* not to try to get a byte that is out of the frame. Hence,
* we provide no bounds check here. (A misbehaving client
* could easily page fault using this call.)
*
******************************************************************/
unsigned long Get_ULong( FRAME_ARG )
{
unsigned long getlong;
getlong = ( ((unsigned long)CUR_Frame.cursor[0] << 24) |
((unsigned long)CUR_Frame.cursor[1] << 16) |
((unsigned long)CUR_Frame.cursor[2] << 8 ) |
(unsigned long)CUR_Frame.cursor[3] );
CUR_Frame.cursor += 4;
return getlong;
}
#endif /* HAVE_MMAP */
/* End */