| #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; |
| } |
| |