Commit 818336fdf4929d2ec9b376532fcdcb54b2c8641d

David Turner 2000-02-13T13:36:53

Added the function FT_Read_Fields, it acts as a finite-state automata to load large TrueType tables in object structures. This is experimental, don't mess too much with it, thanks :-)

diff --git a/src/base/ftstream.c b/src/base/ftstream.c
index 0a40fb3..90cabe4 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 944795c..58cafaa 100644
--- a/src/base/ftstream.h
+++ b/src/base/ftstream.h
@@ -3,6 +3,77 @@
 
 #include <ftobjs.h>
 
+/* 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 */