📄 ttfile.c
字号:
/******************************************************************* * * ttfile.c (extended version) 2.1 * * File I/O Component (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. * * NOTES: * * This implementation relies on the ANSI libc. You may wish to * modify it to get rid of 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 2.0 and 2.1 : * * - it is now possible to close a stream's file handle explicitely * through the new API "TT_Flush_Stream". This will simply close * a stream's file handle (useful to save system resources when * dealing with lots of opened fonts). Of course, the function * "TT_Use_Stream" will automatically re-open a stream's handle if * necessary. * * - added "TT_Stream_Size" to replace "TT_File_Size" which wasn't * used anyway. This one returns the size of any stream, even * flushed one (when the previous TT_File_Size could only return * the size of the current working stream). This is used by the * new "Load_TrueType_Any" function in the tables loader. * ******************************************************************/#include "ttconfig.h"#include <stdio.h>#include <string.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "freetype.h"#include "tttypes.h"#include "ttdebug.h"#include "ttengine.h"#include "ttmutex.h"#include "ttmemory.h"#include "ttfile.h" /* our prototypes *//* required by the tracing mode */#undef TT_COMPONENT#define TT_COMPONENT trace_file/* For now, we don't define additional error messages in the core library *//* to report open-on demand errors. Define these error as standard ones */#define TT_Err_Could_Not_ReOpen_File TT_Err_Could_Not_Open_File#define TT_Err_Could_Not_ReSeek_File TT_Err_Could_Not_Open_File /* This definition is mandatory for each file component! */ EXPORT_FUNC const TFileFrame TT_Null_FileFrame = { NULL, 0, 0 };/* It has proven useful to do some bounds checks during development phase. *//* They should probably be undefined for speed reasons in a later release. */#if DEBUG_FILE#define CHECK_FRAME( frame, n ) \ do { \ if ( frame.cursor + n > frame.address + frame.size ) \ Panic( "Frame boundary error!\n" ); \ } while ( 0 )#else#define CHECK_FRAME( frame, n ) /* nothing */#endif /* Because a stream can be flushed, i.e. its file handle can be */ /* closed to save system resources, we must keep the stream's file */ /* pathname to be able to re-open it on demand when it is flushed */ struct TStream_Rec_; typedef struct TStream_Rec_ TStream_Rec; typedef TStream_Rec* PStream_Rec; struct TStream_Rec_ { Bool opened; /* is the stream handle opened ? */ TT_Text* name; /* the file's pathname */ Long position; /* current position within the file */ FILE* file; /* file handle */ Long base; /* stream base in file */ Long size; /* stream size in file */ }; /* We support embedded TrueType files by allowing them to be */ /* inside any file, at any location, hence the 'base' argument. */ /* Note however that the current implementation does not allow you */ /* to specify a 'base' index when opening a file. */ /* (will come later) */ /* I still don't know if this will turn out useful ?? - DavidT */#define STREAM2REC( x ) ( (TStream_Rec*)HANDLE_Val( x ) ) static TT_Error Stream_Activate ( PStream_Rec stream ); static TT_Error Stream_Deactivate( PStream_Rec stream );#ifndef TT_CONFIG_OPTION_THREAD_SAFE /*******************************************************************/ /*******************************************************************/ /*******************************************************************/ /**** ****/ /**** N O N R E E N T R A N T I M P L E M E N T A T I O N ****/ /**** ****/ /*******************************************************************/ /*******************************************************************/ /*******************************************************************/ /* in non-rentrant builds, we allocate a single block where we'll */ /* place all the frames smaller than FRAME_CACHE_SIZE, rather than */ /* allocating a new block on each access. Bigger frames will be */ /* malloced normally in the heap. */ /* */ /* See TT_Access_Frame() and TT_Forget_Frame() for details. */#define FRAME_CACHE_SIZE 2048 /* 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_ { TMutex lock; /* used by the thread-safe build only */ Byte* frame_cache; /* frame cache */ PStream_Rec stream; /* current stream */ TFileFrame frame; /* current frame */ }; typedef struct TFile_Component_ TFile_Component; static TFile_Component files;#define CUR_Stream files.stream#define CUR_Frame files.frame#define STREAM_VARS /* void */#define STREAM_VAR /* void *//* 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 : Initializes the File component. * ******************************************************************/ LOCAL_FUNC TT_Error TTFile_Init( PEngine_Instance engine ) { TT_Error error; MUTEX_Create( files.lock ); files.stream = NULL; ZERO_Frame( files.frame ); if ( ALLOC( files.frame_cache, FRAME_CACHE_SIZE ) ) return error; return TT_Err_Ok; }/******************************************************************* * * Function : TTFile_Done * * Description : Finalizes the File component. * ******************************************************************/ LOCAL_FUNC TT_Error TTFile_Done( PEngine_Instance engine ) { FREE( files.frame_cache ); MUTEX_Destroy( files.lock ); return TT_Err_Ok; }/******************************************************************* * * Function : TT_Use_Stream * * Description : Copies or duplicates a given stream. * * Input : org_stream original stream * stream target stream (copy or duplicate) * * Output : Error code. * ******************************************************************/ EXPORT_FUNC TT_Error TT_Use_Stream( TT_Stream org_stream, TT_Stream* stream ) { MUTEX_Lock( files.lock ); /* lock file mutex */ *stream = org_stream; /* copy the stream */ files.stream = STREAM2REC(org_stream); /* set current stream */ Stream_Activate( files.stream ); return TT_Err_Ok; }/******************************************************************* * * Function : TT_Done_Stream * * Description : Releases a given stream. * * Input : stream target stream * * Output : Error code. * ******************************************************************/ EXPORT_FUNC TT_Error TT_Done_Stream( TT_Stream* stream ) { HANDLE_Set( *stream, NULL ); MUTEX_Release( files.lock ); return TT_Err_Ok; }/******************************************************************* * * 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 `size' is * too big in both cases). * ******************************************************************/ EXPORT_FUNC TT_Error TT_Access_Frame( STREAM_ARGS FRAME_ARGS Long size ) { TT_Error error; if ( CUR_Frame.address != NULL ) return TT_Err_Nested_Frame_Access; if ( size <= FRAME_CACHE_SIZE ) { /* use the cache */ CUR_Frame.address = files.frame_cache; CUR_Frame.size = FRAME_CACHE_SIZE; } else { if ( ALLOC( CUR_Frame.address, size ) ) return error; CUR_Frame.size = size; } error = TT_Read_File( STREAM_VARS (void*)CUR_Frame.address, size ); if (error) { if ( size > FRAME_CACHE_SIZE ) FREE( CUR_Frame.address ); CUR_Frame.address = NULL; CUR_Frame.size = 0; } CUR_Frame.cursor = CUR_Frame.address; return error; }/******************************************************************* * * Function : TT_Check_And_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 truncates `size' 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 `size' 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. * ******************************************************************/ EXPORT_FUNC TT_Error TT_Check_And_Access_Frame( STREAM_ARGS FRAME_ARGS Long size ) { TT_Error error; Long readBytes, requested; if ( CUR_Frame.address != NULL ) return TT_Err_Nested_Frame_Access; if ( size <= FRAME_CACHE_SIZE ) { /* use the cache */ CUR_Frame.address = files.frame_cache; CUR_Frame.size = FRAME_CACHE_SIZE; } else { if ( ALLOC( CUR_Frame.address, size ) ) return error; CUR_Frame.size = size; } requested = size; readBytes = CUR_Stream->size - TT_File_Pos( STREAM_VAR ); if ( size > readBytes ) size = readBytes; error = TT_Read_File( STREAM_VARS (void*)CUR_Frame.address, size ); if (error) { if ( requested > FRAME_CACHE_SIZE ) FREE( CUR_Frame.address ); CUR_Frame.address = NULL; CUR_Frame.size = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -