--- /dev/null
+/***************************************************************************/
+/* */
+/* t1parse.c */
+/* */
+/* Type 1 parser (body). */
+/* */
+/* Copyright 1996-2000 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 <freetype/internal/ftdebug.h>
+#include <freetype/internal/t1types.h>
+
+
+#ifdef FT_FLAT_COMPILE
+
+#include "t1parse.h"
+
+#else
+
+#include <type1/t1parse.h>
+
+#endif
+
+
+#include <stdio.h> /* for sscanf() */
+#include <string.h> /* for strncpy() */
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_New_Table */
+ /* */
+ /* <Description> */
+ /* Initializes a T1_Table structure. */
+ /* */
+ /* <InOut> */
+ /* table :: The address of the target table. */
+ /* */
+ /* <Input> */
+ /* count :: The table size (i.e. maximum number of elements). */
+ /* memory :: The memory object to use for all subsequent */
+ /* reallocations. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. */
+ /* */
+ LOCAL_FUNC
+ FT_Error T1_New_Table( T1_Table* table,
+ FT_Int count,
+ FT_Memory memory )
+ {
+ FT_Error error;
+
+
+ table->memory = memory;
+
+ if ( ALLOC_ARRAY( table->elements, count, FT_Byte* ) )
+ return error;
+
+ if ( ALLOC_ARRAY( table->lengths, count, FT_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;
+ }
+
+
+ static
+ FT_Error reallocate_t1_table( T1_Table* table,
+ FT_Int new_size )
+ {
+ FT_Memory memory = table->memory;
+ FT_Byte* old_base = table->block;
+ FT_Error error;
+
+
+ /* reallocate the base block */
+ if ( REALLOC( table->block, table->capacity, new_size ) )
+ return error;
+ table->capacity = new_size;
+
+ /* shift all offsets if necessary */
+ if ( old_base )
+ {
+ FT_Long delta = table->block - old_base;
+ FT_Byte** offset = table->elements;
+ FT_Byte** limit = offset + table->max_elems;
+
+
+ if ( delta )
+ for ( ; offset < limit; offset ++ )
+ if (offset[0])
+ offset[0] += delta;
+ }
+
+ return T1_Err_Ok;
+ }
+
+
+ /*************************************************************************/
+ /* */
+ /* <Function> */
+ /* T1_Add_Table */
+ /* */
+ /* <Description> */
+ /* Adds an object to a T1_Table, possibly growing its memory block. */
+ /* */
+ /* <InOut> */
+ /* table :: The target table. */
+ /* */
+ /* <Input> */
+ /* index :: The index of the object in the table. */
+ /* */
+ /* object :: The address of the object to copy in memory. */
+ /* */
+ /* length :: The length in bytes of the source object. */
+ /* */
+ /* <Return> */
+ /* FreeType error code. 0 means success. An error is returned if a */
+ /* reallocation failed. */
+ /* */
+ LOCAL_FUNC
+ FT_Error T1_Add_Table( T1_Table* table,
+ FT_Int index,
+ void* object,
+ FT_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 )
+ {
+ FT_Error error;
+ FT_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> */
+ /* Finalize a T1_Table (reallocate it to its current cursor). */
+ /* */
+ /* <Input> */
+ /* table :: The 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;
+ FT_Error error;
+ FT_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 )
+ {
+ FT_Long delta = table->block - old_base;
+ FT_Byte** element = table->elements;
+ FT_Byte** limit = element + table->max_elems;
+
+
+ for ( ; element < limit; element++ )
+ if ( element[0] )
+ element[0] += delta;
+ }
+ }
+
+
+ LOCAL_FUNC
+ FT_String* CopyString( T1_Parser* parser )
+ {
+ FT_String* string = NULL;
+ T1_Token* token = parser->args++;
+ FT_Memory memory = parser->tokenizer->memory;
+ FT_Error error;
+
+
+ if ( token->kind == tok_string )
+ {
+ FT_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
+ FT_Error parse_int( FT_Byte* base,
+ FT_Byte* limit,
+ FT_Long* result )
+ {
+ FT_Bool sign = 0;
+ FT_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(( "parse_int: integer expected\n" ));
+ *result = 0;
+ return T1_Err_Syntax_Error;
+ }
+
+
+ static
+ FT_Error parse_float( FT_Byte* base,
+ FT_Byte* limit,
+ FT_Long scale,
+ FT_Long* result )
+ {
+#if 1
+
+ /* XXX: We are simply much too lazy to code this function */
+ /* properly for now. We will 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 = (FT_Long)( scale * value );
+ return 0;
+
+#else
+
+ FT_Byte* cur;
+ FT_Bool sign = 0; /* sign */
+ FT_Long number_int = 0; /* integer part */
+ FT_Long number_frac = 0; /* fractional part */
+ FT_Long exponent = 0; /* exponent value */
+ FT_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 )
+ {
+ FT_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 )
+ {
+ FT_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 */
+ /* XXX: incomplete! */
+
+#endif /* 1 */
+
+ Fail:
+ FT_ERROR(( "parse_float: syntax error!\n" ));
+ return T1_Err_Syntax_Error;
+ }
+
+
+ static
+ FT_Error parse_integer( FT_Byte* base,
+ FT_Byte* limit,
+ FT_Long* result )
+ {
+ FT_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 )
+ {
+ FT_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 */
+ {
+ FT_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
+ FT_Long CopyInteger( T1_Parser* parser )
+ {
+ FT_Long sum = 0;
+ T1_Token* token = parser->args++;
+
+
+ if ( token->kind == tok_number )
+ {
+ FT_Byte* base = parser->tokenizer->base + token->start;
+ FT_Byte* limit = base + token->len;
+
+
+ /* now read the number's value */
+ parser->error = parse_integer( base, limit, &sum );
+ return sum;
+ }
+
+ FT_ERROR(( "CopyInteger: number expected\n" ));
+ parser->args--;
+ parser->error = T1_Err_Syntax_Error;
+ return 0;
+ }
+
+
+ LOCAL_FUNC
+ FT_Bool CopyBoolean( T1_Parser* parser )
+ {
+ FT_Error error = T1_Err_Ok;
+ FT_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(( "CopyBoolean:" ));
+ FT_ERROR(( " syntax error; `false' or `true' expected\n" ));
+ error = T1_Err_Syntax_Error;
+ }
+ parser->error = error;
+ return result;
+ }
+
+
+ LOCAL_FUNC
+ FT_Long CopyFloat( T1_Parser* parser,
+ FT_Int scale )
+ {
+ FT_Error error;
+ FT_Long sum = 0;
+ T1_Token* token = parser->args++;
+
+
+ if ( token->kind == tok_number )
+ {
+ FT_Byte* base = parser->tokenizer->base + token->start;
+ FT_Byte* limit = base + token->len;
+
+
+ error = parser->error = parse_float( base, limit, scale, &sum );
+ if ( error )
+ goto Fail;
+
+ return sum;
+ }
+
+ Fail:
+ FT_ERROR(( "CopyFloat: syntax error!\n" ));
+ parser->error = T1_Err_Syntax_Error;
+ return 0;
+ }
+
+
+ LOCAL_FUNC
+ void CopyBBox( T1_Parser* parser,
+ FT_BBox* bbox )
+ {
+ T1_Token* token = parser->args++;
+ FT_Int n;
+ FT_Error error;
+
+
+ if ( token->kind == tok_program ||
+ token->kind == tok_array )
+ {
+ /* get rid of `['/`]', or `{'/`}' */
+ FT_Byte* base = parser->tokenizer->base + token->start + 1;
+ FT_Byte* limit = base + token->len - 2;
+ FT_Byte* cur;
+ FT_Byte* start;
+
+
+ /* read each parameter independently */
+ cur = base;
+ for ( n = 0; n < 4; n++ )
+ {
+ FT_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(( "CopyBBox: syntax error!\n" ));
+ parser->error = T1_Err_Syntax_Error;
+ }
+
+
+ LOCAL_FUNC
+ void CopyMatrix( T1_Parser* parser,
+ FT_Matrix* matrix )
+ {
+ T1_Token* token = parser->args++;
+ FT_Error error;
+
+
+ if ( token->kind == tok_array )
+ {
+ /* get rid of `[' and `]' */
+ FT_Byte* base = parser->tokenizer->base + token->start + 1;
+ FT_Byte* limit = base + token->len - 2;
+ FT_Byte* cur;
+ FT_Byte* start;
+ FT_Int n;
+
+
+ /* read each parameter independently */
+ cur = base;
+ for ( n = 0; n < 4; n++ )
+ {
+ FT_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->yx;
+ break;
+ case 2:
+ result = &matrix->xy;
+ break;
+ default:
+ result = &matrix->yy;
+ }
+
+ error = parse_float( start, cur, 65536000L, result );
+ if ( error )
+ goto Fail;
+ }
+ parser->error = 0;
+ return;
+ }
+
+ Fail:
+ FT_ERROR(( "CopyMatrix: syntax error!\n" ));
+ parser->error = T1_Err_Syntax_Error;
+ }
+
+
+ LOCAL_FUNC
+ void CopyArray( T1_Parser* parser,
+ FT_Byte* num_elements,
+ FT_Short* elements,
+ FT_Int max_elements )
+ {
+ T1_Token* token = parser->args++;
+ FT_Error error;
+
+
+ if ( token->kind == tok_array ||
+ token->kind == tok_program ) /* in the case of MinFeature */
+ {
+ /* get rid of `['/`]', or `{'/`}' */
+ FT_Byte* base = parser->tokenizer->base + token->start + 1;
+ FT_Byte* limit = base + token->len - 2;
+ FT_Byte* cur;
+ FT_Byte* start;
+ FT_Int n;
+
+
+ /* read each parameter independently */
+ cur = base;
+ for ( n = 0; n < max_elements; n++ )
+ {
+ FT_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++ = (FT_Short)result;
+ }
+
+ if ( num_elements )
+ *num_elements = (FT_Byte)n;
+
+ parser->error = 0;
+ return;
+ }
+
+ Fail:
+ FT_ERROR(( "CopyArray: syntax error!\n" ));
+ parser->error = T1_Err_Syntax_Error;
+ }
+
+
+/* END */