IntroductionThis document explains the concept of I/O frames as used in the FreeType 2 source code. It also enumerates the various functions and macros that can be used to read them. It is targeted to FreeType hackers, or more simply to developers who would like a better understanding of the library's source code. I. What frames areSimply speaking, a frame is an array of bytes in a font file that is "preloaded" into memory in order to be rapidly parsed. Frames are useful to ensure that every "load" is checked against end-of-file overruns, and provides nice functions to extract data in a variety of distinct formats. But an example is certainly more meaningful than anything else. The following code error = read_short( stream, &str.value1 ); if ( error ) goto ... error = read_ulong( stream, &str.value2 ); if ( error ) goto ... error = read_ulong( stream, &str.value3 ); if ( error ) goto ... can easily be replaced with error = FT_Access_Frame( stream, 2 + 4 + 4 ); if ( error ) goto ... str.value1 = FT_Get_Short( stream ); str.value2 = FT_Get_ULong( stream ); str.value3 = FT_Get_ULong( stream ); FT_Forget_Frame( stream ); Here, the call to FT_Access_Frame() will
Each FT_Get_Short() or FT_Get_ULong() call will read a big-endian integer from the stream (2 bytes for FT_Get_Short(), 4 bytes for FT_Get_ULong) and advance the frame cursor accordingly. FT_Forget_Frame() "releases" the frame from memory. There are several advantages to using frames:
II. Accessing and reading a frame with macrosBy convention in the FreeType source code, macros are able to use two implicit variables named error and stream. This is useful because these two variables are extremely often used in the library, and doing this only reduces our typing requirements and make the source code much clearer. Note that error must be a local variable of type FT_Error, while stream must be a local variable or argument of type FT_Stream. The macro used to access a frame is ACCESS_Frame(_size_), it will translate to ( error = FT_Access_Frame( stream, _size_ ) ) != FT_Err_Ok Similarly, the macro FORGET_Frame() translates to FT_Forget_Frame( stream ) Extracting integers can be performed with the GET_xxx() macros, like
(Note that an Offset is an integer stored with 3 bytes on the file.) All this means that the following code error = FT_Access_Frame( stream, 2 + 4 + 4 ); if ( error ) goto ... str.value1 = FT_Get_Short( stream ); str.value2 = FT_Get_ULong( stream ); str.value3 = FT_Get_ULong( stream ); FT_Forget_Frame( stream ); can be simplified with macros: if ( ACCESS_Frame( 2 +4 + 4 ) ) goto ... str.value1 = GET_Short(); str.value2 = GET_ULong(); str.value3 = GET_ULong(); FORGET_Frame(); Which is clearer. Notice that error and stream must be defined locally though for this code to work! III. AlternativesIt is sometimes useful to read small integers from a font file without using a frame. Some functions have been introduced in FreeType 2 to do just that, and they are of the form FT_Read_xxxx. For example, FT_Read_Short(stream, &error) reads and returns a 2-byte big-endian integer from a stream, and places an error code in the error variable. Thus, reading a single big-endian integer is shorter than using a frame for it. Note that there are also macros READ_xxx() which translate to FT_Read_xxx( stream, &error ), error != FT_Err_Ok and can be used as in if ( READ_UShort( variable1 ) || READ_ULong ( variable2 ) ) goto Fail; if error and stream are already defined locally. |