/***************************************************************************/ /* */ /* 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 #include #ifdef FT_FLAT_COMPILE #include "t1parse.h" #else #include #endif #include /* for sscanf() */ #include /* for strncpy() */ /*************************************************************************/ /* */ /* */ /* T1_New_Table */ /* */ /* */ /* Initializes a T1_Table structure. */ /* */ /* */ /* table :: The address of the target table. */ /* */ /* */ /* count :: The table size (i.e. maximum number of elements). */ /* memory :: The memory object to use for all subsequent */ /* reallocations. */ /* */ /* */ /* 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; } /*************************************************************************/ /* */ /* */ /* T1_Add_Table */ /* */ /* */ /* Adds an object to a T1_Table, possibly growing its memory block. */ /* */ /* */ /* table :: The target table. */ /* */ /* */ /* 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. */ /* */ /* */ /* 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; } /*************************************************************************/ /* */ /* */ /* T1_Done_Table */ /* */ /* */ /* Finalize a T1_Table (reallocate it to its current cursor). */ /* */ /* */ /* table :: The target table. */ /* */ /* */ /* 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 */