shithub: freetype+ttf2subf

ref: 5ae1259c038d35255fb0331f3a413681df550ba2
dir: /src/type1/t1parse.c/

View raw version
#include <ftdebug.h>
#include <t1types.h>
#include <t1parse.h>

#include <stdio.h>  /* for sscanf */

/*************************************************************************/
/*                                                                       */
/* <Function> T1_New_Table                                               */
/*                                                                       */
/* <Description>                                                         */
/*    Initialise a T1_Table.                                             */
/*                                                                       */
/* <Input>                                                               */
/*    table  :: address of target table                                  */
/*    count  :: table size = maximum number of elements                  */
/*    memory :: memory object to use for all subsequent reallocations    */
/*                                                                       */
/* <Return>                                                              */
/*    Error code. 0 means success                                        */
/*                                                                       */

  LOCAL_FUNC
  T1_Error  T1_New_Table( T1_Table*  table,
                          T1_Int     count,
                          FT_Memory  memory )
  {
	 T1_Error  error;

	 table->memory = memory;
	 if ( ALLOC_ARRAY( table->elements, count, T1_Byte* ) )
		 return error;

	 if ( ALLOC_ARRAY( table->lengths, count, T1_Byte* ) )
	 {
	   FREE( table->elements );
	   return error;
	}

	table->max_elems = count;
	table->num_elems = 0;

	table->block        = 0;
	table->capacity     = 0;
	table->cursor       = 0;

	return error;
  }



/*************************************************************************/
/*                                                                       */
/* <Function> T1_Add_Table                                               */
/*                                                                       */
/* <Description>                                                         */
/*    Adds an object to a T1_Table, possibly growing its memory block    */
/*                                                                       */
/* <Input>                                                               */
/*    table  :: target table                                             */
/*    index  :: index of object in table                                 */
/*    object :: address of object to copy in memory                      */
/*    length :: length in bytes of source object                         */
/*                                                                       */
/* <Return>                                                              */
/*    Error code. 0 means success. An error is returned when a           */
/*    realloc failed..                                                   */
/*                                                                       */

      static
      T1_Error  reallocate_t1_table( T1_Table*  table,
                                     T1_Int     new_size )
      {
        FT_Memory  memory   = table->memory;
        T1_Byte*   old_base = table->block;
        T1_Error   error;

        /* realloc the base block */
        if ( REALLOC( table->block, table->capacity, new_size ) )
          return error;
        table->capacity = new_size;

        /* shift all offsets when needed */
        if (old_base)
        {
          T1_Long   delta  = table->block - old_base;
          T1_Byte** offset = table->elements;
          T1_Byte** limit  = offset + table->max_elems;

          if (delta)
            for ( ; offset < limit; offset ++ )
              if (offset[0])
                offset[0] += delta;
        }

        return T1_Err_Ok;
      }


  LOCAL_FUNC
  T1_Error  T1_Add_Table( T1_Table*  table,
                          T1_Int     index,
                          void*      object,
                          T1_Int     length )
  {
	if (index < 0 || index > table->max_elems)
    {
	  FT_ERROR(( "T1.Add_Table: invalid index\n" ));
	  return T1_Err_Syntax_Error;
    }

    /* grow the base block if needed */
    if ( table->cursor + length > table->capacity )
    {
      T1_Error  error;
      T1_Int    new_size = table->capacity;

      while ( new_size < table->cursor+length )
        new_size += 1024;

      error = reallocate_t1_table( table, new_size );
      if (error) return error;
    }

    /* add the object to the base block and adjust offset */
    table->elements[ index ] = table->block + table->cursor;
    table->lengths [ index ] = length;
    MEM_Copy( table->block + table->cursor, object, length );

    table->cursor += length;
    return T1_Err_Ok;
  }


/*************************************************************************/
/*                                                                       */
/* <Function> T1_Done_Table                                              */
/*                                                                       */
/* <Description>                                                         */
/*    Finalise a T1_Table. (realloc it to its current cursor).           */
/*                                                                       */
/* <Input>                                                               */
/*    table :: target table                                              */
/*                                                                       */
/* <Note>                                                                */
/*    This function does NOT release the heap's memory block. It is up   */
/*    to the caller to clean it, or reference it in its own structures.  */
/*                                                                       */
  LOCAL_FUNC
  void  T1_Done_Table( T1_Table*  table )
  {
    FT_Memory  memory = table->memory;
    T1_Error   error;
    T1_Byte*   old_base;

    /* should never fail, as rec.cursor <= rec.size */
    old_base = table->block;
    if (!old_base)
      return;
    
    (void)REALLOC( table->block, table->capacity, table->cursor );
    table->capacity = table->cursor;
    
    if (old_base != table->block)
    {
      T1_Long   delta   = table->block - old_base;
      T1_Byte** element = table->elements;
      T1_Byte** limit   = element + table->max_elems;
      
      for ( ; element < limit; element++ )
        if (element[0])
          element[0] += delta;
    }
  }


  LOCAL_FUNC
  T1_String*   CopyString( T1_Parser*  parser )
  {
    T1_String*  string = NULL;
    T1_Token*   token  = parser->args++;
    FT_Memory   memory = parser->tokenizer->memory;
    T1_Error    error;

    if ( token->kind == tok_string )
    {
      int  len = token->len-2;

      if ( ALLOC( string, len+1 ) )
      {
        parser->error = error;
        return 0;
      }

      MEM_Copy( string, parser->tokenizer->base + token->start+1, len );
      string[len] = '\0';

      parser->error = T1_Err_Ok;
    }
    else
    {
      FT_ERROR(( "T1.CopyString : syntax error, string token expected !\n" ));
      parser->error = T1_Err_Syntax_Error;
    }
    return string;
  }



  static
  T1_Error  parse_int( T1_Byte*  base,
                       T1_Byte*  limit,
                       T1_Long*  result )
  {
    T1_Bool  sign = 0;
    T1_Long  sum  = 0;

    if (base >= limit)
      goto Fail;

    /* check sign */
    if ( *base == '+' )
      base++;

    else if ( *base == '-' )
    {
      sign++;
      base++;
    }

    /* parse digits */
    if ( base >= limit )
      goto Fail;

    do
    {
      sum = ( 10*sum + (*base++ - '0') );

    } while (base < limit);

    if (sign)
      sum = -sum;

    *result = sum;
    return T1_Err_Ok;

  Fail:
    FT_ERROR(( "T1.parse_integer : integer expected\n" ));
    *result = 0;
    return T1_Err_Syntax_Error;
  }




  static
  T1_Error  parse_float( T1_Byte*  base,
                         T1_Byte*  limit,
                         T1_Int    scale,
                         T1_Long*  result )
  {
#if 1
    /* XXX : We're simply much too lazy to code this function  */
    /*       properly for now.. We'll do that when the rest of */
    /*       the driver works properly..                       */
    char    temp[32];
    int     len = limit-base;
    double  value;

    if (len > 31) goto Fail;

    strncpy( temp, (char*)base, len );
    temp[len] = '\0';
    if ( sscanf( temp, "%lf", &value ) != 1 )
      goto Fail;

    *result = (T1_Long)(scale*value);
    return 0;

#else
  T1_Byte*  cur;
  T1_Bool   sign        = 0;  /* sign                        */
  T1_Long   number_int  = 0;  /* integer part                */
  T1_Long   number_frac = 0;  /* fractional part             */
  T1_Long   exponent    = 0;  /* exponent value              */
  T1_Int    num_frac    = 0;  /* number of fractional digits */

  /* check sign */
  if (*base == '+')
    base++;

  else if (*base == '-')
  {
    sign++;
    base++;
  }

  /* find integer part */
  cur = base;
  while ( cur < limit )
  {
    T1_Byte  c = *cur;
    if ( c == '.' || c == 'e' || c == 'E' )
      break;

    cur++;
  }

  if ( cur > base )
  {
    error = parse_integer( base, cur, &number_int );
    if (error) goto Fail;
  }

  /* read fractional part, if any */
  if ( *cur == '.' )
  {
    cur++;
    base = cur;
    while ( cur < limit )
    {
      T1_Byte  c = *cur;
      if ( c == 'e' || c == 'E' )
        break;
      cur++;
    }

    num_frac = cur - base;

    if ( cur > base )
    {
      error = parse_integer( base, cur, &number_frac );
      if (error) goto Fail;
      base = cur;
    }
  }

  /* read exponent, if any */
  if ( *cur == 'e' || *cur == 'E' )
  {
    cur++;
    base = cur;
    error = parse_integer( base, limit, &exponent );
    if (error) goto Fail;

    /* now check that exponent is within 'correct bounds' */
    /* i.e. between -6 and 6                              */
    if ( exponent < -6 || exponent > 6 )
      goto Fail;
  }

  /* now adjust integer value and exponent for fractional part */
  while ( num_frac > 0 )
  {
    number_int *= 10;
    exponent   --;
    num_frac--;
  }

  number_int += num_frac;

  /* skip point if any, read fractional part */
  if ( cur+1 < limit )
  {
    if (*cur
  }

  /* now compute scaled float value */
  /* XXXXX : incomplete !!!         */
#endif

  Fail:
    FT_ERROR(( "T1.parse_float : syntax error !\n" ));
    return T1_Err_Syntax_Error;
  }



  static
  T1_Error  parse_integer( T1_Byte*  base,
                           T1_Byte*  limit,
                           T1_Long*  result )
  {
    T1_Byte*  cur;

    /* the lexical analyser accepts floats as well as integers */
    /* now, check that we really have an int in this token     */
    cur = base;
    while ( cur < limit )
    {
      T1_Byte  c = *cur++;

      if ( c == '.' || c == 'e' || c == 'E' )
        goto Float_Number;
    }

    /* now read the number's value */
    return parse_int( base, limit, result );

  Float_Number:
    /* We really have a float there, simply call parse_float in this */
    /* case with a scale of '10' to perform round..                */
    {
      T1_Error error;

      error = parse_float( base, limit, 10, result );
      if (!error)
      {
        if (*result >= 0) *result = (*result+5)/10;      /* round value */
                    else  *result = -((5-*result)/10);
      }
      return error;
    }
  }


  LOCAL_FUNC
  T1_Long  CopyInteger( T1_Parser*  parser )
  {
    T1_Long   sum   = 0;
    T1_Token* token = parser->args++;

    if ( token->kind == tok_number )
    {
      T1_Byte*  base  = parser->tokenizer->base + token->start;
      T1_Byte*  limit = base + token->len;

      /* now read the number's value */
      parser->error = parse_integer( base, limit, &sum );
      return sum;
    }

    FT_ERROR(( "T1.CopyInteger : number expected\n" ));
    parser->args--;
    parser->error = T1_Err_Syntax_Error;
    return 0;
  }



  LOCAL_FUNC
  T1_Bool   CopyBoolean( T1_Parser*  parser )
  {
    T1_Error  error  = T1_Err_Ok;
    T1_Bool   result = 0;
    T1_Token* token  = parser->args++;

    if ( token->kind == tok_keyword )
    {
      if ( token->kind2 == key_false )
        result = 0;

      else if ( token->kind2 == key_true )
        result = !0;

      else
        goto Fail;
    }
    else
    {
      Fail:
        FT_ERROR(( "T1.CopyBoolean : syntax error, 'false' or 'true' expected\n" ));
        error = T1_Err_Syntax_Error;
    }
    parser->error = error;
    return result;
  }




  LOCAL_FUNC
  T1_Long   CopyFloat( T1_Parser*  parser,
                       T1_Int      scale )
  {
    T1_Error  error;
    T1_Long   sum = 0;
    T1_Token* token = parser->args++;

    if ( token->kind == tok_number )
    {
      T1_Byte*  base  = parser->tokenizer->base + token->start;
      T1_Byte*  limit = base + token->len;

      error = parser->error = parse_float( base, limit, scale, &sum );
      if (error) goto Fail;

      return sum;
    }

  Fail:
    FT_ERROR(( "T1.CopyFloat : syntax error !\n" ));
    parser->error = T1_Err_Syntax_Error;
    return 0;
  }






  LOCAL_FUNC
  void  CopyBBox( T1_Parser*  parser,
                  T1_BBox*    bbox )
  {
    T1_Token* token = parser->args++;
    T1_Int    n;
    T1_Error  error;

    if ( token->kind == tok_program ||
         token->kind == tok_array   )
    {
      /* get rid of '['/']', or '{'/'}' */
      T1_Byte*  base  = parser->tokenizer->base + token->start + 1;
      T1_Byte*  limit = base + token->len - 1;
      T1_Byte*  cur;
      T1_Byte*  start;

      /* read each parameter independently */
      cur = base;
      for ( n = 0; n < 4; n++ )
      {
        T1_Long*  result;

        /* skip whitespace */
        while (cur < limit && *cur == ' ') cur++;

        /* skip numbers */
        start = cur;
        while (cur < limit && *cur != ' ') cur++;

        /* compute result address */
        switch (n)
        {
          case 0 : result = &bbox->xMin; break;
          case 1 : result = &bbox->yMin; break;
          case 2 : result = &bbox->xMax; break;
          default: result = &bbox->yMax;
        }

        error = parse_integer( start, cur, result );
        if (error) goto Fail;
      }
      parser->error = 0;
      return;
    }

  Fail:
    FT_ERROR(( "T1.CopyBBox : syntax error !\n" ));
    parser->error = T1_Err_Syntax_Error;
  }




  LOCAL_FUNC
  void  CopyMatrix( T1_Parser*  parser,
                    T1_Matrix*  matrix )
  {
    T1_Token* token = parser->args++;
    T1_Error  error;

    if ( token->kind == tok_array )
    {
      /* get rid of '[' and ']' */
      T1_Byte*  base  = parser->tokenizer->base + token->start + 1;
      T1_Byte*  limit = base + token->len - 1;
      T1_Byte*  cur;
      T1_Byte*  start;
      T1_Int    n;

      /* read each parameter independently */
      cur = base;
      for ( n = 0; n < 4; n++ )
      {
        T1_Long*  result;

        /* skip whitespace */
        while (cur < limit && *cur == ' ') cur++;

        /* skip numbers */
        start = cur;
        while (cur < limit && *cur != ' ') cur++;

        /* compute result address */
        switch (n)
        {
          case 0 : result = &matrix->xx; break;
          case 1 : result = &matrix->xy; break;
          case 2 : result = &matrix->yx; break;
          default: result = &matrix->yy;
        }

        error = parse_float( start, cur, 65536000, result );
        if (error) goto Fail;
      }
      parser->error = 0;
      return;
    }

  Fail:
    FT_ERROR(( "T1.CopyMatrix : syntax error !\n" ));
    parser->error = T1_Err_Syntax_Error;
  }



  LOCAL_FUNC
  void  CopyArray( T1_Parser*  parser,
                   T1_Byte*    num_elements,
                   T1_Short*   elements,
                   T1_Int      max_elements )
  {
    T1_Token* token = parser->args++;
    T1_Error  error;

    if ( token->kind == tok_array   ||
         token->kind == tok_program )   /* in the case of MinFeature */
    {
      /* get rid of '['/']', or '{'/'}' */
      T1_Byte*  base  = parser->tokenizer->base + token->start + 1;
      T1_Byte*  limit = base + token->len - 2;
      T1_Byte*  cur;
      T1_Byte*  start;
      T1_Int    n;

      /* read each parameter independently */
      cur = base;
      for ( n = 0; n < max_elements; n++ )
      {
        T1_Long  result;

        /* test end of string */
        if (cur >= limit)
          break;

        /* skip whitespace */
        while (cur < limit && *cur == ' ') cur++;

        /* end of list ? */
        if (cur >= limit)
          break;

        /* skip numbers */
        start = cur;
        while (cur < limit && *cur != ' ') cur++;

        error = parse_integer( start, cur, &result );
        if (error) goto Fail;

        *elements ++ = (T1_Short)result;
      }

      if (num_elements)
        *num_elements = (T1_Byte)n;

      parser->error = 0;
      return;
    }

  Fail:
    FT_ERROR(( "T1.CopyArray : syntax error !\n" ));
    parser->error = T1_Err_Syntax_Error;
  }