shithub: freetype+ttf2subf

ref: dcb8b7103fc8692cce093247188249fb786de2ff
dir: /src/sfnt/ttbdf.c/

View raw version
/***************************************************************************/
/*                                                                         */
/*  ttbdf.c                                                                */
/*                                                                         */
/*    TrueType and OpenType embedded BDF properties (body).                */
/*                                                                         */
/*  Copyright 2005 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_STREAM_H
#include FT_TRUETYPE_TAGS_H
#include "ttbdf.h"

#include "sferrors.h"

#ifdef TT_CONFIG_OPTION_BDF

  /*************************************************************************/
  /*                                                                       */
  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  /* messages during execution.                                            */
  /*                                                                       */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_ttbdf

FT_LOCAL_DEF( void )
tt_face_free_bdf_props( TT_Face  face )
{
  TT_BDF   bdf = &face->bdf;

  if ( bdf->loaded )
  {
    FT_Stream  stream = FT_FACE(face)->stream;

    if ( bdf->table != NULL )
      FT_FRAME_RELEASE( bdf->table );

    bdf->table_end    = NULL;
    bdf->strings      = NULL;
    bdf->strings_size = 0;
  }
}


static FT_Error
tt_face_load_bdf_props( TT_Face    face,
                        FT_Stream  stream )
{
  TT_BDF    bdf = &face->bdf;
  FT_ULong  length;
  FT_Error  error;

  FT_ZERO( bdf );

  error = tt_face_goto_table( face, TTAG_BDF, stream, &length );
  if ( error                                  ||
       length < 8                             ||
       FT_FRAME_EXTRACT( length, bdf->table ) )
  {
    error = FT_Err_Invalid_Table;
    goto Exit;
  }

  bdf->table_end = bdf->table + length;

  {
    FT_Byte*  p           = bdf->table;
    FT_UInt   version     = FT_NEXT_USHORT(p);
    FT_UInt   num_strikes = FT_NEXT_USHORT(p);
    FT_UInt32 strings     = FT_NEXT_ULONG(p);

    if ( version != 0x0001           ||
         strings < 8                 ||
         (strings-8)/4 < num_strikes ||
         strings+1 > length          )
    {
    BadTable:
      FT_FRAME_RELEASE( bdf->table );
      FT_ZERO( bdf );
      error = FT_Err_Invalid_Table;
      goto Exit;
    }

    bdf->num_strikes  = num_strikes;
    bdf->strings      = bdf->table + strings;
    bdf->strings_size = length - strings;
  }

 /* check the strike descriptors
  */
  {
    FT_UInt   count  = bdf->num_strikes;
    FT_Byte*  p      = bdf->table + 8;
    FT_Byte*  strike = p + count*4;

    for ( ; count > 0; count-- )
    {
      FT_UInt  num_items = FT_PEEK_USHORT(p+2);

     /* we don't need to check the value sets themselves, since this
      * is done later
      */
      strike += 10*num_items;

      p += 4;
    }

    if ( strike > bdf->strings )
      goto BadTable;
  }

  bdf->loaded = 1;

Exit:
  return error;
}


FT_LOCAL_DEF( FT_Error )
tt_face_find_bdf_prop( TT_Face           face,
                       const char*       property_name,
                       BDF_PropertyRec  *aprop )
{
  TT_BDF    bdf   = &face->bdf;
  FT_Size   size  = FT_FACE(face)->size;
  FT_Error  error = 0;
  FT_Byte*  p;
  FT_UInt   count;
  FT_Byte*  strike;
  FT_UInt   property_len;

  aprop->type = BDF_PROPERTY_TYPE_NONE;

  if ( bdf->loaded == 0 )
  {
    error = tt_face_load_bdf_props( face, FT_FACE(face)->stream );
    if ( error )
      goto Exit;
  }

  count  = bdf->num_strikes;
  p      = bdf->table + 8;
  strike = p + 4*count;

  error = FT_Err_Invalid_Argument;

  if ( size == NULL || property_name == NULL )
    goto Exit;

  property_len = ft_strlen( property_name );
  if ( property_len == 0 )
    goto Exit;

  for ( ; count > 0; count-- )
  {
    FT_UInt   _ppem  = FT_NEXT_USHORT(p);
    FT_UInt   _count = FT_NEXT_USHORT(p);

    if ( _ppem == size->metrics.y_ppem )
    {
      count = _count;
      goto FoundStrike;
    }

    strike += 10*_count;
  }
  goto Exit;

FoundStrike:
  p = strike;
  for ( ; count > 0; count-- )
  {
    FT_UInt   type = FT_PEEK_USHORT(p+4);

    if ( (type & 0x10) != 0 )
    {
      FT_UInt32  name_offset = FT_PEEK_ULONG(p);
      FT_UInt32  value       = FT_PEEK_ULONG(p+6);

      /* be a bit paranoid for invalid entries here */
      if ( name_offset < bdf->strings_size                        &&
           property_len < bdf->strings_size - name_offset         &&
           ft_strncmp( property_name, (const char*)bdf->strings + name_offset,
                       bdf->strings_size - name_offset ) == 0     )
      {
        switch ( type & 0x0F )
        {
          case 0x00:  /* string */
          case 0x01:  /* atoms */
            /* check that the content is really 0-terminated */
            if ( value < bdf->strings_size &&
                 ft_memchr( bdf->strings + value, 0, bdf->strings_size ) )
            {
              aprop->type   = BDF_PROPERTY_TYPE_ATOM;
              aprop->u.atom = (const char*) bdf->strings + value;
              error         = 0;
              goto Exit;
            }
            break;

          case 0x02:
            aprop->type      = BDF_PROPERTY_TYPE_INTEGER;
            aprop->u.integer = (FT_Int32)value;
            error            = 0;
            goto Exit;

          case 0x03:
            aprop->type       = BDF_PROPERTY_TYPE_CARDINAL;
            aprop->u.cardinal = value;
            error             = 0;
            goto Exit;

          default:
            ;
        }
      }
    }
    p += 10;
  }

Exit:
  return error;
}

#endif /* TT_CONFIG_OPTION_BDF */