text: /***************************************************************************/
  /*                                                                         */
  /*  psmodule.c                                                             */
  /*                                                                         */
  /*    PSNames module implementation (body).                                */
  /*                                                                         */
  /*  Copyright 1996-2015 by                                                 */
  /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
  /*                                                                         */
  /*  This file is part of the FreeType project, and may only be used,       */
  /*  modified, and distributed under the terms of the FreeType project      */
  /*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
  /*  this file you indicate that you have read the license and              */
  /*  understand and accept it fully.                                        */
  /*                                                                         */
  /***************************************************************************/
  
  
  #include <ft2build.h>
  #include FT_INTERNAL_DEBUG_H
  #include FT_INTERNAL_OBJECTS_H
  #include FT_SERVICE_POSTSCRIPT_CMAPS_H
  
  #include "psmodule.h"
  #include "pstables.h"
  
  #include "psnamerr.h"
  #include "pspic.h"
  
  
  #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
  
  
  #ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
  
  
  #define VARIANT_BIT         0x80000000UL
  #define BASE_GLYPH( code )  ( (FT_UInt32)( (code) & ~VARIANT_BIT ) )
  
  
    /* Return the Unicode value corresponding to a given glyph.  Note that */
    /* we do deal with glyph variants by detecting a non-initial dot in    */
    /* the name, as in `A.swash' or `e.final'; in this case, the           */
    /* VARIANT_BIT is set in the return value.                             */
    /*                                                                     */
    static FT_UInt32
    ps_unicode_value( const char*  glyph_name )
    {
      /* If the name begins with `uni', then the glyph name may be a */
      /* hard-coded unicode character code.                          */
      if ( glyph_name[0] == 'u' &&
           glyph_name[1] == 'n' &&
           glyph_name[2] == 'i' )
      {
        /* determine whether the next four characters following are */
        /* hexadecimal.                                             */
  
        /* XXX: Add code to deal with ligatures, i.e. glyph names like */
        /*      `uniXXXXYYYYZZZZ'...                                   */
  
        FT_Int       count;
        FT_UInt32    value = 0;
        const char*  p     = glyph_name + 3;
  
  
        for ( count = 4; count > 0; count--, p++ )
        {
          char          c = *p;
          unsigned int  d;
  
  
          d = (unsigned char)c - '0';
          if ( d >= 10 )
          {
            d = (unsigned char)c - 'A';
            if ( d >= 6 )
              d = 16;
            else
              d += 10;
          }
  
          /* Exit if a non-uppercase hexadecimal character was found   */
          /* -- this also catches character codes below `0' since such */
          /* negative numbers cast to `unsigned int' are far too big.  */
          if ( d >= 16 )
            break;
  
          value = ( value << 4 ) + d;
        }
  
        /* there must be exactly four hex digits */
        if ( count == 0 )
        {
          if ( *p == '\0' )
            return value;
          if ( *p == '.' )
            return (FT_UInt32)( value | VARIANT_BIT );
        }
      }
  
      /* If the name begins with `u', followed by four to six uppercase */
      /* hexadecimal digits, it is a hard-coded unicode character code. */
      if ( glyph_name[0] == 'u' )
      {
        FT_Int       count;
        FT_UInt32    value = 0;
        const char*  p     = glyph_name + 1;
  
  
        for ( count = 6; count > 0; count--, p++ )
        {
          char          c = *p;
          unsigned int  d;
  
  
          d = (unsigned char)c - '0';
          if ( d >= 10 )
          {
            d = (unsigned char)c - 'A';
            if ( d >= 6 )
              d = 16;
            else
              d += 10;
          }
  
          if ( d >= 16 )
            break;
  
          value = ( value << 4 ) + d;
        }
  
        if ( count <= 2 )
        {
          if ( *p == '\0' )
            return value;
          if ( *p == '.' )
            return (FT_UInt32)( value | VARIANT_BIT );
        }
      }
  
      /* Look for a non-initial dot in the glyph name in order to */
      /* find variants like `A.swash', `e.final', etc.            */
      {
        const char*  p   = glyph_name;
        const char*  dot = NULL;
  
  
        for ( ; *p; p++ )
        {
          if ( *p == '.' && p > glyph_name )
          {
            dot = p;
            break;
          }
        }
  
        /* now look up the glyph in the Adobe Glyph List */
        if ( !dot )
          return (FT_UInt32)ft_get_adobe_glyph_index( glyph_name, p );
        else
          return (FT_UInt32)( ft_get_adobe_glyph_index( glyph_name, dot ) |
                              VARIANT_BIT );
      }
    }
  
  
    /* ft_qsort callback to sort the unicode map */
    FT_CALLBACK_DEF( int )
    compare_uni_maps( const void*  a,
                      const void*  b )
    {
      PS_UniMap*  map1 = (PS_UniMap*)a;
      PS_UniMap*  map2 = (PS_UniMap*)b;
      FT_UInt32   unicode1 = BASE_GLYPH( map1->unicode );
      FT_UInt32   unicode2 = BASE_GLYPH( map2->unicode );
  
  
      /* sort base glyphs before glyph variants */
      if ( unicode1 == unicode2 )
      {
        if ( map1->unicode > map2->unicode )
          return 1;
        else if ( map1->unicode < map2->unicode )
          return -1;
        else
          return 0;
      }
      else
      {
        if ( unicode1 > unicode2 )
          return 1;
        else if ( unicode1 < unicode2 )
          return -1;
        else
          return 0;
      }
    }
  
  
    /* support for extra glyphs not handled (well) in AGL; */
    /* we add extra mappings for them if necessary         */
  
  #define EXTRA_GLYPH_LIST_SIZE  10
  
    static const FT_UInt32  ft_extra_glyph_unicodes[EXTRA_GLYPH_LIST_SIZE] =
    {
      /* WGL 4 */
      0x0394,
      0x03A9,
      0x2215,
      0x00AD,
      0x02C9,
      0x03BC,
      0x2219,
      0x00A0,
      /* Romanian */
      0x021A,
      0x021B
    };
  
    static const char  ft_extra_glyph_names[] =
    {
      'D','e','l','t','a',0,
      'O','m','e','g','a',0,
      'f','r','a','c','t','i','o','n',0,
      'h','y','p','h','e','n',0,
      'm','a','c','r','o','n',0,
      'm','u',0,
      'p','e','r','i','o','d','c','e','n','t','e','r','e','d',0,
      's','p','a','c','e',0,
      'T','c','o','m','m','a','a','c','c','e','n','t',0,
      't','c','o','m','m','a','a','c','c','e','n','t',0
    };
  
    static const FT_Int
    ft_extra_glyph_name_offsets[EXTRA_GLYPH_LIST_SIZE] =
    {
       0,
       6,
      12,
      21,
      28,
      35,
      38,
      53,
      59,
      72
    };
  
  
    static void
    ps_check_extra_glyph_name( const char*  gname,
                               FT_UInt      glyph,
                               FT_UInt*     extra_glyphs,
                               FT_UInt     *states )
    {
      FT_UInt  n;
  
  
      for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
      {
        if ( ft_strcmp( ft_extra_glyph_names +
                          ft_extra_glyph_name_offsets[n], gname ) == 0 )
        {
          if ( states[n] == 0 )
          {
            /* mark this extra glyph as a candidate for the cmap */
            states[n]     = 1;
            extra_glyphs[n] = glyph;
          }
  
          return;
        }
      }
    }
  
  
    static void
    ps_check_extra_glyph_unicode( FT_UInt32  uni_char,
                                  FT_UInt   *states )
    {
      FT_UInt  n;
  
  
      for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
      {
        if ( uni_char == ft_extra_glyph_unicodes[n] )
        {
          /* disable this extra glyph from being added to the cmap */
          states[n] = 2;
  
          return;
        }
      }
    }
  
  
    /* Build a table that maps Unicode values to glyph indices. */
    static FT_Error
    ps_unicodes_init( FT_Memory             memory,
                      PS_Unicodes           table,
                      FT_UInt               num_glyphs,
                      PS_GetGlyphNameFunc   get_glyph_name,
                      PS_FreeGlyphNameFunc  free_glyph_name,
                      FT_Pointer            glyph_data )
    {
      FT_Error  error;
  
      FT_UInt  extra_glyph_list_states[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
      FT_UInt  extra_glyphs[EXTRA_GLYPH_LIST_SIZE];
  
  
      /* we first allocate the table */
      table->num_maps = 0;
      table->maps     = NULL;
  
      if ( !FT_NEW_ARRAY( table->maps, num_glyphs + EXTRA_GLYPH_LIST_SIZE ) )
      {
        FT_UInt     n;
        FT_UInt     count;
        PS_UniMap*  map;
        FT_UInt32   uni_char;
  
  
        map = table->maps;
  
        for ( n = 0; n < num_glyphs; n++ )
        {
          const char*  gname = get_glyph_name( glyph_data, n );
  
  
          if ( gname )
          {
            ps_check_extra_glyph_name( gname, n,
                                       extra_glyphs, extra_glyph_list_states );
            uni_char = ps_unicode_value( gname );
  
            if ( BASE_GLYPH( uni_char ) != 0 )
            {
              ps_check_extra_glyph_unicode( uni_char,
                                            extra_glyph_list_states );
              map->unicode     = uni_char;
              map->glyph_index = n;
              map++;
            }
  
            if ( free_glyph_name )
              free_glyph_name( glyph_data, gname );
          }
        }
  
        for ( n = 0; n < EXTRA_GLYPH_LIST_SIZE; n++ )
        {
          if ( extra_glyph_list_states[n] == 1 )
          {
            /* This glyph name has an additional representation. */
            /* Add it to the cmap.                               */
  
            map->unicode     = ft_extra_glyph_unicodes[n];
            map->glyph_index = extra_glyphs[n];
            map++;
          }
        }
  
        /* now compress the table a bit */
        count = (FT_UInt)( map - table->maps );
  
        if ( count == 0 )
        {
          /* No unicode chars here! */
          FT_FREE( table->maps );
          if ( !error )
            error = FT_THROW( No_Unicode_Glyph_Name );
        }
        else
        {
          /* Reallocate if the number of used entries is much smaller. */
          if ( count < num_glyphs / 2 )
          {
            (void)FT_RENEW_ARRAY( table->maps, num_glyphs, count );
            error = FT_Err_Ok;
          }
  
          /* Sort the table in increasing order of unicode values, */
          /* taking care of glyph variants.                        */
          ft_qsort( table->maps, count, sizeof ( PS_UniMap ),
                    compare_uni_maps );
        }
  
        table->num_maps = count;
      }
  
      return error;
    }
  
  
    static FT_UInt
    ps_unicodes_char_index( PS_Unicodes  table,
                            FT_UInt32    unicode )
    {
      PS_UniMap  *min, *max, *mid, *result = NULL;
  
  
      /* Perform a binary search on the table. */
  
      min = table->maps;
      max = min + table->num_maps - 1;
  
      while ( min <= max )
      {
        FT_UInt32  base_glyph;
  
  
        mid = min + ( ( max - min ) >> 1 );
  
        if ( mid->unicode == unicode )
        {
          result = mid;
          break;
        }
  
        base_glyph = BASE_GLYPH( mid->unicode );
  
        if ( base_glyph == unicode )
          result = mid; /* remember match but continue search for base glyph */
  
        if ( min == max )
          break;
  
        if ( base_glyph < unicode )
          min = mid + 1;
        else
          max = mid - 1;
      }
  
      if ( result )
        return result->glyph_index;
      else
        return 0;
    }
  
  
    static FT_UInt32
    ps_unicodes_char_next( PS_Unicodes  table,
                           FT_UInt32   *unicode )
    {
      FT_UInt    result    = 0;
      FT_UInt32  char_code = *unicode + 1;
  
  
      {
        FT_UInt     min = 0;
        FT_UInt     max = table->num_maps;
        FT_UInt     mid;
        PS_UniMap*  map;
        FT_UInt32   base_glyph;
  
  
        while ( min < max )
        {
          mid = min + ( ( max - min ) >> 1 );
          map = table->maps + mid;
  
          if ( map->unicode == char_code )
          {
            result = map->glyph_index;
            goto Exit;
          }
  
          base_glyph = BASE_GLYPH( map->unicode );
  
          if ( base_glyph == char_code )
            result = map->glyph_index;
  
          if ( base_glyph < char_code )
            min = mid + 1;
          else
            max = mid;
        }
  
        if ( result )
          goto Exit;               /* we have a variant glyph */
  
        /* we didn't find it; check whether we have a map just above it */
        char_code = 0;
  
        if ( min < table->num_maps )
        {
          map       = table->maps + min;
          result    = map->glyph_index;
          char_code = BASE_GLYPH( map->unicode );
        }
      }
  
    Exit:
      *unicode = char_code;
      return result;
    }
  
  
  #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
  
  
    static const char*
    ps_get_macintosh_name( FT_UInt  name_index )
    {
      if ( name_index >= FT_NUM_MAC_NAMES )
        name_index = 0;
  
      return ft_standard_glyph_names + ft_mac_names[name_index];
    }
  
  
    static const char*
    ps_get_standard_strings( FT_UInt  sid )
    {
      if ( sid >= FT_NUM_SID_NAMES )
        return 0;
  
      return ft_standard_glyph_names + ft_sid_names[sid];
    }
  
  
  #ifdef FT_CONFIG_OPTION_ADOBE_GLYPH_LIST
  
    FT_DEFINE_SERVICE_PSCMAPSREC(
      pscmaps_interface,
      (PS_Unicode_ValueFunc)     ps_unicode_value,
      (PS_Unicodes_InitFunc)     ps_unicodes_init,
      (PS_Unicodes_CharIndexFunc)ps_unicodes_char_index,
      (PS_Unicodes_CharNextFunc) ps_unicodes_char_next,
  
      (PS_Macintosh_NameFunc)    ps_get_macintosh_name,
      (PS_Adobe_Std_StringsFunc) ps_get_standard_strings,
  
      t1_standard_encoding,
      t1_expert_encoding )
  
  #else
  
    FT_DEFINE_SERVICE_PSCMAPSREC(
      pscmaps_interface,
      NULL,
      NULL,
      NULL,
      NULL,
  
      (PS_Macintosh_NameFunc)    ps_get_macintosh_name,
      (PS_Adobe_Std_StringsFunc) ps_get_standard_strings,
  
      t1_standard_encoding,
      t1_expert_encoding )
  
  #endif /* FT_CONFIG_OPTION_ADOBE_GLYPH_LIST */
  
  
    FT_DEFINE_SERVICEDESCREC1(
      pscmaps_services,
      FT_SERVICE_ID_POSTSCRIPT_CMAPS, &PSCMAPS_INTERFACE_GET )
  
  
    static FT_Pointer
    psnames_get_service( FT_Module    module,
                         const char*  service_id )
    {
      /* PSCMAPS_SERVICES_GET dereferences `library' in PIC mode */
  #ifdef FT_CONFIG_OPTION_PIC
      FT_Library  library;
  
  
      if ( !module )
        return NULL;
      library = module->library;
      if ( !library )
        return NULL;
  #else
      FT_UNUSED( module );
  #endif
  
      return ft_service_list_lookup( PSCMAPS_SERVICES_GET, service_id );
    }
  
  #endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */
  
  
  #ifndef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
  #define PUT_PS_NAMES_SERVICE( a )  NULL
  #else
  #define PUT_PS_NAMES_SERVICE( a )  a
  #endif
  
    FT_DEFINE_MODULE(
      psnames_module_class,
  
      0,  /* this is not a font driver, nor a renderer */
      sizeof ( FT_ModuleRec ),
  
      "psnames",  /* driver name                         */
      0x10000L,   /* driver version                      */
      0x20000L,   /* driver requires FreeType 2 or above */
  
      PUT_PS_NAMES_SERVICE(
        (void*)&PSCMAPS_INTERFACE_GET ),   /* module specific interface */
      (FT_Module_Constructor)NULL,
      (FT_Module_Destructor) NULL,
      (FT_Module_Requester)  PUT_PS_NAMES_SERVICE( psnames_get_service ) )
  
  
  /* END */
  