972 lines
46 KiB
C
972 lines
46 KiB
C
|
/***************************************************************************/
|
||
|
/* */
|
||
|
/* ftsys.c */
|
||
|
/* */
|
||
|
/* ANSI-specific system operations (body). */
|
||
|
/* */
|
||
|
/* Copyright 1996-1999 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. */
|
||
|
/* */
|
||
|
/***************************************************************************/
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* This implementation of the `ftsys' component uses the standard ANSI C */
|
||
|
/* library. */
|
||
|
/* */
|
||
|
/* IMPORTANT NOTE: */
|
||
|
/* */
|
||
|
/* Porters, read carefully the comments in ftsys.h before trying to */
|
||
|
/* port this file to your system. It contains many essential */
|
||
|
/* remarks, and will ease your work greatly. */
|
||
|
/* */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
|
||
|
#include "ftsys.h"
|
||
|
#include "ftstream.h"
|
||
|
#include "ftdebug.h"
|
||
|
|
||
|
|
||
|
#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
|
||
|
#include "memdebug.c"
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
|
||
|
/* parameter of the PTRACE() and PERROR() macros, used to print/log */
|
||
|
/* messages during execution. */
|
||
|
/* */
|
||
|
#undef FT_COMPONENT
|
||
|
#define FT_COMPONENT trace_io
|
||
|
|
||
|
|
||
|
#undef CUR_SYSTEM /* just in case */
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* To ease porting, we use the macro SYS_STREAM to name the */
|
||
|
/* system-specific stream type. For example, it is a `FILE*' with the */
|
||
|
/* ANSI libc, it will be a file descriptor, i.e. an integer, when using */
|
||
|
/* the Unix system API, etc. */
|
||
|
/* */
|
||
|
#define SYS_STREAM FILE*
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* This implementation of ftsys uses the ANSI C library. Memory */
|
||
|
/* management is performed through malloc/free, i/o access through */
|
||
|
/* fopen/fread/fseek, and no synchronisation primitive is implemented */
|
||
|
/* (they contain dummy code) */
|
||
|
/* */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* I/O ACCESS AND MANAGEMENT */
|
||
|
/* */
|
||
|
/* We only define the `ANSI' resource class in this class. It is */
|
||
|
/* disk-based and provides a MRU cache in order to only keep the file */
|
||
|
/* descriptors of the 10 most recently used resource files. */
|
||
|
/* */
|
||
|
/* It simply contains two lists. One contains the `cached' resources */
|
||
|
/* with a valid FILE* pointer, the second contains all other `flushed' */
|
||
|
/* resource objects. */
|
||
|
/* */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Struct> */
|
||
|
/* FT_AnsiFileRec */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* The FT_AnsiFile class derives from FT_ResourceRec. */
|
||
|
/* */
|
||
|
/* <Fields> */
|
||
|
/* root :: The root resource class fields. */
|
||
|
/* */
|
||
|
/* pathname :: This is a copy of the ANSI file pathname used to open */
|
||
|
/* streams for the resource. A different implementation */
|
||
|
/* is free to use Unicode chars, or file i-node numbers, */
|
||
|
/* etc. */
|
||
|
/* */
|
||
|
/* file_size :: The size in bytes of the resource. This field should */
|
||
|
/* be set to -1 until the resource is first opened. */
|
||
|
/* */
|
||
|
typedef struct FT_AnsiFileRec_
|
||
|
{
|
||
|
FT_ResourceRec root;
|
||
|
char* pathname; /* the font file's pathname */
|
||
|
FT_Long file_size; /* file size in bytes */
|
||
|
|
||
|
} FT_AnsiFileRec, *FT_AnsiFile;
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* We use the macro STREAM_Name() as a convenience to return a given */
|
||
|
/* ANSI resource's pathname. Its `stream' argument is a FT_Resource */
|
||
|
/* which is typecasted to the FT_AnsiFile class. */
|
||
|
/* */
|
||
|
#define STREAM_Name( stream ) ((FT_AnsiFile)stream->resource)->pathname
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* We use the macro STREAM_File() as a convenience to extract the */
|
||
|
/* system-specific stream handle from a given FreeType stream object. */
|
||
|
/* */
|
||
|
#define STREAM_File( stream ) ((FILE*)stream->stream_id.pointer)
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* AnsiFile_Open */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* This function is used to open a system-stream for a given */
|
||
|
/* resource. */
|
||
|
/* */
|
||
|
/* Note that it must update the target FreeType stream object with */
|
||
|
/* the system-stream handle and the resource's size. */
|
||
|
/* */
|
||
|
/* Also, the `stream->base' field must be set to NULL for disk-based */
|
||
|
/* resources, and to the address in memory of the resource's first */
|
||
|
/* byte for memory-based ones. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* resource :: The source resource. */
|
||
|
/* stream :: The target stream object. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This function simply calls fopen() in the resource's file */
|
||
|
/* pathname. */
|
||
|
/* */
|
||
|
/* The stream object IS NOT CREATED by this function, but by its */
|
||
|
/* caller. */
|
||
|
/* */
|
||
|
static
|
||
|
FT_Error AnsiFile_Open( FT_AnsiFile resource,
|
||
|
FT_Stream stream )
|
||
|
{
|
||
|
FILE* file;
|
||
|
|
||
|
/* open the file */
|
||
|
file = fopen( resource->pathname, "rb" );
|
||
|
if ( !file )
|
||
|
{
|
||
|
PERROR(( "AnsiFile_Open: Could not open file `%s'\n",
|
||
|
resource->pathname ));
|
||
|
return FT_Err_Cannot_Open_Stream;
|
||
|
}
|
||
|
|
||
|
/* compute file size if necessary */
|
||
|
if ( resource->file_size < 0 )
|
||
|
{
|
||
|
fseek( file, 0, SEEK_END );
|
||
|
resource->file_size = ftell( file );
|
||
|
fseek( file, 0, SEEK_SET );
|
||
|
}
|
||
|
|
||
|
stream->resource = (FT_Resource)resource;
|
||
|
stream->stream_id.pointer = file;
|
||
|
stream->size = resource->file_size;
|
||
|
|
||
|
/* it's a disk-based resource, we don't need to use the `base' and */
|
||
|
/* `cursor' fields of the stream objects */
|
||
|
stream->base = NULL;
|
||
|
stream->cursor = NULL;
|
||
|
|
||
|
PTRACE1(( "AnsiFile_Open: Opened `%s' (%d bytes) successfully\n",
|
||
|
resource->pathname, resource->file_size ));
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* AnsiFile_Close */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Closes a given stream. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* stream :: The target stream object. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This function simply calls fclose() on the stream's ANSI FILE */
|
||
|
/* object. */
|
||
|
/* */
|
||
|
static
|
||
|
FT_Error AnsiFile_Close( FT_Stream stream )
|
||
|
{
|
||
|
PTRACE1(( "AnsiFile_Close: Closing file `%s'\n", STREAM_Name( stream ) ));
|
||
|
|
||
|
fclose( STREAM_File( stream ) );
|
||
|
|
||
|
stream->resource = NULL;
|
||
|
stream->stream_id.pointer = NULL;
|
||
|
stream->size = 0;
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* AnsiFile_Seek */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Seeks a stream to a given position. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* stream :: The target stream object. */
|
||
|
/* position :: The offset in bytes from the start of the */
|
||
|
/* resource/stream. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This function simply calls fseek() on the stream. */
|
||
|
/* */
|
||
|
/* The `seek' method is never called by the stream manager in case */
|
||
|
/* of a memory-based resource (i.e., when `stream->base' isn't NULL). */
|
||
|
/* */
|
||
|
static
|
||
|
FT_Error AnsiFile_Seek( FT_Stream stream,
|
||
|
FT_Long position )
|
||
|
{
|
||
|
if ( fseek( STREAM_File( stream ), position, SEEK_SET ) )
|
||
|
{
|
||
|
PERROR(( "AnsiFile_Seek: FAILED! Pos. %ld of `%s'\n",
|
||
|
position, STREAM_Name( stream ) ));
|
||
|
|
||
|
return FT_Err_Invalid_Stream_Seek;
|
||
|
}
|
||
|
|
||
|
PTRACE2(( "AnsiFile_Seek: Pos. %ld of `%s'\n",
|
||
|
position, STREAM_Name( stream ) ));
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* AnsiFile_Skip */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Skips a given number of bytes in an ANSI stream. Useful to skip */
|
||
|
/* pad bytes, for example. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* stream :: The target stream object. */
|
||
|
/* count :: The number of bytes to skip in the stream. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This function simply calls fseek() on the stream. */
|
||
|
/* */
|
||
|
/* The `skip' method is never called by the stream manager in case */
|
||
|
/* of a memory-based resource (i.e., when `stream->base' isn't NULL). */
|
||
|
/* */
|
||
|
static
|
||
|
FT_Error AnsiFile_Skip( FT_Stream stream,
|
||
|
FT_Long count )
|
||
|
{
|
||
|
if ( fseek( STREAM_File( stream ), count, SEEK_CUR ) )
|
||
|
{
|
||
|
PERROR(( "AnsiFile_Skip: FAILED! %ld bytes in `%s'\n",
|
||
|
count, STREAM_Name( stream ) ));
|
||
|
|
||
|
return FT_Err_Invalid_Stream_Seek;
|
||
|
}
|
||
|
|
||
|
PTRACE2(( "AnsiFile_Skip: %ld bytes in `%s'\n",
|
||
|
count, STREAM_Name( stream ) ));
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* AnsiFile_Pos */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Returns the current offset within an ANSI stream's resource. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* stream :: The target stream object. */
|
||
|
/* */
|
||
|
/* <Output> */
|
||
|
/* position :: The current offset. -1 in case of error. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This function simply calls ftell() on the stream. */
|
||
|
/* */
|
||
|
/* The `pos' method is never called by the stream manager in case */
|
||
|
/* of a memory-based resource (i.e., when `stream->base' isn't NULL). */
|
||
|
/* */
|
||
|
static
|
||
|
FT_Error AnsiFile_Pos( FT_Stream stream,
|
||
|
FT_Long* position )
|
||
|
{
|
||
|
*position = ftell( STREAM_File( stream ) );
|
||
|
if ( *position == -1 )
|
||
|
{
|
||
|
PTRACE2(( "AnsiFile_Pos: FAILED! In `%s'\n", STREAM_Name( stream ) ));
|
||
|
return FT_Err_Invalid_Stream_Seek;
|
||
|
}
|
||
|
|
||
|
PTRACE2(( "AnsiFile_Pos: For `%s'\n", STREAM_Name( stream ) ));
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* AnsiFile_Read */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Reads a given number of bytes from an ANSI stream into memory. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* stream :: The target stream object. */
|
||
|
/* buffer :: The target read buffer where data is copied. */
|
||
|
/* size :: The number of bytes to read from the stream. */
|
||
|
/* */
|
||
|
/* <Output> */
|
||
|
/* read_bytes :: The number of bytes effectively read from the */
|
||
|
/* stream. Used in case of error */
|
||
|
/* (i.e. FT_Err_Invalid_Stream_Read) by some parts of */
|
||
|
/* the library. */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This function simply calls fread() on the stream. */
|
||
|
/* */
|
||
|
/* It MUST return the error FT_Err_Invalid_Stream_Read in case of */
|
||
|
/* an over-read (i.e., reading more bytes from the stream that what */
|
||
|
/* is left), as the stream component checks for this specific value. */
|
||
|
/* */
|
||
|
/* The `read' method is never called by the stream manager in case */
|
||
|
/* of a memory-based resource (i.e., when `stream->base' isn't NULL). */
|
||
|
/* */
|
||
|
static
|
||
|
FT_Error AnsiFile_Read( FT_Stream stream,
|
||
|
FT_Char* buffer,
|
||
|
FT_Long size,
|
||
|
FT_Long* read_bytes )
|
||
|
{
|
||
|
*read_bytes = fread( buffer, 1, size, STREAM_File( stream ) );
|
||
|
if ( *read_bytes != size )
|
||
|
{
|
||
|
/* Note : we can have an over-read here when called by the */
|
||
|
/* function FT_Access_Compressed_Frame. This means */
|
||
|
/* that the following message should be a trace, */
|
||
|
/* rather than an error for disk-based resources.. */
|
||
|
/* */
|
||
|
/* the function must set the value of 'read_bytes' */
|
||
|
/* even if it returns an error code.. */
|
||
|
PTRACE2(( "AnsiFile_Read: FAILED! Read %ld bytes from '%s'\n",
|
||
|
size, STREAM_Name( stream ) ));
|
||
|
|
||
|
return FT_Err_Invalid_Stream_Read;
|
||
|
}
|
||
|
|
||
|
PTRACE2(( "AnsiFile_Read: Read %ld bytes to buffer 0x%08lx from `%s'\n",
|
||
|
size, (long)buffer, STREAM_Name( stream ) ));
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* The following table is the `virtual method table' for the `ANSI */
|
||
|
/* resource class', which methods are defined above. Its address is set */
|
||
|
/* in the `interface' field of all resource objects created by the */
|
||
|
/* function FT_Create_AnsiFile() (see below). */
|
||
|
/* */
|
||
|
static
|
||
|
FTRes_InterfaceRec FT_AnsiFile_Interface =
|
||
|
{
|
||
|
(FTRes_Open_Func) AnsiFile_Open,
|
||
|
(FTRes_Close_Func)AnsiFile_Close,
|
||
|
(FTRes_Seek_Func) AnsiFile_Seek,
|
||
|
(FTRes_Skip_Func) AnsiFile_Skip,
|
||
|
(FTRes_Pos_Func) AnsiFile_Pos,
|
||
|
(FTRes_Read_Func) AnsiFile_Read,
|
||
|
};
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* FT_Create_Resource */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Creates a new resource object. This function is called by the */
|
||
|
/* FT_New_Resource() function of the base layer. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* library :: The input library object. */
|
||
|
/* pathname :: The file's pathname as an ASCII string. */
|
||
|
/* */
|
||
|
/* <Output> */
|
||
|
/* aresource :: A handle to new resource object. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* Error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This functions does not open a stream. It simply copies the */
|
||
|
/* pathname within a fresh new resource object. */
|
||
|
/* */
|
||
|
EXPORT_FUNC
|
||
|
FT_Error FT_Create_Resource( FT_Library library,
|
||
|
const char* pathname,
|
||
|
FT_Resource* aresource )
|
||
|
{
|
||
|
FT_Int len;
|
||
|
FT_AnsiFile resource;
|
||
|
FT_Error error;
|
||
|
FT_System system;
|
||
|
|
||
|
|
||
|
if ( !library )
|
||
|
return FT_Err_Invalid_Library_Handle;
|
||
|
|
||
|
system = library->system;
|
||
|
|
||
|
if ( !pathname )
|
||
|
goto Fail_Null;
|
||
|
|
||
|
len = strlen( pathname );
|
||
|
if ( len == 0 )
|
||
|
goto Fail_Null;
|
||
|
|
||
|
resource = NULL;
|
||
|
|
||
|
if ( ALLOC( resource, sizeof ( *resource ) ) ||
|
||
|
ALLOC( resource->pathname, len + 1 ) )
|
||
|
goto Fail_Memory;
|
||
|
|
||
|
resource->root.library = library;
|
||
|
resource->root.interface = &FT_AnsiFile_Interface;
|
||
|
resource->root.flags = FT_RESOURCE_TYPE_DISK_BASED;
|
||
|
resource->file_size = -1;
|
||
|
strcpy( resource->pathname, pathname );
|
||
|
|
||
|
PTRACE1(( "Create_AnsiFile: Ansi resource created for `%s'\n",
|
||
|
pathname ));
|
||
|
|
||
|
*aresource = (FT_Resource)resource;
|
||
|
return FT_Err_Ok;
|
||
|
|
||
|
Fail_Null:
|
||
|
PERROR(( "Create_AnsiFile: Null pathname!\n" ));
|
||
|
return FT_Err_Invalid_Argument;
|
||
|
|
||
|
Fail_Memory:
|
||
|
if ( resource )
|
||
|
FREE( resource->pathname );
|
||
|
FREE( resource );
|
||
|
PERROR(( "Create_AnsiFile: Not enough memory to create resource!\n" ));
|
||
|
return error;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* FT_Destroy_Resource */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Discards a given resource object explicitly. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* resource :: The ANSI resource object. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* This function does not check whether runs or streams are opened */
|
||
|
/* for the resource (for now, we assume developer intelligence. */
|
||
|
/* We'll most probably lower our standard later to ease debugging :-) */
|
||
|
/* */
|
||
|
EXPORT_FUNC
|
||
|
FT_Error FT_Destroy_Resource( FT_Resource resource )
|
||
|
{
|
||
|
FT_System system = resource->library->system;
|
||
|
FT_AnsiFile ansi = (FT_AnsiFile)resource;
|
||
|
|
||
|
if ( !ansi || ansi->root.interface != &FT_AnsiFile_Interface )
|
||
|
{
|
||
|
PERROR((
|
||
|
"Destroy_AnsiFile: Trying to destroy an invalid resource!\n" ));
|
||
|
return FT_Err_Invalid_Resource_Handle;
|
||
|
}
|
||
|
|
||
|
PTRACE1(( "Destroy_AnsiFile: Destroying resource for `%s'\n",
|
||
|
ansi->pathname ));
|
||
|
|
||
|
FREE( ansi->pathname );
|
||
|
FREE( ansi );
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* MEMORY MANAGEMENT */
|
||
|
/* */
|
||
|
/* */
|
||
|
/* This part copies the old FreeType 1.0 and 1.1 memory management */
|
||
|
/* scheme that was defined in the file `ttmemory.h'. One can see that */
|
||
|
/* */
|
||
|
/* - a set of macros is defined for the memory operations used by the */
|
||
|
/* engine (MEM_Copy(), MEM_Move(), MEM_Set()). This comes from the */
|
||
|
/* fact that many compilers are able to inline these operations */
|
||
|
/* directly within the compiled code, rather than generating a call */
|
||
|
/* to the C library. However, this obliges us to include the */
|
||
|
/* `<string.h>' header file. */
|
||
|
/* */
|
||
|
/* If you provide your own memory operations, you can get rid of the */
|
||
|
/* `#include <string.h>' below. */
|
||
|
/* */
|
||
|
/* */
|
||
|
/* - the FT_Alloc() function has several essential properties that MUST */
|
||
|
/* be retained by each port: */
|
||
|
/* */
|
||
|
/* - It returns an error code, NOT the allocated block's base */
|
||
|
/* address. */
|
||
|
/* */
|
||
|
/* - It takes the address of a target pointer, where the block's base */
|
||
|
/* address will be set. If the size is zero, its value will be */
|
||
|
/* NULL, and the function returns successfully. */
|
||
|
/* */
|
||
|
/* - In case of error, the pointer's value is set to NULL and an */
|
||
|
/* error code is returned. */
|
||
|
/* */
|
||
|
/* - The new allocated block MUST be zero-filled. This is a strong */
|
||
|
/* convention the rest of the engine relies on. */
|
||
|
/* */
|
||
|
/* */
|
||
|
/* - the FT_Free() function has also its essentials: */
|
||
|
/* */
|
||
|
/* - It takes the address of a pointer which value is the block's */
|
||
|
/* base address. This is UNLIKE a standard `free()' which takes */
|
||
|
/* the block's base directly. */
|
||
|
/* */
|
||
|
/* - It accepts successfully the address of a pointer which value is */
|
||
|
/* NULL, in which case it simply returns. */
|
||
|
/* */
|
||
|
/* - The pointer is always set to NULL by the function. */
|
||
|
/* */
|
||
|
/* */
|
||
|
/* - The MEM_Alloc(), ALLOC(), and ALLOC_ARRAY() macros are used by the */
|
||
|
/* library and should NOT be modified by porters! */
|
||
|
/* */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
|
||
|
/* parameter of the PTRACE() and PERROR() macros, used to print/log */
|
||
|
/* messages during execution. */
|
||
|
/* */
|
||
|
#undef FT_COMPONENT
|
||
|
#define FT_COMPONENT trace_memory
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* FT_Alloc */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Allocates a new block of memory. The returned area is always */
|
||
|
/* zero-filled, this is a strong convention in many FreeType parts. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* system :: A handle to a given `system object' where allocation */
|
||
|
/* occurs. */
|
||
|
/* */
|
||
|
/* size :: The size in bytes of the block to allocate. */
|
||
|
/* */
|
||
|
/* <Output> */
|
||
|
/* P :: A pointer to the fresh new block. It should be set to */
|
||
|
/* NULL if `size' is 0, or in case of error. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
BASE_FUNC
|
||
|
FT_Error FT_Alloc( FT_System system,
|
||
|
FT_Long size,
|
||
|
void** P )
|
||
|
{
|
||
|
if ( !P )
|
||
|
{
|
||
|
PERROR(( "FT_Alloc: Invalid pointer address!\n" ));
|
||
|
return FT_Err_Invalid_Argument;
|
||
|
}
|
||
|
|
||
|
if ( size > 0 )
|
||
|
{
|
||
|
*P = malloc( size );
|
||
|
if ( !*P )
|
||
|
{
|
||
|
PERROR(( "FT_Alloc: Out of memory (%ld bytes requested)!\n",
|
||
|
size ));
|
||
|
|
||
|
return FT_Err_Out_Of_Memory;
|
||
|
}
|
||
|
|
||
|
#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
|
||
|
DM_Record( (char*)*P, size );
|
||
|
#endif
|
||
|
|
||
|
system->total_alloc += size;
|
||
|
|
||
|
/* ALWAYS ZERO-FILL THE BLOCK! */
|
||
|
MEM_Set( *P, 0, size );
|
||
|
}
|
||
|
else
|
||
|
*P = NULL;
|
||
|
|
||
|
PTRACE2(( "FT_Alloc: Size = %ld, pointer = 0x%08lx, block = 0x%08lx\n",
|
||
|
size, (long)P, (long)*P ));
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* FT_Realloc */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Reallocates a block of memory pointed to by `*P' to `Size' bytes */
|
||
|
/* from the heap, possibly changing `*P'. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* system :: A handle to a given `system object' where allocation */
|
||
|
/* occurs. */
|
||
|
/* */
|
||
|
/* size :: The size in bytes of the block to allocate. */
|
||
|
/* */
|
||
|
/* <InOut> */
|
||
|
/* P :: A pointer to the fresh new block. It should be set to */
|
||
|
/* NULL if `size' is 0, or in case of error. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
BASE_FUNC
|
||
|
FT_Error FT_Realloc( FT_System system,
|
||
|
FT_Long size,
|
||
|
void* *P )
|
||
|
{
|
||
|
void* Q;
|
||
|
|
||
|
|
||
|
if ( !P )
|
||
|
{
|
||
|
PERROR(( "FT_Realloc: Invalid pointer address!\n" ));
|
||
|
return FT_Err_Invalid_Argument;
|
||
|
}
|
||
|
|
||
|
/* if the original pointer is NULL, call FT_Alloc() */
|
||
|
if ( !*P )
|
||
|
return FT_Alloc( system, size, P );
|
||
|
|
||
|
/* if the new block if zero-sized, clear the current one */
|
||
|
if ( size <= 0 )
|
||
|
return FT_Free( system, P );
|
||
|
|
||
|
#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
|
||
|
DM_Forget( (char*)*P );
|
||
|
#endif
|
||
|
|
||
|
Q = (void*)realloc( *P, size );
|
||
|
if ( !Q )
|
||
|
{
|
||
|
PERROR(( "FT_Realloc: Reallocation failed!\n" ));
|
||
|
return FT_Err_Out_Of_Memory;
|
||
|
}
|
||
|
|
||
|
#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
|
||
|
DM_Record( (char*)Q, size );
|
||
|
#endif
|
||
|
|
||
|
*P = Q;
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* FT_Free */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Releases a given block of memory allocated through FT_Alloc(). */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* system :: A handle to a given `system object' where allocation */
|
||
|
/* occured. */
|
||
|
/* */
|
||
|
/* P :: This is the _address_ of a _pointer_ which points to the */
|
||
|
/* allocated block. It is always set to NULL on exit. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
/* <Note> */
|
||
|
/* If P or *P are NULL, this function should return successfully. */
|
||
|
/* This is a strong convention within all of FreeType and its */
|
||
|
/* drivers. */
|
||
|
/* */
|
||
|
BASE_FUNC
|
||
|
FT_Error FT_Free( FT_System system,
|
||
|
void* *P )
|
||
|
{
|
||
|
UNUSED( system );
|
||
|
|
||
|
PTRACE2(( "FT_Free: Freeing pointer 0x%08lx (block 0x%08lx)\n",
|
||
|
(long)P, (P ? (long)*P : -1) ));
|
||
|
|
||
|
if ( !P || !*P )
|
||
|
return FT_Err_Ok;
|
||
|
|
||
|
free( *P );
|
||
|
|
||
|
#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
|
||
|
DM_Forget( (char*)*P );
|
||
|
#endif
|
||
|
|
||
|
*P = NULL;
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* SYNCHRONIZATION MANAGEMENT */
|
||
|
/* */
|
||
|
/* */
|
||
|
/* This section deals with mutexes. The library can be compiled to */
|
||
|
/* two distinct thread support levels (namely single threaded and */
|
||
|
/* re-entrant modes). */
|
||
|
/* */
|
||
|
/* It protects its variables through the MUTEX_Lock() and */
|
||
|
/* MUTEX_Release() macros which are void in single threaded mode. */
|
||
|
/* */
|
||
|
/* It defines a typeless mutex reference type, `FT_Mutex', that you're */
|
||
|
/* free to redefine for your system's needs. */
|
||
|
/* */
|
||
|
/* The default implementation of ftsys.c contains only dummy functions */
|
||
|
/* which always return successfully. You NEED to specialize them in */
|
||
|
/* order to port ftsys.c to any multi-threaded environment. */
|
||
|
/* */
|
||
|
/*************************************************************************/
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
|
||
|
/* parameter of the PTRACE() and PERROR() macros, used to print/log */
|
||
|
/* messages during execution. */
|
||
|
/* */
|
||
|
#undef FT_COMPONENT
|
||
|
#define FT_COMPONENT trace_sync
|
||
|
|
||
|
|
||
|
#ifdef FT_CONFIG_THREADS
|
||
|
|
||
|
BASE_FUNC
|
||
|
FT_Error FT_Mutex_Create( FT_System system,
|
||
|
TMutex* mutex )
|
||
|
{
|
||
|
UNUSED( system );
|
||
|
|
||
|
mutex = (void*)-1;
|
||
|
system->num_mutexes++;
|
||
|
|
||
|
/* Insert your own mutex creation code here */
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
BASE_FUNC
|
||
|
void FT_Mutex_Delete( FT_System system,
|
||
|
TMutex* mutex )
|
||
|
{
|
||
|
UNUSED( system );
|
||
|
|
||
|
mutex = (void*)0;
|
||
|
system->num_mutexes--;
|
||
|
|
||
|
/* Insert your own mutex destruction code here */
|
||
|
}
|
||
|
|
||
|
|
||
|
BASE_FUNC
|
||
|
void FT_Mutex_Lock( FT_System system,
|
||
|
TMutex* mutex )
|
||
|
{
|
||
|
/* NOTE: It is legal to call this function with a NULL argument */
|
||
|
/* in which case an immediate return is appropriate. */
|
||
|
|
||
|
UNUSED( system );
|
||
|
|
||
|
if ( !mutex )
|
||
|
return;
|
||
|
|
||
|
/* Insert your own mutex locking code here */
|
||
|
}
|
||
|
|
||
|
|
||
|
BASE_FUNC
|
||
|
void FT_Mutex_Release( FT_System system,
|
||
|
TMutex* mutex )
|
||
|
{
|
||
|
/* NOTE: It is legal to call this function with a NULL argument */
|
||
|
/* in which case an immediate return is appropriate */
|
||
|
|
||
|
UNUSED( system );
|
||
|
|
||
|
if ( !mutex )
|
||
|
return;
|
||
|
|
||
|
/* Insert your own mutex release code here */
|
||
|
}
|
||
|
|
||
|
#endif /* FT_CONFIG_THREADS */
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* FT_New_System */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* This function is used to create and initialize new system objects. */
|
||
|
/* These are mainly used to let client applications and font servers */
|
||
|
/* specify their own memory allocators and synchronization */
|
||
|
/* procedures. */
|
||
|
/* */
|
||
|
/* <Output> */
|
||
|
/* system :: A handle to a given `system object'. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
EXPORT_FUNC
|
||
|
FT_Error FT_New_System( FT_System* system )
|
||
|
{
|
||
|
*system = (FT_System)malloc( sizeof ( **system ) );
|
||
|
|
||
|
if ( !*system )
|
||
|
return FT_Err_Out_Of_Memory;
|
||
|
|
||
|
/* the ANSI function `free()' is unable to return the number */
|
||
|
/* of released bytes. Hence, the `current_alloc' field of the */
|
||
|
/* system object cannot be used. */
|
||
|
|
||
|
(*system)->system_flags = FT_SYSTEM_FLAG_TOTAL_ALLOC |
|
||
|
FT_SYSTEM_FLAG_MUTEXES;
|
||
|
(*system)->total_alloc = 0;
|
||
|
(*system)->num_mutexes = 0;
|
||
|
|
||
|
#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
|
||
|
DM_Init_Mem();
|
||
|
#endif
|
||
|
|
||
|
/* initialize i/o management (nothing) */
|
||
|
|
||
|
/* initialize synchronisation (nothing) */
|
||
|
|
||
|
/* initialize streams (nothing) */
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*************************************************************************/
|
||
|
/* */
|
||
|
/* <Function> */
|
||
|
/* FT_Done_System */
|
||
|
/* */
|
||
|
/* <Description> */
|
||
|
/* Destroys a given FreeType system object. */
|
||
|
/* */
|
||
|
/* <Input> */
|
||
|
/* system :: A handle to a given `system object'. */
|
||
|
/* */
|
||
|
/* <Return> */
|
||
|
/* FreeType error code. 0 means success. */
|
||
|
/* */
|
||
|
EXPORT_FUNC
|
||
|
FT_Error FT_Done_System( FT_System system )
|
||
|
{
|
||
|
/* finalize synchronization (nothing) */
|
||
|
|
||
|
/* finalize i/o management (nothing) */
|
||
|
|
||
|
/* finalize memory management */
|
||
|
|
||
|
#ifdef FT_CONFIG_OPTION_DEBUG_MEMORY
|
||
|
DM_Done_Mem();
|
||
|
#endif
|
||
|
|
||
|
free( system );
|
||
|
|
||
|
return FT_Err_Ok;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* END */
|