shithub: freetype+ttf2subf

Download patch

ref: 617a2e1c3c8176e8ae31313a784829f278b1766e
parent: 53b3fa1da5e3397388f3483ccc95910eca4a419d
author: David Turner <[email protected]>
date: Wed Feb 27 16:25:47 EST 2002

adding several experimental sources:

  - OpenType Layout validation and parsing (common tables)
  - Type 1 charmap processing

git/fs: mount .git/fs: mount/attach disallowed
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -75,6 +75,159 @@
 
 
   /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                    V A L I D A T I O N                          ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+ /* handle to a validation object */
+  typedef struct FT_ValidatorRec_*   FT_Validator;
+
+ /**************************************************************************
+  *
+  *  there are three distinct validation levels defined here:
+  *
+  *  FT_VALIDATE_DEFAULT ::
+  *    a table that passes this validation level can be used reliably by
+  *    FreeType. It generally means that all offsets have been checked to
+  *    prevent out-of-bound reads, array counts are correct, etc..
+  *
+  *
+  *  FT_VALIDATE_TIGHT ::
+  *    a table that passes this validation level can be used reliably and
+  *    doesn't contain invalid data. For example, a charmap table that
+  *    returns invalid glyph indices will not pass, even though it can 
+  *    be used with FreeType in default mode (the library will simply
+  *    return an error later when trying to load the glyph)
+  *
+  *    it also check that fields that must be a multiple of 2, 4 or 8 don't
+  *    have incorrect values, etc..
+  *
+  *
+  *  FT_VALIDATE_PARANOID ::
+  *    only for font facists. Checks that a table follows the specification
+  *    100%. Very few fonts will be able to pass this level anyway but it
+  *    can be useful for certain tools like font editors/converters..
+  */
+  typedef enum FT_ValidationLevel_
+  {
+    FT_VALIDATE_DEFAULT = 0,
+    FT_VALIDATE_TIGHT,
+    FT_VALIDATE_PARANOID
+  
+  } FT_ValidationLevel;
+
+
+ /* validator structure */
+  typedef struct FT_ValidatorRec_
+  {
+    FT_Byte*            base;   /* address of table in memory           */
+    FT_Byte*            limit;  /* 'base' + sizeof(table) in memory     */
+    FT_ValidationLevel  level;  /* validation level                     */
+    FT_Error            error;  /* error returned. 0 means success      */
+    
+    jmp_buf             jump_buffer;  /* used for exception handling */
+    
+  } FT_ValidatorRec;
+
+
+ /* sets the error field in a validator, then calls 'longjmp' to return */
+ /* to high-level caller. Using 'setjmp/longjmp' avoids many stupid     */
+ /* error checks within the validation routines..                       */
+ /*                                                                     */
+  FT_BASE( void )
+  ft_validate_error( FT_Valid  valid,
+                     FT_Error  error );
+
+ /* calls ft_validate_error. Assumes that the 'valid' local variable holds */
+ /* a pointer to the current validator object..                            */
+ /*                                                                        */
+#define  FT_INVALID(_error)   ft_validate_error( valid, _error )
+
+ /* called when a broken table is detected */
+#define  FT_INVALID_TOO_SHORT   FT_INVALID( FT_Err_Invalid_Format )
+
+ /* called when an invalid offset is detected */
+#define  FT_INVALID_OFFSET      FT_INVALID( FT_Err_Invalid_Offset )
+
+ /* called when an invalid format/value is detected */
+#define  FT_INVALID_FORMAT      FT_INVALID( FT_Err_Invalid_Format )
+
+ /* called when an invalid glyph index is detected */
+#define  FT_INVALID_GLYPH_ID    FT_INVALID( FT_Err_Invalid_Glyph_Id )
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /****                       C H A R M A P S                           ****/
+  /****                                                                 ****/
+  /****                                                                 ****/
+  /*************************************************************************/
+  /*************************************************************************/
+  /*************************************************************************/
+
+ /* handle to internal charmap object */
+  typedef struct FT_CMapRec_*              FT_CMap;
+  
+ /* handle to charmap class structure */
+  typedef const struct FT_CMap_ClassRec_*   FT_CMap_Class;
+
+ /* internal charmap object structure */
+  typedef struct FT_CMapRec_
+  {
+    FT_CharMapRec  charmap;
+    FT_CMap_Class  clazz;
+    FT_Pointer     data;
+    
+  } FT_CMapRec;
+
+ /* typecase any pointer to a charmap handle */
+#define  FT_CMAP(x)               ((FT_CMap)(x))
+
+ /* obvious macros */
+#define  FT_CMAP_PLATFORM_ID(x)   FT_CMAP(x)->charmap.platform_id
+#define  FT_CMAP_ENCODING_ID(x)   FT_CMAP(x)->charmap.encoding_id
+#define  FT_CMAP_ENCODING(x)      FT_CMAP(x)->charmap.encoding
+#define  FT_CMAP_FACE(x)          FT_CMAP(x)->charmap.face
+
+
+ /* class method definitions */
+  typedef FT_Error  (*FT_CMap_InitFunc)( FT_CMap     cmap,
+                                         FT_Pointer  data );
+
+  typedef void      (*FT_CMap_DoneFunc)( FT_CMap     cmap );
+
+  typedef FT_Error  (*FT_CMap_ValidateFunc)( FT_Pointer    cmap_data,
+                                             FT_Validator  valid );
+
+  typedef FT_UInt   (*FT_CMap_CharIndexFunc)( FT_Pointer   cmap_data,
+                                              FT_ULong     char_code );
+
+  typedef FT_UInt   (*FT_CMap_CharNextFunc)( FT_Pointer  cmap_data,
+                                             FT_ULong   *achar_code );
+
+  typedef struct FT_CMap_ClassRec_
+  {
+    FT_UInt                size;
+    FT_CMap_InitFunc       init;
+    FT_CMap_DoneFunc       done;
+    FT_CMap_ValidateFunc   validate;
+    FT_CMap_CharIndexFunc  char_index;
+    FT_CMap_CharNextFunc   char_next;
+  
+  } FT_CMap_ClassRec;
+
+
+  /*************************************************************************/
   /*                                                                       */
   /* <Struct>                                                              */
   /*    FT_Face_InternalRec                                                */
@@ -329,109 +482,6 @@
   FT_BASE( void )
   FT_Done_GlyphSlot( FT_GlyphSlot  slot );
 
-
-#if 0
-
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-  /****                                                                 ****/
-  /****                                                                 ****/
-  /****                   G L Y P H   L O A D E R                       ****/
-  /****                                                                 ****/
-  /****                                                                 ****/
-  /*************************************************************************/
-  /*************************************************************************/
-  /*************************************************************************/
-
-
-#define FT_SUBGLYPH_FLAG_ARGS_ARE_WORDS          1
-#define FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES      2
-#define FT_SUBGLYPH_FLAG_ROUND_XY_TO_GRID        4
-#define FT_SUBGLYPH_FLAG_SCALE                   8
-#define FT_SUBGLYPH_FLAG_XY_SCALE             0x40
-#define FT_SUBGLYPH_FLAG_2X2                  0x80
-#define FT_SUBGLYPH_FLAG_USE_MY_METRICS      0x200
-
-
-  enum
-  {
-    FT_GLYPH_OWN_BITMAP = 1
-  };
-
-
-  struct  FT_SubGlyph_
-  {
-    FT_Int     index;
-    FT_UShort  flags;
-    FT_Int     arg1;
-    FT_Int     arg2;
-    FT_Matrix  transform;
-  };
-
-
-  typedef struct  FT_GlyphLoad_
-  {
-    FT_Outline    outline;       /* outline             */
-    FT_UInt       num_subglyphs; /* number of subglyphs */
-    FT_SubGlyph*  subglyphs;     /* subglyphs           */
-    FT_Vector*    extra_points;  /* extra points table  */
-
-  } FT_GlyphLoad;
-
-
-  struct  FT_GlyphLoader_
-  {
-    FT_Memory     memory;
-    FT_UInt       max_points;
-    FT_UInt       max_contours;
-    FT_UInt       max_subglyphs;
-    FT_Bool       use_extra;
-
-    FT_GlyphLoad  base;
-    FT_GlyphLoad  current;
-
-    void*         other;            /* for possible future extension? */
-
-  };
-
-
-  FT_BASE( FT_Error )
-  FT_GlyphLoader_New( FT_Memory         memory,
-                      FT_GlyphLoader*  *aloader );
-
-  FT_BASE( FT_Error )
-  FT_GlyphLoader_Create_Extra( FT_GlyphLoader*  loader );
-
-  FT_BASE( void )
-  FT_GlyphLoader_Done( FT_GlyphLoader*  loader );
-
-  FT_BASE( void )
-  FT_GlyphLoader_Reset( FT_GlyphLoader*  loader );
-
-  FT_BASE( void )
-  FT_GlyphLoader_Rewind( FT_GlyphLoader*  loader );
-
-  FT_BASE( FT_Error )
-  FT_GlyphLoader_Check_Points( FT_GlyphLoader*  loader,
-                               FT_UInt          n_points,
-                               FT_UInt          n_contours );
-
-  FT_BASE( FT_Error )
-  FT_GlyphLoader_Check_Subglyphs( FT_GlyphLoader*  loader,
-                                  FT_UInt          n_subs );
-
-  FT_BASE( void )
-  FT_GlyphLoader_Prepare( FT_GlyphLoader*  loader );
-
-  FT_BASE( void )
-  FT_GlyphLoader_Add( FT_GlyphLoader*  loader );
-
-  FT_BASE( FT_Error )
-  FT_GlyphLoader_Copy_Points( FT_GlyphLoader*  target,
-                              FT_GlyphLoader*  source );
-
-#endif
 
   /*************************************************************************/
   /*************************************************************************/
--- /dev/null
+++ b/src/otlayout/otlcommn.c
@@ -1,0 +1,820 @@
+#include "otlayout.h"
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                       COVERAGE TABLE                          *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_coverage_validate( OTL_Bytes      table,
+                         OTL_Validator  valid )
+  {
+    OTL_Bytes  p;
+    OTL_UInt   format;
+
+    if ( table + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    format = OTL_NEXT_UShort(p);
+    switch (format)
+    {
+      case 1:
+        {
+          OTL_UInt  count = OTL_NEXT_UShort(p);
+
+          if ( p + count*2 >= valid->limit )
+            OTL_INVALID_TOO_SHORT;
+
+          /* XXX: check glyph indices */
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  n, num_ranges = OTL_NEXT_UShort(p);
+          OTL_UInt  start, end, start_cover, total = 0, last = 0;
+
+          if ( p + num_ranges*6 >= valid->limit )
+            OTL_INVALID_TOO_SHORT;
+
+          for ( n = 0; n < num_ranges; n++ )
+          {
+            start       = OTL_NEXT_UShort(p);
+            end         = OTL_NEXT_UShort(p);
+            start_cover = OTL_NEXT_UShort(p);
+
+            if ( start > end || start_cover != total )
+              OTL_INVALID_DATA;
+
+            if ( n > 0 && start <= last )
+              OTL_INVALID_DATA;
+
+            total += (end - start + 1);
+            last   = end;
+          }
+        }
+        break;
+
+      default:
+        OTL_INVALID_FORMAT;
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_coverage_get_count( OTL_Bytes   table )
+  {
+    OTL_Bytes  p      = table;
+    OTL_UInt   format = OTL_NEXT_UShort(p);
+    OTL_UInt   count  = OTL_NEXT_UShort(p);
+    OTL_UInt   result = 0;
+
+    switch ( format )
+    {
+      case 1:
+        return count;
+
+      case 2:
+        {
+          OTL_UInt  start, end;
+
+          for ( ; count > 0; count-- )
+          {
+            start = OTL_NEXT_UShort(p);
+            end   = OTL_NEXT_UShort(p);
+            p    += 2;  /* skip start_index */
+
+            result += ( end - start + 1 );
+          }
+        }
+        break;
+
+      default:
+        ;
+    }
+
+    return  result;
+  }
+
+
+  OTL_LOCALDEF( OTL_Int )
+  otl_coverage_get_index( OTL_Bytes   table,
+                          OTL_UInt    glyph_index )
+  {
+    OTL_Bytes  p      = table;
+    OTL_UInt   format = OTL_NEXT_UShort(p);
+    OTL_UInt   count  = OTL_NEXT_UShort(p);
+
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt   min = 0, max = count, mid, gindex;
+
+          table += 4;
+          while ( min < max )
+          {
+            mid    = ( min + max ) >> 1;
+            p      = table + 2*mid;
+            gindex = OTL_PEEK_UShort(p);
+
+            if ( glyph_index == gindex )
+              return (OTL_Int)mid;
+
+            if ( glyph_index < gindex )
+              max = mid;
+            else
+              min = mid + 1;
+          }
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt   min = 0, max = count, mid;
+          OTL_UInt   start, end, delta, start_cover;
+
+          table += 4;
+          while ( min < max )
+          {
+            mid    = ( min + max ) >> 1;
+            p      = table + 6*mid;
+            start  = OTL_NEXT_UShort(p);
+            end    = OTL_NEXT_UShort(p);
+
+            if ( glyph_index < start )
+              max = mid;
+            else if ( glyph_index > end )
+              min = mid + 1;
+            else
+              return (OTL_Int)( glyph_index + OTL_NEXT_UShort(p) - start );
+          }
+        }
+        break;
+
+      default:
+        ;
+    }
+    return  -1;
+  }
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                  CLASS DEFINITION TABLE                       *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_class_definition_validate( OTL_Bytes      table,
+                                 OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   format;
+
+    if ( p + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    format = OTL_NEXT_UShort(p);
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  count, start = OTL_NEXT_UShort(p);
+
+          if ( p + 2 > valid->limit )
+            OTL_INVALID_TOO_SHORT;
+
+          count = OTL_NEXT_UShort(p);
+
+          if ( p + count*2 > valid->limit )
+            OTL_INVALID_TOO_SHORT;
+
+          /* XXX: check glyph indices */
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  n, num_ranges = OTL_NEXT_UShort(p);
+          OTL_UInt  start, end, value, last = 0;
+
+          if ( p + num_ranges*6 > valid->limit )
+            OTL_INVALID_TOO_SHORT;
+
+          for ( n = 0; n < num_ranges; n++ )
+          {
+            start = OTL_NEXT_UShort(p);
+            end   = OTL_NEXT_UShort(p);
+            value = OTL_NEXT_UShort(p);  /* ignored */
+
+            if ( start > end || ( n > 0 && start <= last ) )
+              OTL_INVALID_DATA;
+
+            last = end;
+          }
+        }
+        break;
+
+      default:
+        OTL_INVALID_FORMAT;
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_class_definition_get_value( OTL_Bytes  table,
+                                  OTL_UInt   glyph_index )
+  {
+    OTL_Bytes  p      = table;
+    OTL_UInt   format = OTL_NEXT_UShort(p);
+
+    switch ( format )
+    {
+      case 1:
+        {
+          OTL_UInt  start = OTL_NEXT_UShort(p);
+          OTL_UInt  count = OTL_NEXT_UShort(p);
+          OTL_UInt  index = (OTL_UInt)( glyph_index - start );
+
+          if ( index < count )
+          {
+            p += 2*index;
+            return OTL_PEEK_UShort(p);
+          }
+        }
+        break;
+
+      case 2:
+        {
+          OTL_UInt  count = OTL_NEXT_UShort(p);
+          OTL_UInt  min = 0, max = count, mid, gindex;
+
+          table += 4;
+          while ( min < max )
+          {
+            mid   = ( min + max ) >> 1;
+            p     = table + 6*mid;
+            start = OTL_NEXT_UShort(p);
+            end   = OTL_NEXT_UShort(p);
+
+            if ( glyph_index < start )
+              max = mid;
+            else if ( glyph_index > end )
+              min = mid+1;
+            else
+              return OTL_PEEK_UShort(p);
+          }
+        }
+        break;
+
+      default:
+        ;
+    }
+    return 0;
+  }
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                      DEVICE TABLE                             *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_device_table_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   start, end, count, format, count;
+
+    if ( p + 8 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    start  = OTL_NEXT_UShort(p);
+    end    = OTL_NEXT_UShort(p);
+    format = OTL_NEXT_UShort(p);
+
+    if ( format < 1 || format > 3 || end < start )
+      OTL_INVALID_DATA;
+
+    count    = (OTL_UInt)( end - start + 1 );
+
+    if ( p + ((1 << format)*count)/8> valid->limit )
+      OTL_INVALID_TOO_SHORT;
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_start( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+
+    return OTL_PEEK_UShort(p);
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_end( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table + 2;
+
+    return OTL_PEEK_UShort(p);
+  }
+
+
+  OTL_LOCALDEF( OTL_Int )
+  otl_device_table_get_delta( OTL_Bytes   table,
+                              OTL_UInt    size )
+  {
+    OTL_Bytes   p = table;
+    OTL_Int     result = 0;
+    OTL_UInt    start, end, format, index, value;
+
+    start  = OTL_NEXT_UShort(p);
+    end    = OTL_NEXT_UShort(p);
+    format = OTL_NEXT_UShort(p);
+
+    if ( size >= start && size <= end )
+    {
+      /* we could do that with clever bit operations, but a switch is simply */
+      /* much simpler to understand and maintain !!                          */
+      /*                                                                     */
+      switch ( format )
+      {
+        case 1:
+          {
+            index   = (OTL_UInt)(( size - start )*2);
+            p      += (index/16);
+            value   = OTL_PEEK_UShort(p);
+            shift   = index & 15;
+            result  = (OTL_Short)(value << shift) >> (14-shift);
+          }
+          break;
+
+        case 2:
+          {
+            index   = (OTL_UInt)(( size - start )*4);
+            p      += (index/16);
+            value   = OTL_PEEK_UShort(p);
+            shift   = index & 15;
+            result  = (OTL_Short)(value << shift) >> (12-shift);
+          }
+          break;
+
+        case 3:
+          {
+            index   = (OTL_UInt)(( size - start )*8);
+            p      += (index/16);
+            value   = OTL_PEEK_UShort(p);
+            shift   = index & 15;
+            result  = (OTL_Short)(value << shift) >> (8-shift);
+          }
+          break;
+
+        default:
+          ;
+      }
+    }
+    return  result;
+  }
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                      LOOKUP LISTS                             *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_lookup_validate( OTL_Bytes      table,
+                       OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   num_tables;
+
+    if ( table + 6 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    p += 4;
+    num_tables = OTL_NEXT_UShort(p);
+
+    if ( p + num_tables*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_tables > 0; num_tables-- )
+    {
+      offset = OTL_NEXT_UShort(p);
+
+      if ( table + offset >= valid->limit )
+        OTL_INVALID_OFFSET;
+    }
+
+    /* XXX: check sub-tables ?? */
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table + 4;
+
+    return  OTL_PEEK_UShort(p);
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_get_table( OTL_Bytes  table,
+                        OTL_UInt   index )
+  {
+    OTL_Bytes  p, result = NULL;
+    OTL_UInt   count;
+
+    p     = table + 4;
+    count = OTL_NEXT_UShort(p);
+    if ( index < count )
+    {
+      p     += index*2;
+      result = table + OTL_PEEK_UShort(p);
+    }
+    return  result;
+  }
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                      LOOKUP LISTS                             *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_lookup_list_validate( OTL_Bytes      table,
+                            OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table, q;
+    OTL_UInt   num_lookups, offset;
+
+    if ( p + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    num_lookups = OTL_NEXT_UShort(p);
+
+    if ( p + num_lookups*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_lookups > 0; num_lookups-- )
+    {
+
+      offset = OTL_NEXT_UShort(p);
+
+      otl_lookup_validate( table + offset, valid );
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_list_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+
+    return OTL_PEEK_UShort(p);
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_lookup( OTL_Bytes  table,
+                              OTL_UInt   index )
+  {
+    OTL_Bytes  p, result = 0;
+    OTL_UInt   count;
+
+    p     = table;
+    count = OTL_NEXT_UShort(p);
+    if ( index < count )
+    {
+      p     += index*2;
+      result = table + OTL_PEEK_UShort(p);
+    }
+    return  result;
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_table( OTL_Bytes  table,
+                             OTL_UInt   lookup_index,
+                             OTL_UInt   table_index )
+  {
+    OTL_Bytes  result = NULL;
+
+    result = otl_lookup_list_get_lookup( table, lookup_index );
+    if ( result )
+      result = otl_lookup_get_table( result, table_index );
+
+    return result;
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_lookup_list_foreach( OTL_Bytes        table,
+                           OTL_ForeachFunc  func,
+                           OTL_Pointer      func_data )
+  {
+    OTL_Bytes  p     = table;
+    OTL_UInt   count = OTL_NEXT_UShort(p);
+
+    for ( ; count > 0; count-- )
+      func( table + OTL_NEXT_USHORT(p), func_data );
+  }
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                        FEATURES                               *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_feature_validate( OTL_Bytes      table,
+                        OTL_Validator  valid )
+  {
+    OTL_Bytes   p = table;
+    OTL_UInt    feat_params, num_lookups;
+
+    if ( p + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    feat_params = OTL_NEXT_UShort(p);  /* ignored */
+    num_lookups = OTL_NEXT_UShort(p);
+
+    if ( p + num_lookups*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    /* XXX: check lookup indices */
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_count( OTL_Bytes   table )
+  {
+    OTL_Bytes  p = table + 4;
+
+    return OTL_PEEK_UShort(p);
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_lookups( OTL_Bytes   table,
+                           OTL_UInt    start,
+                           OTL_UInt    count,
+                           OTL_UInt   *lookups )
+  {
+    OTL_Bytes  p;
+    OTL_UInt   num_features, result = 0;
+
+    p            = table + 4;
+    num_features = OTL_NEXT_UShort(p);
+
+    p += start*2;
+
+    for ( ; count > 0 && start < num_features; count--, start++ )
+    {
+      lookups[0] = OTL_NEXT_UShort(p);
+      lookups++;
+      result++;
+    }
+
+    return result;
+  }
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                        FEATURE LIST                           *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+  OTL_LOCALDEF( void )
+  otl_feature_list_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   num_features, offset;
+
+    if ( table + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    num_features = OTL_NEXT_UShort(p);
+
+    if ( p + num_features*2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_features > 0; num_features-- )
+    {
+      p     += 4;   /* skip tag */
+      offset = OTL_NEXT_UShort(p);
+
+      otl_feature_table_validate( table + offset, valid );
+    }
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_list_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes  p = table;
+
+    return OTL_PEEK_UShort(p);
+  }
+
+
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_feature_list_get_feature( OTL_Bytes  table,
+                                OTL_UInt   index )
+  {
+    OTL_Bytes  p, result = NULL;
+    OTL_UInt   count;
+
+    p     = table;
+    count = OTL_NEXT_UShort(p);
+
+    if ( index < count )
+    {
+      p     += index*2;
+      result = table + OTL_PEEK_UShort(p);
+    }
+    return  result;
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_feature_list_foreach( OTL_Bytes        table,
+                            OTL_ForeachFunc  func,
+                            OTL_Pointer      func_data )
+  {
+    OTL_Bytes   p;
+    OTL_UInt    count;
+
+    p = table;
+    count = OTL_NEXT_UShort(p);
+
+    for ( ; count > 0; count-- )
+      func( table + OTL_NEXT_UShort(p), func_data );
+  }
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                                                               *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+  OTL_LOCALDEF( void )
+  otl_lang_validate( OTL_Bytes      table,
+                     OTL_Validator  valid )
+  {
+    OTL_Bytes  p = table;
+    OTL_UInt   lookup_order;
+    OTL_UInt   req_feature;
+    OTL_UInt   num_features;
+
+    if ( table + 6 >= valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    lookup_order = OTL_NEXT_UShort(p);
+    req_feature  = OTL_NEXT_UShort(p);
+    num_features = OTL_NEXT_UShort(p);
+
+    /* XXX: check req_feature if not 0xFFFFU */
+
+    if ( p + 2*num_features >= valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    /* XXX: check features indices !! */
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lang_get_count( OTL_Bytes  table )
+  {
+    OTL_Bytes   p  = table + 4;
+
+    return OTL_PEEK_UShort(p);
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lang_get_features( OTL_Bytes  table,
+                         OTL_UInt   start,
+                         OTL_UInt   count,
+                         OTL_UInt  *features )
+  {
+    OTL_Bytes   p            = table + 4;
+    OTL_UInt    num_features = OTL_NEXT_UShort(p);
+    OTL_UInt    result       = 0;
+
+    p += start*2;
+
+    for ( ; count > 0 && start < num_features; start++, count-- )
+    {
+      features[0] = OTL_NEXT_UShort(p);
+      features++;
+      result++;
+    }
+    return  result;
+  }
+
+
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lang_get_req_feature( OTL_Bytes   table )
+  {
+    OTL_Bytes  p = table + 2;
+
+    return OTL_PEEK_UShort(p);
+  }
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                                                               *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+
+  OTL_LOCALDEF( void )
+  otl_script_table_validate( OTL_Bytes      table,
+                             OTL_Validator  valid )
+  {
+    OTL_UInt   default_lang;
+    OTL_Bytes  p = table;
+
+    if ( table + 4 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    default_lang = OTL_NEXT_UShort(p);
+    num_langs    = OTL_NEXT_UShort(p);
+
+    if ( default_lang != 0 )
+    {
+      if ( table + default_lang >= valid->limit )
+        OTL_INVALID_OFFSET;
+    }
+
+    if ( p + num_langs*6 >= valid->limit )
+      OTL_INVALID_OFFSET;
+
+    for ( ; num_langs > 0; num_langs-- )
+    {
+      OTL_UInt  offset;
+
+      p     += 4;  /* skip tag */
+      offset = OTL_NEXT_UShort(p);
+
+      otl_lang_validate( table + offset, valid );
+    }
+  }
+
+
+  OTL_LOCALDEF( void )
+  otl_script_list_validate( OTL_Bytes      list,
+                            OTL_Validator  valid )
+  {
+    OTL_UInt  num_scripts;
+    OTL_Bytes p = list;
+
+    if ( list + 2 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    num_scripts = OTL_NEXT_UShort(p);
+
+    if ( p + num_scripts*6 > valid->limit )
+      OTL_INVALID_TOO_SHORT;
+
+    for ( ; num_scripts > 0; num_scripts-- )
+    {
+      OTL_UInt  offset;
+
+      p     += 4; /* skip tag */
+      offset = OTL_NEXT_UShort(p);
+
+      otl_script_table_validate( list + offset, valid );
+    }
+  }
+
+
--- /dev/null
+++ b/src/otlayout/otlcommn.h
@@ -1,0 +1,211 @@
+/***************************************************************************
+ *
+ *  otlcommn.h
+ *
+ *    OpenType Layout common tables processing
+ *
+ *  this header provides several routines used to process common table
+ *  found in various OpenType Layout tables..
+ */
+#ifndef __OTLAYOUT_COMMON_H__
+#define __OTLAYOUT_COMMON_H__
+
+#include "otlayout.h"
+
+OTL_BEGIN_HEADER
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                       COVERAGE TABLE                          *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate coverage table */
+  OTL_LOCALDEF( void )
+  otl_coverage_validate( OTL_Bytes      base,
+                         OTL_Validator  valid );
+
+ /* return number of covered glyphs */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_coverage_get_count( OTL_Bytes   base );
+
+
+ /* return the coverage index corresponding to a glyph glyph index. */
+ /* returns -1 if the glyph isn't covered..                         */
+  OTL_LOCALDEF( OTL_Int )
+  otl_coverage_get_index( OTL_Bytes   base,
+                          OTL_UInt    glyph_index );
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                  CLASS DEFINITION TABLE                       *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate class definition table */
+  OTL_LOCALDEF( void )
+  otl_class_definition_validate( OTL_Bytes      table,
+                                 OTL_Validator  valid );
+
+ /* return class value for a given glyph index */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_class_definition_get_value( OTL_Bytes  table,
+                                  OTL_UInt   glyph_index );
+
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                      DEVICE TABLE                             *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate a device table */
+  OTL_LOCALDEF( void )
+  otl_device_table_validate( OTL_Bytes      table,
+                             OTL_Validator  valid );
+
+
+ /* return a device table's first size */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_start( OTL_Bytes  table );
+
+
+ /* return a device table's last size */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_device_table_get_end( OTL_Bytes  table );
+
+
+ /* return pixel adjustment for a given size */
+  OTL_LOCALDEF( OTL_Int )
+  otl_device_table_get_delta( OTL_Bytes   table,
+                              OTL_UInt    size );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                           LOOKUPS                             *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate lookup table */
+  OTL_LOCALDEF( void )
+  otl_lookup_validate( OTL_Bytes      table,
+                       OTL_Validator  valid );
+
+ /* return number of sub-tables in a lookup */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_get_count( OTL_Bytes  table );
+
+
+ /* return lookup sub-table */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_get_table( OTL_Bytes  table,
+                        OTL_UInt   index );
+
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                      LOOKUP LISTS                             *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate lookup list */
+  OTL_LOCALDEF( void )
+  otl_lookup_list_validate( OTL_Bytes      table,
+                            OTL_Validator  valid );
+
+ /* return number of lookups in list */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_lookup_list_get_count( OTL_Bytes  table );
+
+
+ /* return a given lookup from a list */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_lookup( OTL_Bytes  table,
+                              OTL_UInt   index );
+
+
+ /* return lookup sub-table from a list */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_lookup_list_get_table( OTL_Bytes  table,
+                             OTL_UInt   lookup_index,
+                             OTL_UInt   table_index );
+
+ /* iterate over lookup list */
+  OTL_LOCALDEF( void )
+  otl_lookup_list_foreach( OTL_Bytes        table,
+                           OTL_ForeachFunc  func,
+                           OTL_Pointer      func_data );
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                        FEATURES                               *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate feature table */
+  OTL_LOCALDEF( void )
+  otl_feature_validate( OTL_Bytes      table,
+                        OTL_Validator  valid );
+
+ /* return feature's lookup count */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_count( OTL_Bytes   table );
+
+ /* get several lookups from a feature. returns the number of lookups grabbed */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_get_lookups( OTL_Bytes   table,
+                           OTL_UInt    start,
+                           OTL_UInt    count,
+                           OTL_UInt   *lookups );
+
+ /*************************************************************************/
+ /*************************************************************************/
+ /*****                                                               *****/
+ /*****                        FEATURE LIST                           *****/
+ /*****                                                               *****/
+ /*************************************************************************/
+ /*************************************************************************/
+
+ /* validate a feature list */
+  OTL_LOCALDEF( void )
+  otl_feature_list_validate( OTL_Bytes      table,
+                             OTL_Validator  valid );
+
+ /* return number of features in list */
+  OTL_LOCALDEF( OTL_UInt )
+  otl_feature_list_get_count( OTL_Bytes  table );
+
+
+ /* return a given feature from a list */
+  OTL_LOCALDEF( OTL_Bytes )
+  otl_feature_list_get_feature( OTL_Bytes  table,
+                                OTL_UInt   index );
+
+ /* iterate over all features in a list */
+  OTL_LOCALDEF( void )
+  otl_feature_list_foreach( OTL_Bytes        table,
+                            OTL_ForeachFunc  func,
+                            OTL_Pointer      func_data );
+
+ /* */
+
+OTL_END_HEADER
+
+#endif /* __OTLAYOUT_COMMON_H__ */
--- a/src/sfnt/sfobjs.c
+++ b/src/sfnt/sfobjs.c
@@ -300,6 +300,7 @@
     /* fonts within PDF documents, so don't check for them.            */
     (void)LOAD_( max_profile );
     (void)LOAD_( charmaps );
+
       
     /* the following tables are optional in PCL fonts -- */
     /* don't check for errors                            */
--- a/src/sfnt/ttcmap0.c
+++ b/src/sfnt/ttcmap0.c
@@ -34,8 +34,8 @@
 
 
 
-#define  TT_PEEK_Short   FT_PEEK_SHORT
-#define  TT_PEEK_UShort  FT_PEEK16_UBE
+#define  TT_PEEK_SHORT   FT_PEEK_SHORT
+#define  TT_PEEK_USHORT  FT_PEEK16_UBE
 #define  TT_PEEK_Long    FT_PEEK32_BE
 #define  TT_PEEK_ULong   FT_PEEK32_UBE
 
@@ -72,7 +72,7 @@
   tt_cmap0_validate( FT_Byte*      table,
                      FT_Validator  valid )
   {
-    FT_Byte*  p      = table + 2;  /* skip format */
+    FT_Byte*  p      = table + 2;
     FT_UInt   length = TT_NEXT_USHORT(p);
 
     if ( table + length > valid->limit || length < 262 )
@@ -83,6 +83,7 @@
     {
       FT_UInt  n, index;
 
+      p = table + 6;
       for ( n = 0; n < 256; n++ )
       {
         index = *p++;
@@ -183,7 +184,7 @@
   *    keys        6              USHORT[256]     sub-header keys
   *    subs        518            SUBHEAD[NSUBS]  sub-headers array
   *    glyph_ids   518+NSUB*8     USHORT[]        glyph id array
-  *    
+  *
   *   the 'keys' table is used to map charcode high-bytes to sub-headers.
   *   the value of 'NSUBS' is the number of sub-headers defined in the
   *   table and is computed by finding the maximum of the 'keys' table.
@@ -228,7 +229,7 @@
                      FT_Validator  valid )
   {
     FT_Byte*  p      = table + 2;  /* skip format */
-    FT_UInt   length = PEEK_UShort(p);
+    FT_UInt   length = TT_PEEK_USHORT(p);
     FT_UInt   n, max_subs;
     FT_Byte*  keys;        /* keys table */
     FT_Byte*  subs;        /* sub-headers */
@@ -256,6 +257,8 @@
         max_subs = index;
     }
 
+    FT_ASSERT( p == table + 518 );
+
     subs      = p;
     glyph_ids = subs + (max_subs + 1)*8;
     if ( glyph_ids > valid->limit )
@@ -322,8 +325,8 @@
     {
       FT_UInt  char_lo = (FT_UInt)( char_code & 0xFF );
       FT_UInt  char_hi = (FT_UInt)( char_code >> 8 );
-      FT_Byte* p       = table + 6;  /* keys table */
-      FT_Byte* subs    = p + 512;    /* subheaders table */
+      FT_Byte* p       = table + 6;    /* keys table */
+      FT_Byte* subs    = table + 518;  /* subheaders table */
       FT_Byte* sub;
 
 
@@ -339,14 +342,14 @@
         /* Otherwise, return 0                                 */
         /*                                                     */
         p  += char_lo*2;
-        if ( PEEK_UShort(p) != 0 )
+        if ( TT_PEEK_USHORT(p) != 0 )
           goto Exit;
       }
       else
       {
         /* a 16-bit character code */
-        p  += char_hi*2;                   /* jump to key entry */
-        sub = subs + PEEK_UShort(p);       /* jump to sub-header */
+        p  += char_hi*2;                       /* jump to key entry */
+        sub = subs + ( TT_PEEK_USHORT(p) & -8 );  /* jump to sub-header */
 
         /* check that the hi byte isn't a valid one-byte value */
         if ( sub == subs )
@@ -378,76 +381,23 @@
       start  = TT_NEXT_USHORT(p);
       count  = TT_NEXT_USHORT(p);
       delta  = TT_NEXT_SHORT(p);
-      offset = PEEK_UShort(p);
+      offset = TT_PEEK_USHORT(p);
 
       index -= start;
       if ( index < count && offset != 0 )
       {
         p    += offset + 2*index;
-        index = PEEK_UShort(p);
+        index = TT_PEEK_USHORT(p);
 
-        if ( index == 0 )
-          goto Exit;
-
-        result = (FT_UInt)( index + delta ) & 0xFFFFU;
+        if ( index != 0 )
+          result = (FT_UInt)( index + delta ) & 0xFFFFU;
       }
     }
-
-  Exit:
     return result;
   }
 
 
- /* return first valid charcode in a format 2 sub-header */
-  static FT_ULong
-  tt_cmap2_subheader_first( FT_Byte*  subheader,
-                            FT_UInt   char_hi,
-                            FT_UInt  *agindex )
-  {
-    FT_ULong  result    = 0;
-    FT_UInt   n, gindex = 0;
-    FT_Byte*  p         = subheader;
 
-    FT_UInt   start  = TT_NEXT_USHORT(p);
-    FT_UInt   count  = TT_NEXT_USHORT(p);
-
-    if ( count > 0 )
-    {
-      FT_Int    delta  = TT_NEXT_SHORT(p);
-      FT_UInt   offset = TT_NEXT_USHORT(p);
-
-      if ( offset == 0 )
-      {
-        /* simple difference, compute directly */
-        result = char_hi*256 + start;
-        gindex = (FT_UInt)( start + delta ) & 0xFFFFU;
-      }
-      else
-      {
-        FT_UInt  i, index;
-
-        /* parse glyph id table for non-0 indices */
-        p += offset - 2;
-        for (; i < count; i++ )
-        {
-          index = TT_NEXT_USHORT(p);
-          if ( index != 0 )
-          {
-            result = char_hi*256 + start + i;
-            gindex = (FT_UInt)(index + delta) & 0xFFFFU;
-            break;
-          }
-        }
-      }
-    }
-
-    if ( agindex )
-      *agindex = gindex;
-
-    return result;
-  }
-
-
   static FT_UInt
   tt_cmap2_char_next( FT_Byte*  table,
                       FT_ULong  char_code,
@@ -459,7 +409,7 @@
     FT_Byte*  p;
 
     ++char_code;
-    for (;;)
+    while ( char_code < 0x10000U )
     {
       subheader = tt_cmap2_get_subheader( table, char_code );
       if ( subheader )
@@ -468,7 +418,7 @@
         FT_UInt   start   = TT_NEXT_USHORT(p);
         FT_UInt   count   = TT_NEXT_USHORT(p);
         FT_Int    delta   = TT_NEXT_SHORT(p);
-        FT_UInt   offset  = PEEK_UShort(p);
+        FT_UInt   offset  = TT_PEEK_USHORT(p);
         FT_UInt   char_lo = (FT_UInt)( char_code & 0xFF );
         FT_UInt   pos, index;
 
@@ -505,8 +455,6 @@
       /* jump to next sub-header, i.e. higher byte value */
     Next_SubHeader:
       char_code = (char_code & -256) + 256;
-      if ( char_code >= 0x10000U )
-        break;
     }
 
   Exit:
@@ -534,6 +482,58 @@
  /************************************************************************/
  /************************************************************************/
 
+ /*************************************************************************
+  *
+  *  TABLE OVERVIEW:
+  *  ---------------
+  *
+  *    NAME        OFFSET           TYPE               DESCRIPTION
+  *
+  *    format        0              USHORT             must be 4
+  *    length        2              USHORT             table length in bytes
+  *    language      4              USHORT             Mac language code
+  *
+  *    segCountX2    6              USHORT             2*NUM_SEGS
+  *    searchRange   8              USHORT             2*(1 << LOG_SEGS)
+  *    entrySelector 10             USHORT             LOG_SEGS
+  *    rangeShift    12             USHORT             segCountX2 - searchRange
+  *
+  *    endCount      14             USHORT[NUM_SEGS]   end charcode for each
+  *                                                    segment. last is 0xFFFF
+  *
+  *    pad           14+NUM_SEGS*2  USHORT             padding
+  *
+  *    startCount    16+NUM_SEGS*2  USHORT[NUM_SEGS]   first charcode for each
+  *                                                    segment
+  *
+  *    idDelta       16+NUM_SEGS*4  SHORT[NUM_SEGS]    delta for each segment
+  *
+  *    idOffset      16+NUM_SEGS*6  SHORT[NUM_SEGS]    range offset for each
+  *                                                    segment. can be 0
+  *
+  *    glyphIds      16+NUM_SEGS*8  USHORT[]           array og glyph id ranges
+  *
+  *
+  *  Charcodes are modelled by a series of ordered (increasing) intervals
+  *  called segments. Each segment has start and end codes, provided by
+  *  the 'startCount' and 'endCount' arrays. Segments must not be over-lapping
+  *  and the last segment should always contain the '0xFFFF' endCount.
+  *
+  *  The fields 'searchRange', 'entrySelector' and 'rangeShift' are better
+  *  ignored (they're traces of over-engineering in the TT specification)
+  *
+  *  Each segment also has a signed 'delta', as well as an optional offset
+  *  within the 'glyphIds' table.
+  *
+  *  if a segment's idOffset is 0, then the glyph index corresponding to
+  *  any charcode within the segment is obtained by adding the value of
+  *  'idDelta' directly to the charcode, modulo 65536
+  *
+  *  otherwise, a glyph index is taken from the glyph ids sub-array for the
+  *  segment, and the value of 'idDelta' is added to it..
+  */
+
+
 #ifdef TT_CONFIG_CMAP_FORMAT_4
 
   static void
@@ -542,14 +542,13 @@
   {
     FT_Byte*  p      = table + 2;  /* skip format */
     FT_UInt   length = TT_NEXT_USHORT(p);
-    FT_Byte   *ends, *starts, *offsets, *glyph_ids;
+    FT_Byte   *ends, *starts, *offsets, *deltas, *glyph_ids;
     FT_UInt   n, num_segs;
 
     if ( table + length > valid->limit || length < 16 )
       TOO_SHORT;
 
-    p += 2;  /* skip language */
-
+    p        = table + 6;
     num_segs = TT_NEXT_USHORT(p);   /* read segCountX2 */
 
     if ( valid->level >= FT_VALIDATE_PARANOID )
@@ -584,12 +583,11 @@
            search_range != (1 << entry_selector)  )
         INVALID_DATA;
     }
-    else
-      p += 6;
 
-    ends      = p;
-    starts    = ends + num_segs*2 + 2;
-    offsets   = starts + num_segs*4;
+    ends      = table   + 14;
+    starts    = table   + 16 + num_segs*2;
+    deltas    = starts  + num_segs*2;
+    offsets   = deltas  + num_segs*2;
     glyph_ids = offsets + num_segs*2;
 
     if ( glyph_ids >= table + length )
@@ -599,7 +597,7 @@
     if ( valid->level >= FT_VALIDATE_PARANOID )
     {
       p = ends + (num_segs-1)*2;
-      if ( PEEK_UShort(p) != 0xFFFFU )
+      if ( TT_PEEK_USHORT(p) != 0xFFFFU )
         INVALID_DATA;
     }
 
@@ -607,12 +605,14 @@
     /* check also the offsets..                                              */
     {
       FT_UInt  start, end, last = 0,offset, n;
+      FT_Int   delta;
 
       for ( n = 0; n < num_segs; n++ )
       {
-        p = starts + n*2;  start  = PEEK_UShort(p);
-        p = ends   + n*2;  end    = PEEK_UShort(p);
-        p = offsets + n*2; offset = PEEK_UShort(p);
+        p = starts  + n*2;  start  = TT_PEEK_USHORT(p);
+        p = ends    + n*2;  end    = TT_PEEK_USHORT(p);
+        p = deltas  + n*2;  delta  = TT_PEEK_SHORT(p);
+        p = offsets + n*2;  offset = TT_PEEK_USHORT(p);
 
         if ( end > start )
           INVALID_DATA;
@@ -625,10 +625,26 @@
           p += offset;  /* start of glyph id array */
 
           /* check that we point within the glyph ids table only */
-          if ( p < glyph_ids || p + (end - start + 1) > table + length )
+          if ( p < glyph_ids || p + (end - start + 1)*2 > table + length )
             INVALID_DATA;
 
-          /* XXXX: check glyph ids !! */
+          /* check glyph indices within the segment range */
+          if ( valid->level >= FT_VALIDATE_TIGHT )
+          {
+            FT_UInt   index;
+
+            for ( ; start < end; )
+            {
+              index = NEXT_USHORT(p);
+              if ( index != 0 )
+              {
+                index = (FT_UInt)(index + delta) & 0xFFFFU;
+
+                if ( index >= valid->num_glyphs )
+                  INVALID_GLYPH_ID;
+              }
+            }
+          }
         }
         last = end;
       }
@@ -651,7 +667,7 @@
       FT_UInt   code = (FT_UInt)char_code;
 
       p         = table + 6;
-      num_segs2 = PEEK_UShort(p);
+      num_segs2 = TT_PEEK_USHORT(p) & -2;  /* be paranoid !! */
 
       p = table + 14;               /* ends table   */
       q = table + 16 + num_segs2;   /* starts table */
@@ -668,13 +684,13 @@
         {
           index = (FT_UInt)( char_code - start );
 
-          p  = q + num_segs2 - 2; delta  = PEEK_Short(p);
-          p += num_segs2;         offset = PEEK_UShort(p);
+          p  = q + num_segs2 - 2; delta  = TT_PEEK_SHORT(p);
+          p += num_segs2;         offset = TT_PEEK_USHORT(p);
 
           if ( offset != 0 )
           {
             p    += offset + 2*index;
-            index = PEEK_UShort(p);
+            index = TT_PEEK_USHORT(p);
           }
 
           if ( index != 0 )
@@ -703,7 +719,7 @@
 
     code      = (FT_UInt)char_code;
     p         = table + 6;
-    num_segs2 = PEEK_UShort(p) & -2;  /* ensure even-ness */
+    num_segs2 = TT_PEEK_USHORT(p) & -2;  /* ensure even-ness */
 
     for (;;)
     {
@@ -723,8 +739,8 @@
 
         if ( code <= end )
         {
-          p  = q + num_segs2 - 2; delta  = PEEK_Short(p);
-          p += num_segs2;         offset = PEEK_UShort(p);
+          p  = q + num_segs2 - 2; delta  = TT_PEEK_SHORT(p);
+          p += num_segs2;         offset = TT_PEEK_USHORT(p);
 
           if ( offset != 0 )
           {
@@ -785,6 +801,25 @@
  /************************************************************************/
  /************************************************************************/
 
+ /*************************************************************************
+  *
+  *  TABLE OVERVIEW:
+  *  ---------------
+  *
+  *    NAME        OFFSET           TYPE               DESCRIPTION
+  *
+  *    format        0              USHORT             must be 4
+  *    length        2              USHORT             table length in bytes
+  *    language      4              USHORT             Mac language code
+  *
+  *    first         6              USHORT             first segment code
+  *    count         8              USHORT             segment size in chars
+  *    glyphIds      10             USHORT[count]      glyph ids
+  *
+  *
+  *  A very simplified segment mapping
+  */
+
 #ifdef TT_CONFIG_CMAP_FORMAT_6
 
   static void
@@ -791,14 +826,16 @@
   tt_cmap6_validate( FT_Byte*      table,
                      FT_Validator  valid )
   {
-    FT_Byte*  p = table + 2;
+    FT_Byte*  p;
     FT_UInt   length, start, count;
 
     if ( table + 10 > valid->limit )
       INVALID_TOO_SHORT;
 
+    p      = table + 2;
     length = TT_NEXT_USHORT(p);
-    p     += 2;  /* skip language */
+
+    p      = table + 6;  /* skip language */
     start  = TT_NEXT_USHORT(p);
     count  = TT_NEXT_USHORT(p);
 
@@ -833,7 +870,7 @@
     if ( index < count )
     {
       p += 2*index;
-      result = PEEK_UShort(p);
+      result = TT_PEEK_USHORT(p);
     }
     return result;
   }
@@ -924,6 +961,28 @@
  /************************************************************************/
  /************************************************************************/
 
+ /*************************************************************************
+  *
+  *  TABLE OVERVIEW:
+  *  ---------------
+  *
+  *    NAME        OFFSET           TYPE               DESCRIPTION
+  *
+  *    format        0              USHORT             must be 8
+  *    reseved       2              USHORT             reserved
+  *    length        4              ULONG              length in bytes
+  *    language      8              ULONG              Mac language code
+  *    is32          12             BYTE[8192]         32-bitness bitmap
+  *    count         8204           ULONG              number of groups
+  *
+  *  this header is followed by 'count' groups of the following format:
+  *
+  *    start         0              ULONG              first charcode
+  *    end           4              ULONG              last charcode
+  *    startId       8              ULONG              start glyph id for
+  *                                                    the group
+  */
+
 #ifdef TT_CONFIG_CMAP_FORMAT_8
 
   static void
@@ -939,11 +998,11 @@
       INVALID_TOO_SHORT;
 
     length = TT_NEXT_ULONG(p);
-    if ( table + length > valid->limit || length < 16 + 8192 )
+    if ( table + length > valid->limit || length < 8208 )
       INVALID_TOO_SHORT;
 
-    is32       = p + 4;        /* skip language     */
-    p          = is32 + 8192;  /* skip 'is32' array */
+    is32       = table + 12;
+    p          = is32  + 8192;  /* skip 'is32' array */
     num_groups = TT_NEXT_ULONG(p);
 
     if ( p + num_groups*12 > valid->limit )
@@ -983,10 +1042,10 @@
             {
               hi = (FT_UInt)(start >> 16);
               lo = (FT_UInt)(start & 0xFFFFU);
-  
+
               if ( is32[ hi >> 3 ] & (0x80 >> (hi & 7)) == 0 )
                 INVALID_DATA;
-  
+
               if ( is32[ lo >> 3 ] & (0x80 >> (lo & 7)) == 0 )
                 INVALID_DATA;
             }
@@ -995,20 +1054,22 @@
           {
             /* start_hi == 0, check that is32[i] is 0 for each i in */
             /* the range [start..end]                               */
-  
+
             /* end_hi cannot be != 0 !! */
             if ( end & ~0xFFFFU )
               INVALID_DATA;
-  
+
             for ( ; count > 0; count--, start++ )
             {
               lo = (FT_UInt)(start & 0xFFFFU);
-  
+
               if ( is32[ lo >> 3 ] & (0x80 >> (lo & 7)) != 0 )
                 INVALID_DATA;
             }
           }
         }
+
+        last = end;
       }
     }
   }
@@ -1019,19 +1080,19 @@
                        FT_ULong   char_code )
   {
     FT_UInt   result     = 0;
-    FT_Byte*  p          = table + 12 + 8192;
+    FT_Byte*  p          = table + 8204;
     FT_ULong  num_groups = TT_NEXT_ULONG(p);
     FT_ULong  n, start, end, start_id;
-    
+
     for ( ; num_groups > 0; num_groups-- )
     {
       start    = TT_NEXT_ULONG(p);
       end      = TT_NEXT_ULONG(p);
       start_id = TT_NEXT_ULONG(p);
-      
+
       if ( char_code < start )
         break;
-        
+
       if ( char_code <= end )
       {
         result = start_id + char_code - start;
@@ -1049,22 +1110,22 @@
   {
     FT_ULong   result     = 0;
     FT_UInt    gindex     = 0;
-    FT_Byte*   p          = table + 12 + 8192;
-    FT_ULong   num_groups = TT_NEXT_USHORT(p);
+    FT_Byte*   p          = table + 8204;
+    FT_ULong   num_groups = TT_NEXT_ULONG(p);
     FT_ULong   n, start, end, start_id;
-    
+
     ++char_code;
-    p = table + 16 + 8192;
-    
+    p = table + 8208;
+
     for ( n = 0; n < num_groups++; n++ )
     {
       start    = TT_NEXT_ULONG(p);
       end      = TT_NEXT_ULONG(p);
       start_id = TT_NEXT_ULONG(p);
-      
+
       if ( char_code < start )
         char_code = start;
-      
+
       if ( char_code <= end )
       {
         gindex = (FT_UInt)(char_code - start + start_id);
@@ -1075,13 +1136,13 @@
         }
       }
     }
-    
+
   Exit:
     if ( agindex )
       *agindex = gindex;
-    
+
     return result;
-  }                      
+  }
 
 
   static const TT_Cmap_ClassRec  tt_cmap8_class_rec =
@@ -1101,6 +1162,23 @@
  /************************************************************************/
  /************************************************************************/
 
+ /*************************************************************************
+  *
+  *  TABLE OVERVIEW:
+  *  ---------------
+  *
+  *    NAME        OFFSET           TYPE               DESCRIPTION
+  *
+  *    format        0              USHORT             must be 10
+  *    reseved       2              USHORT             reserved
+  *    length        4              ULONG              length in bytes
+  *    language      8              ULONG              Mac language code
+  *
+  *    start        12              ULONG              first char in range
+  *    count        16              ULONG              number of chars in range
+  *    glyphIds     20              USHORT[count]      glyph indices covered
+  */
+
 #ifdef TT_CONFIG_CMAP_FORMAT_10
 
   static void
@@ -1107,14 +1185,14 @@
   tt_cmap10_validate( FT_Byte*      table,
                       FT_Validator  valid )
   {
-    FT_Byte*  p = table + 2;
+    FT_Byte*  p = table + 4;
     FT_ULong  length, start, count;
 
     if ( table + 20 > valid->limit )
       INVALID_TOO_SHORT;
 
-    length = TT_NEXT_USHORT(p);
-    p     += 4;  /* skip language */
+    length = TT_NEXT_ULONG(p);
+    p      = table + 12;
     start  = TT_NEXT_ULONG(p);
     count  = TT_NEXT_ULONG(p);
 
@@ -1148,8 +1226,8 @@
 
     if ( index < count )
     {
-      p += 2*index;
-      result = PEEK_UShort(p);
+      p     += 2*index;
+      result = TT_PEEK_USHORT(p);
     }
     return result;
   }
@@ -1168,9 +1246,6 @@
     FT_ULong  index;
 
     char_code++;
-    if ( char_code >= 0x10000U )
-      goto Exit;
-
     if ( char_code < start )
       char_code = start;
 
@@ -1213,6 +1288,28 @@
  /************************************************************************/
  /************************************************************************/
 
+ /*************************************************************************
+  *
+  *  TABLE OVERVIEW:
+  *  ---------------
+  *
+  *    NAME        OFFSET           TYPE               DESCRIPTION
+  *
+  *    format        0              USHORT             must be 12
+  *    reseved       2              USHORT             reserved
+  *    length        4              ULONG              length in bytes
+  *    language      8              ULONG              Mac language code
+  *    count         12             ULONG              number of groups
+  *                  16
+  *
+  *  this header is followed by 'count' groups of the following format:
+  *
+  *    start         0              ULONG              first charcode
+  *    end           4              ULONG              last charcode
+  *    startId       8              ULONG              start glyph id for
+  *                                                    the group
+  */
+
 #ifdef TT_CONFIG_CMAP_FORMAT_12
 
   static void
@@ -1219,24 +1316,124 @@
   tt_cmap12_validate( FT_Byte*      table,
                       FT_Validator  valid )
   {
-  }                      
+    FT_Byte*   p;
+    FT_ULong   length;
+    FT_ULong   num_groups;
 
+    if ( table + 16 > valid->limit )
+      INVALID_TOO_SHORT;
 
+    p      = table + 4;
+    length = TT_NEXT_ULONG(p);
+
+    p          = table + 12;
+    num_groups =  TT_NEXT_ULONG(p);
+
+    if ( table + length > valid->limit || length < 16 + 12*num_groups )
+      INVALID_TOO_SHORT;
+
+    /* check groups, they must be in increasing order */
+    {
+      FT_ULong  n, start, end, start_id, count, last = 0;
+
+      for ( n = 0; n < num_groups; n++ )
+      {
+        FT_Bytes* q;
+        FT_UInt   hi, lo;
+
+        start    = TT_NEXT_ULONG(p);
+        end      = TT_NEXT_ULONG(p);
+        start_id = TT_NEXT_ULONG(p);
+
+        if ( start > end )
+          INVALID_DATA;
+
+        if ( n > 0 && start <= last )
+          INVALID_DATA;
+
+        if ( valid->level >= FT_VALIDATE_TIGHT )
+        {
+          if ( start_id + end - start >= valid->num_glyphs )
+            INVALID_GLYPH_ID;
+        }
+
+        last = end;
+      }
+    }
+  }
+
+
+
   static FT_UInt
   tt_cmap12_char_index( FT_Byte*   table,
                         FT_ULong   char_code )
   {
-  }                        
+    FT_UInt   result     = 0;
+    FT_Byte*  p          = table + 12;
+    FT_ULong  num_groups = TT_NEXT_ULONG(p);
+    FT_ULong  n, start, end, start_id;
 
+    for ( ; num_groups > 0; num_groups-- )
+    {
+      start    = TT_NEXT_ULONG(p);
+      end      = TT_NEXT_ULONG(p);
+      start_id = TT_NEXT_ULONG(p);
 
+      if ( char_code < start )
+        break;
+
+      if ( char_code <= end )
+      {
+        result = start_id + char_code - start;
+        break;
+      }
+    }
+    return result;
+  }
+
+
   static FT_ULong
   tt_cmap12_char_next( FT_Byte*   table,
                        FT_ULong   char_code,
                        FT_UInt   *agindex )
   {
-  }                       
+    FT_ULong   result     = 0;
+    FT_UInt    gindex     = 0;
+    FT_Byte*   p          = table + 12;
+    FT_ULong   num_groups = TT_NEXT_ULONG(p);
+    FT_ULong   n, start, end, start_id;
 
+    ++char_code;
+    p = table + 8208;
 
+    for ( n = 0; n < num_groups++; n++ )
+    {
+      start    = TT_NEXT_ULONG(p);
+      end      = TT_NEXT_ULONG(p);
+      start_id = TT_NEXT_ULONG(p);
+
+      if ( char_code < start )
+        char_code = start;
+
+      if ( char_code <= end )
+      {
+        gindex = (FT_UInt)(char_code - start + start_id);
+        if ( gindex != 0 )
+        {
+          result = char_code;
+          goto Exit;
+        }
+      }
+    }
+
+  Exit:
+    if ( agindex )
+      *agindex = gindex;
+
+    return result;
+  }
+
+
   static const TT_Cmap_ClassRec  tt_cmap12_class_rec =
   {
     (TT_CMap_ValidateFunc)  tt_cmap12_validate,
@@ -1246,3 +1443,4 @@
 
 #endif /* TT_CONFIG_CMAP_FORMAT_12 */
 
+/* END */
--- /dev/null
+++ b/src/type1/t1cmap.c
@@ -1,0 +1,414 @@
+#include "t1cmap.h"
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****           TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS            *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  static( void )
+  t1_cmap_std_init( T1_CMapStd   cmap,
+                    FT_Int       is_expert )
+  {
+    T1_Face             face    = (T1_Face) FT_CMAP_FACE(cmap);
+    PSNames_Interface*  psnames = face->psnames;
+
+    cmap->num_glyphs  = face->type1.num_glyphs;
+    cmap->glyph_names = face->type1.glyph_names;
+    cmap->sid_strings = sid_strings;
+    cmap->code_to_sid = is_expert ? psnames->adobe_expert_encoding
+                                  : psnames->adobe_std_encoding;
+
+    FT_ASSERT( cmap->code_to_sid != NULL );
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  t1_cmap_std_done( T1_CMapStd  cmap )
+  {
+    cmap->num_glyphs  = 0;
+    cmap->glyph_names = NULL;
+    cmap->sid_strings = NULL;
+    cmap->code_to_sid = NULL;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_std_char_index( T1_CMapStd   cmap,
+                          FT_UInt32    char_code )
+  {
+    FT_UInt  result = 0;
+
+    if ( char_code < 256 )
+    {
+      FT_UInt      code;
+      const char*  glyph_name;
+      FT_Int       n;
+
+      /* conver character code to Adobe SID string */
+      code       = cmap->code_to_sid[ char_code ];
+      glyph_name = cmap->adobe_sid_strings[ code ];
+
+      /* look for the corresponding glyph name */
+      for ( n = 0; n < cmap->num_glyphs; n++ )
+      {
+        const char* gname = cmap->glyph_names[n];
+
+        if ( gname && gname[0] == glyph_name[0] &&
+             strcmp( gname, glyph_name ) == 0   )
+        {
+          result = n;
+          break;
+        }
+      }
+    }
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_std_char_next( T1_CMapStd   cmap,
+                         FT_UInt32   *pchar_code )
+  {
+    FT_UInt   result    = 0;
+    FT_UInt32 char_code = *pchar_code;
+
+    ++char_code;
+    while ( char_code < 256 )
+    {
+      result = t1_cmap_standard_char_index( cmap, char_code );
+      if ( result != 0 )
+        goto Exit;
+
+      char_code++;
+    }
+    char_code = 0;
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  t1_cmap_standard_init( T1_CMapStd  cmap )
+  {
+    t1_cmap_std_init( cmap, 0 );
+    return 0;
+  }
+
+
+  FT_CALLBACK_TABLE const T1_CMap_ClassRec
+  t1_cmap_standard_class_rec =
+  {
+    sizeof( T1_CMapStdRec ),
+
+    t1_cmap_standard_init,
+    t1_cmap_std_done,
+    t1_cmap_std_char_index,
+    t1_cmap_std_char_next
+  };
+
+
+  FT_LOCAL_DEF T1_CMap_Class
+  t1_cmap_standard_class = &t1_cmap_standard_class_rec;
+
+
+
+
+
+  FT_CALLBACK_DEF( void )
+  t1_cmap_expert_init( T1_CMapStd  cmap )
+  {
+    t1_cmap_std_init( cmap, 1 );
+    return 0;
+  }
+
+  FT_CALLBACK_TABLE const T1_CMap_ClassRec
+  t1_cmap_expert_class_rec =
+  {
+    sizeof( T1_CMapStdRec ),
+
+    t1_cmap_expert_init,
+    t1_cmap_std_done,
+    t1_cmap_std_char_index,
+    t1_cmap_std_char_next
+  };
+
+
+  FT_LOCAL_DEF T1_CMap_Class
+  t1_cmap_expert_class = &t1_cmap_expert_class_rec;
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****                    TYPE1 CUSTOM ENCODING CMAP                   *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  t1_cmap_custom_init( T1_CMapCustom  cmap )
+  {
+    T1_Face       face     = (T1_Face) FT_CMAP_FACE(cmap);
+    T1_Encoding*  encoding = face->type1.encoding;
+
+    cmap->first   = encoding->code_first;
+    cmap->count   = (FT_UInt)(encoding->code_last - cmap->first + 1);
+    cmap->indices = encoding->char_index;
+
+    FT_ASSERT( cmap->indices != NULL );
+    FT_ASSERT( encoding->code_first <= encoding->code_last );
+
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  t1_cmap_custom_done( T1_CMapCustom  cmap )
+  {
+    cmap->indices = NULL;
+    cmap->first   = 0;
+    cmap->count   = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_custom_char_index( T1_CMapCustom  cmap,
+                             FT_UInt32      char_code )
+  {
+    FT_UInt    result = 0;
+    FT_UInt32  index;
+
+    index = (FT_UInt32)( char_code - cmap->first );
+    if ( index < cmap->count )
+      result = cmap->indices[ index ];
+
+    return result;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_custom_char_next( T1_CMapCustion  cmap,
+                            FT_UInt32      *pchar_code )
+  {
+    FT_UInt   result = 0;
+    FT_UInt32 char_code = *pchar_code;
+    FT_UInt32 index;
+
+    ++char_code;
+
+    if ( char_code < cmap->first )
+      char_code = cmap->first;
+
+    index = (FT_UInt32)( char_code - cmap->first );
+    while ( index < cmap->count; index++, char_code++ )
+    {
+      result = cmap->indices[index];
+      if ( result != 0 )
+        goto Exit;
+    }
+
+    char_code = 0;
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  t1_cmap_custom_class_rec =
+  {
+    sizeof( T1_CMapCustomRec ),
+    t1_cmap_custom_init,
+    t1_cmap_custom_done,
+    t1_cmap_custom_char_index,
+    t1_cmap_custom_char_next
+  };
+
+
+  FT_LOCAL_DEF FT_CMap_Class
+  t1_cmap_custom_class = &t1_cmap_custom_class_rec;
+
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****             TYPE1 SYNTHETIC UNICODE ENCODING CMAP               *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+
+  FT_CALLBACK_DEF( FT_Error )
+  t1_cmap_unicode_init( T1_CMapUnicode  cmap )
+  {
+    FT_Error    error;
+    FT_UInt     count;
+    T1_Face     face   = (T1_Face) FT_CMAP_FACE(cmap);
+    FT_Memory   memory = FT_FACE_MEMORY(face);
+
+    cmap->num_pairs = 0;
+    cmap->pairs     = NULL;
+
+    count = face->type1.num_glyphs;
+
+    if ( !ALLOC_ARRAY( cmap->pairs, count, T1_CMapUniPairRec ) )
+    {
+      FT_UInt         n, new_count;
+      T1_CMapUniPair  pair;
+      FT_UInt32       uni_code;
+
+
+      pair = cmap->pairs;
+      for ( n = 0; n < count; n++ )
+      {
+        const char*  gname = face->type1.glyph_names[n];
+
+        /* build unsorted pair table by matching glyph names */
+        if ( gname )
+        {
+          uni_code = PS_Unicode_Value( gname );
+
+          if ( uni_code != 0 )
+          {
+            pair->unicode = uni_code;
+            pair->gindex  = n;
+            pair++;
+          }
+        }
+
+        if ( new_count == 0 )
+        {
+          /* there are no unicode characters in here !! */
+          FREE( cmap->pairs );
+          error = FT_Err_Invalid_Argument;
+        }
+        else
+        {
+          /* re-allocate if the new array is much smaller than the original */
+          /* one..                                                          */
+          if ( new_count != count && new_count < count/2 )
+            REALLOC_ARRAY( cmap->pairs, count, new_count, T1_CMapUniPairRec )
+
+          /* sort the pairs table to allow efficient binary searches */
+          qsort( cmap->pairs,
+                 new_count,
+                 sizeof(T1_CMapUniPairRec),
+                 t1_cmap_uni_pair_compare );
+          
+          cmap->num_pairs = new_count;
+        }
+      }
+    }
+
+    return error;
+  }
+
+
+  FT_CALLBACK_DEF( void )
+  t1_cmap_unicode_done( T1_CMapUnicode  cmap )
+  {
+    FT_Face    face = FT_CMAP_FACE(cmap);
+    FT_Memory  memory = FT_FACE_MEMORY(face);
+    
+    FREE( cmap->pairs );
+    cmap->num_pairs = 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_unicode_char_index( T1_CMapUnicode  cmap,
+                              FT_UInt32       char_code )
+  {
+    FT_UInt         min = 0;
+    FT_UInt         max = cmap->num_pairs;
+    FT_UInt         mid;
+    T1_CMapUniPair  pair;
+    
+    while ( min < max )
+    {
+      mid  = min + (max - min)/2;
+      pair = cmap->pairs + mid;
+      
+      if ( pair->unicode == char_code )
+        return pair->gindex;
+        
+      if ( pair->unicode < char_code )
+        min = mid+1;
+      else
+        max = mid;
+    }
+    return 0;
+  }
+
+
+  FT_CALLBACK_DEF( FT_UInt )
+  t1_cmap_unicode_char_next( T1_CMapUnicode  cmap,
+                             FT_UInt32      *pchar_code )
+  {
+    FT_UInt32       char_code = *pchar_code + 1;
+
+  Restart:
+    {
+      FT_UInt         min = 0;
+      FT_UInt         max = cmap->num_pairs;
+      FT_UInt         mid;
+      T1_CMapUniPair  pair;
+
+      while ( min < max )
+      {
+        mid  = min + (max - min)/2;
+        pair = cmap->pairs + mid;
+        
+        if ( pair->unicode == char_code )
+        {
+          result = pair->gindex;
+          if ( result != 0 )
+            goto Exit;
+          
+          char_code++;
+          goto Restart;
+        }
+        
+        if ( pair->unicode < char_code )
+          min = mid+1;
+        else
+          max = mid;
+      }
+    
+      /* we didn't find it, but we have a pair just above it */
+      char_code = 0;
+      
+      if ( min < cmap->num_pairs )
+      {
+        pair   = cmap->num_pairs + min;
+        result = pair->gindex;
+        if ( result != 0 )
+          char_code = pair->unicode;
+      }
+    }
+
+  Exit:
+    *pchar_code = char_code;
+    return result;
+  }
+
+
+  FT_CALLBACK_TABLE const FT_CMap_ClassRec
+  t1_cmap_unicode_class_rec =
+  {
+    sizeof( T1_CMapUnicodeRec ),
+    t1_cmap_unicode_init,
+    t1_cmap_unicode_done,
+    t1_cmap_unicode_char_index,
+    t1_cmap_unicode_char_next
+  };
+
+
+  
\ No newline at end of file
--- /dev/null
+++ b/src/type1/t1cmap.h
@@ -1,0 +1,92 @@
+#ifndef __FT_TYPE1_CMAP_H__
+#define __FT_TYPE1_CMAP_H__
+
+FT_BEGIN_HEADER
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****           TYPE1 STANDARD (AND EXPERT) ENCODING CMAPS            *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  typedef struct T1_CMapStrRec_*       T1_CMapStd;
+
+  typedef struct T1_CMapUnicodeRec_*   T1_CMapUnicode;
+
+  
+  typedef struct T1_CMapStdRec_
+  {
+    FT_CMapRec          cmap;
+
+    const FT_UShort*    charcode_to_sid;
+    const char* const*  adobe_sid_strings;
+
+    FT_UInt             num_glyphs;
+    const char**        glyph_names;
+    
+    
+  } T1_CMapStdRec;
+
+
+  FT_LOCAL( FT_CMap_Class )   t1_cmap_standard_class;
+
+  FT_LOCAL( FT_CMap_Class )   t1_cmap_expert_class;
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****                    TYPE1 CUSTOM ENCODING CMAP                   *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  typedef struct T1_CMapCustomRec_*    T1_CMapCustom;
+  
+  typedef struct T1_CMapCustomRec_
+  {
+    FT_CMapRec    cmap;
+    FT_UInt       first;
+    FT_UInt       count;
+    FT_UInt*      indices;
+  
+  } T1_CMapCustomRec;
+
+
+  FT_LOCAL( FT_CMap_Class )   t1_cmap_custom_class;
+
+ /***************************************************************************/
+ /***************************************************************************/
+ /*****                                                                 *****/
+ /*****             TYPE1 SYNTHETIC UNICODE ENCODING CMAP               *****/
+ /*****                                                                 *****/
+ /***************************************************************************/
+ /***************************************************************************/
+
+  typedef struct T1_CMapUniPairRec_*   T1_CMapUniPair;
+  
+  typedef struct T1_CMapUniPairRec_
+  {
+    FT_UInt32  unicode;
+    FT_UInt    gindex;
+  
+  } T1_CMapUniPairRec;
+
+
+  typedef struct T1_CMapUnicodeRec_
+  {
+    FT_CMapRec      cmap;
+    FT_UInt         num_pairs;
+    T1_CMapUniPair  pairs;
+
+  } T1_CMapUnicodeRec;
+
+
+  FT_LOCAL( FT_CMap_Class )   t1_cmap_unicode_class;
+
+ /* */
+ 
+FT_END_HEADER
+
+#endif /* __FT_TYPE1_CMAP_H__ */