diff --git a/src/base/ftstream.c b/src/base/ftstream.c index 0a40fb3b8..90cabe431 100644 --- a/src/base/ftstream.c +++ b/src/base/ftstream.c @@ -429,3 +429,149 @@ return 0; } + BASE_FUNC + FT_Error FT_Read_Fields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ) + { + FT_Error error; + FT_Bool frame_accessed = 0; + + if (!fields || !stream) + return FT_Err_Invalid_Argument; + + error = FT_Err_Ok; + do + { + FT_ULong value; + FT_Int sign_shift; + FT_Byte* p; + + switch (fields->value) + { + case ft_frame_start: /* access a new frame */ + { + error = FT_Access_Frame( stream, fields->offset ); + if (error) goto Exit; + + frame_accessed = 1; + fields++; + continue; /* loop ! */ + } + + case ft_frame_byte: + case ft_frame_schar: /* read a single byte */ + { + value = GET_Byte(); + sign_shift = 24; + break; + } + + case ft_frame_short_be: + case ft_frame_ushort_be: /* read a 2-byte big-endian short */ + { + value = GET_UShort(); + sign_shift = 16; + break; + } + + case ft_frame_short_le: + case ft_frame_ushort_le: /* read a 2-byte little-endian short */ + { + char* p; + value = 0; + p = stream->cursor; + if (p+1 < stream->limit) + { + value = (FT_UShort)p[0] | ((FT_UShort)p[1] << 8); + stream->cursor += 2; + } + sign_shift = 16; + break; + } + + case ft_frame_long_be: + case ft_frame_ulong_be: /* read a 4-byte big-endian long */ + { + value = GET_ULong(); + sign_shift = 0; + break; + } + + case ft_frame_long_le: + case ft_frame_ulong_le: /* read a 4-byte little-endian long */ + { + char* p; + value = 0; + p = stream->cursor; + if (p+3 < stream->limit) + { + value = (FT_ULong)p[0] | + ((FT_ULong)p[1] << 8) | + ((FT_ULong)p[2] << 16) | + ((FT_ULong)p[3] << 24); + stream->cursor += 4; + } + sign_shift = 0; + break; + } + + case ft_frame_off3_be: + case ft_frame_uoff3_be: /* read a 3-byte big-endian long */ + { + value = GET_UOffset(); + sign_shift = 8; + break; + } + + case ft_frame_off3_le: + case ft_frame_uoff3_le: /* read a 3-byte little-endian long */ + { + char* p; + value = 0; + p = stream->cursor; + if (p+3 < stream->limit) + { + value = (FT_ULong)p[0] | + ((FT_ULong)p[1] << 8) | + ((FT_ULong)p[2] << 16) | + ((FT_ULong)p[3] << 24); + stream->cursor += 4; + } + sign_shift = 8; + break; + } + + default: + /* otherwise, exit the loop */ + goto Exit; + } + + /* now, compute the signed value is necessary */ + if (fields->value & FT_FRAME_OP_SIGNED) + value = (FT_ULong)((FT_Long)(value << sign_shift) >> sign_shift); + + /* finally, store the value in the object */ + + p = (FT_Byte*)structure + fields->offset; + switch (fields->size) + { + case 1: *(FT_Byte*)p = (FT_Byte) value; break; + case 2: *(FT_UShort*)p = (FT_UShort)value; break; + case 4: *(FT_ULong*)p = (FT_ULong) value; break; + default: ; /* ignore !! */ + } + + /* go to next field */ + fields++; + } + while (1); + + Exit: + /* close the frame if it was opened by this read */ + if (frame_accessed) + FT_Forget_Frame(stream); + + return error; + } + diff --git a/src/base/ftstream.h b/src/base/ftstream.h index 944795c75..58cafaa9a 100644 --- a/src/base/ftstream.h +++ b/src/base/ftstream.h @@ -3,6 +3,77 @@ #include +/* format of an 8-bit frame_op value = [ xxxxx | e | s ] */ +/* where s is set to 1 when the value is signed.. */ +/* where e is set to 1 when the value is little-endian */ +/* xxxxx is a command */ + +#define FT_FRAME_OP_SHIFT 2 +#define FT_FRAME_OP_SIGNED 1 +#define FT_FRAME_OP_LITTLE 2 +#define FT_FRAME_OP_COMMAND(x) (x >> FT_FRAME_OP_SHIFT) + +#define FT_MAKE_FRAME_OP( command, little, sign ) \ + ((command << FT_FRAME_OP_SHIFT) | (little << 1) | sign) + +#define FT_FRAME_OP_END 0 +#define FT_FRAME_OP_START 1 /* start a new frame */ +#define FT_FRAME_OP_BYTE 2 /* read 1-byte value */ +#define FT_FRAME_OP_SHORT 3 /* read 2-byte value */ +#define FT_FRAME_OP_LONG 4 /* read 4-byte value */ +#define FT_FRAME_OP_OFF3 5 /* read 3-byte value */ + +typedef enum FT_Frame_Op_ +{ + ft_frame_end = 0, + ft_frame_start = FT_MAKE_FRAME_OP( FT_FRAME_OP_START, 0, 0 ), + + ft_frame_byte = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 0 ), + ft_frame_schar = FT_MAKE_FRAME_OP( FT_FRAME_OP_BYTE, 0, 1 ), + + ft_frame_ushort_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 0 ), + ft_frame_short_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 0, 1 ), + ft_frame_ushort_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 0 ), + ft_frame_short_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_SHORT, 1, 1 ), + + ft_frame_ulong_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 0 ), + ft_frame_ulong_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 0, 1 ), + ft_frame_long_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 0 ), + ft_frame_long_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_LONG, 1, 1 ), + + ft_frame_uoff3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 0 ), + ft_frame_uoff3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 0, 1 ), + ft_frame_off3_be = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 0 ), + ft_frame_off3_le = FT_MAKE_FRAME_OP( FT_FRAME_OP_OFF3, 1, 1 ), + +} FT_Frame_Op; + + +typedef struct FT_Frame_Field_ +{ + FT_Frame_Op value; + char size; + FT_UShort offset; + +} FT_Frame_Field; + +/* make-up a FT_Frame_Field out of a structure type and a field name */ +#define FT_FIELD_REF(s,f) (((s*)0)->f) + +#define FT_FRAME_FIELD( frame_op, struct_type, field ) \ + { \ + frame_op, \ + sizeof(FT_FIELD_REF(struct_type,field)), \ + (FT_UShort)(char*)&FT_FIELD_REF(struct_type,field) } + +#define FT_MAKE_EMPTY_FIELD( frame_op ) { frame_op, 0, 0 } + +#define FT_FRAME_LONG(s,f) FT_FRAME_FIELD( ft_frame_long_be, s, f ) +#define FT_FRAME_ULONG(s,f) FT_FRAME_FIELD( ft_frame_ulong_be, s, f ) +#define FT_FRAME_SHORT(s,f) FT_FRAME_FIELD( ft_frame_short_be, s, f ) +#define FT_FRAME_USHORT(s,f) FT_FRAME_FIELD( ft_frame_ushort_be, s, f ) +#define FT_FRAME_BYTE(s,f) FT_FRAME_FIELD( ft_frame_byte, s, f ) +#define FT_FRAME_CHAR(s,f) FT_FRAME_FIELD( ft_frame_schar, s, f ) /*************************************************************************/ /* */ @@ -134,6 +205,11 @@ FT_Long FT_Read_Long( FT_Stream stream, FT_Error* error ); + BASE_DEF + FT_Error FT_Read_Fields( FT_Stream stream, + const FT_Frame_Field* fields, + void* structure ); + #define USE_Stream( resource, stream ) \ FT_SET_ERROR( FT_Open_Stream( resource, stream ) ) @@ -173,6 +249,7 @@ (FT_Char*)buffer, \ count ) ) - +#define READ_Fields( fields, object ) \ + ((error = FT_Read_Fields( stream, fields, object )) != FT_Err_Ok) #endif /* FTIO_H */