📄 afmparse.c
字号:
/***************************************************************************//* *//* afmparse.c *//* *//* AFM parser (body). *//* *//* Copyright 2006 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_FREETYPE_H#include FT_INTERNAL_POSTSCRIPT_AUX_H#include FT_INTERNAL_DEBUG_H#include "afmparse.h"#include "psconv.h"#include "psauxerr.h"/***************************************************************************//* *//* AFM_Stream *//* *//* The use of AFM_Stream is largely inspired by parseAFM.[ch] from t1lib. *//* *//* */ enum { AFM_STREAM_STATUS_NORMAL, AFM_STREAM_STATUS_EOC, AFM_STREAM_STATUS_EOL, AFM_STREAM_STATUS_EOF }; typedef struct AFM_StreamRec_ { FT_Byte* cursor; FT_Byte* base; FT_Byte* limit; FT_Int status; } AFM_StreamRec;#ifndef EOF#define EOF -1#endif /* this works because empty lines are ignored */#define AFM_IS_NEWLINE( ch ) ( (ch) == '\r' || (ch) == '\n' )#define AFM_IS_EOF( ch ) ( (ch) == EOF || (ch) == '\x1a' )#define AFM_IS_SPACE( ch ) ( (ch) == ' ' || (ch) == '\t' ) /* column separator; there is no `column' in the spec actually */#define AFM_IS_SEP( ch ) ( (ch) == ';' )#define AFM_GETC() \ ( ( (stream)->cursor < (stream)->limit ) ? *(stream)->cursor++ \ : EOF )#define AFM_STREAM_KEY_BEGIN( stream ) \ (char*)( (stream)->cursor - 1 )#define AFM_STREAM_KEY_LEN( stream, key ) \ ( (char*)(stream)->cursor - key - 1 )#define AFM_STATUS_EOC( stream ) \ ( (stream)->status >= AFM_STREAM_STATUS_EOC )#define AFM_STATUS_EOL( stream ) \ ( (stream)->status >= AFM_STREAM_STATUS_EOL )#define AFM_STATUS_EOF( stream ) \ ( (stream)->status >= AFM_STREAM_STATUS_EOF ) static int afm_stream_skip_spaces( AFM_Stream stream ) { int ch = 0; /* make stupid compiler happy */ if ( AFM_STATUS_EOC( stream ) ) return ';'; while ( 1 ) { ch = AFM_GETC(); if ( !AFM_IS_SPACE( ch ) ) break; } if ( AFM_IS_NEWLINE( ch ) ) stream->status = AFM_STREAM_STATUS_EOL; else if ( AFM_IS_SEP( ch ) ) stream->status = AFM_STREAM_STATUS_EOC; else if ( AFM_IS_EOF( ch ) ) stream->status = AFM_STREAM_STATUS_EOF; return ch; } /* read a key or value in current column */ static char* afm_stream_read_one( AFM_Stream stream ) { char* str; int ch; afm_stream_skip_spaces( stream ); if ( AFM_STATUS_EOC( stream ) ) return NULL; str = AFM_STREAM_KEY_BEGIN( stream ); while ( 1 ) { ch = AFM_GETC(); if ( AFM_IS_SPACE( ch ) ) break; else if ( AFM_IS_NEWLINE( ch ) ) { stream->status = AFM_STREAM_STATUS_EOL; break; } else if ( AFM_IS_SEP( ch ) ) { stream->status = AFM_STREAM_STATUS_EOC; break; } else if ( AFM_IS_EOF( ch ) ) { stream->status = AFM_STREAM_STATUS_EOF; break; } } return str; } /* read a string (i.e., read to EOL) */ static char* afm_stream_read_string( AFM_Stream stream ) { char* str; int ch; afm_stream_skip_spaces( stream ); if ( AFM_STATUS_EOL( stream ) ) return NULL; str = AFM_STREAM_KEY_BEGIN( stream ); /* scan to eol */ while ( 1 ) { ch = AFM_GETC(); if ( AFM_IS_NEWLINE( ch ) ) { stream->status = AFM_STREAM_STATUS_EOL; break; } else if ( AFM_IS_EOF( ch ) ) { stream->status = AFM_STREAM_STATUS_EOF; break; } } return str; } /*************************************************************************/ /* */ /* AFM_Parser */ /* */ /* */ /* all keys defined in Ch. 7-10 of 5004.AFM_Spec.pdf */ typedef enum AFM_Token_ { AFM_TOKEN_ASCENDER, AFM_TOKEN_AXISLABEL, AFM_TOKEN_AXISTYPE, AFM_TOKEN_B, AFM_TOKEN_BLENDAXISTYPES, AFM_TOKEN_BLENDDESIGNMAP, AFM_TOKEN_BLENDDESIGNPOSITIONS, AFM_TOKEN_C, AFM_TOKEN_CC, AFM_TOKEN_CH, AFM_TOKEN_CAPHEIGHT, AFM_TOKEN_CHARWIDTH, AFM_TOKEN_CHARACTERSET, AFM_TOKEN_CHARACTERS, AFM_TOKEN_DESCENDER, AFM_TOKEN_ENCODINGSCHEME, AFM_TOKEN_ENDAXIS, AFM_TOKEN_ENDCHARMETRICS, AFM_TOKEN_ENDCOMPOSITES, AFM_TOKEN_ENDDIRECTION, AFM_TOKEN_ENDFONTMETRICS, AFM_TOKEN_ENDKERNDATA, AFM_TOKEN_ENDKERNPAIRS, AFM_TOKEN_ENDTRACKKERN, AFM_TOKEN_ESCCHAR, AFM_TOKEN_FAMILYNAME, AFM_TOKEN_FONTBBOX, AFM_TOKEN_FONTNAME, AFM_TOKEN_FULLNAME, AFM_TOKEN_ISBASEFONT, AFM_TOKEN_ISCIDFONT, AFM_TOKEN_ISFIXEDPITCH, AFM_TOKEN_ISFIXEDV, AFM_TOKEN_ITALICANGLE, AFM_TOKEN_KP, AFM_TOKEN_KPH, AFM_TOKEN_KPX, AFM_TOKEN_KPY, AFM_TOKEN_L, AFM_TOKEN_MAPPINGSCHEME, AFM_TOKEN_METRICSSETS, AFM_TOKEN_N, AFM_TOKEN_NOTICE, AFM_TOKEN_PCC, AFM_TOKEN_STARTAXIS, AFM_TOKEN_STARTCHARMETRICS, AFM_TOKEN_STARTCOMPOSITES, AFM_TOKEN_STARTDIRECTION, AFM_TOKEN_STARTFONTMETRICS, AFM_TOKEN_STARTKERNDATA, AFM_TOKEN_STARTKERNPAIRS, AFM_TOKEN_STARTKERNPAIRS0, AFM_TOKEN_STARTKERNPAIRS1, AFM_TOKEN_STARTTRACKKERN, AFM_TOKEN_STDHW, AFM_TOKEN_STDVW, AFM_TOKEN_TRACKKERN, AFM_TOKEN_UNDERLINEPOSITION, AFM_TOKEN_UNDERLINETHICKNESS, AFM_TOKEN_VV, AFM_TOKEN_VVECTOR, AFM_TOKEN_VERSION, AFM_TOKEN_W, AFM_TOKEN_W0, AFM_TOKEN_W0X, AFM_TOKEN_W0Y, AFM_TOKEN_W1, AFM_TOKEN_W1X, AFM_TOKEN_W1Y, AFM_TOKEN_WX, AFM_TOKEN_WY, AFM_TOKEN_WEIGHT, AFM_TOKEN_WEIGHTVECTOR, AFM_TOKEN_XHEIGHT, N_AFM_TOKENS, AFM_TOKEN_UNKNOWN } AFM_Token; static const char* const afm_key_table[N_AFM_TOKENS] = { "Ascender", "AxisLabel", "AxisType", "B", "BlendAxisTypes", "BlendDesignMap", "BlendDesignPositions", "C", "CC", "CH", "CapHeight", "CharWidth", "CharacterSet", "Characters", "Descender", "EncodingScheme", "EndAxis", "EndCharMetrics", "EndComposites", "EndDirection", "EndFontMetrics", "EndKernData", "EndKernPairs", "EndTrackKern", "EscChar", "FamilyName", "FontBBox", "FontName", "FullName", "IsBaseFont", "IsCIDFont", "IsFixedPitch", "IsFixedV", "ItalicAngle", "KP", "KPH", "KPX", "KPY", "L", "MappingScheme", "MetricsSets", "N", "Notice", "PCC", "StartAxis", "StartCharMetrics", "StartComposites", "StartDirection", "StartFontMetrics", "StartKernData", "StartKernPairs", "StartKernPairs0", "StartKernPairs1", "StartTrackKern", "StdHW", "StdVW", "TrackKern", "UnderlinePosition", "UnderlineThickness", "VV", "VVector", "Version", "W", "W0", "W0X", "W0Y", "W1", "W1X", "W1Y", "WX", "WY", "Weight", "WeightVector", "XHeight" }; /* * `afm_parser_read_vals' and `afm_parser_next_key' provide * high-level operations to an AFM_Stream. The rest of the * parser functions should use them without accessing the * AFM_Stream directly. */ FT_LOCAL_DEF( FT_Int ) afm_parser_read_vals( AFM_Parser parser, AFM_Value vals, FT_Int n ) { AFM_Stream stream = parser->stream; char* str; FT_Int i; if ( n > AFM_MAX_ARGUMENTS ) return 0; for ( i = 0; i < n; i++ ) { FT_UInt len; AFM_Value val = vals + i; if ( val->type == AFM_VALUE_TYPE_STRING ) str = afm_stream_read_string( stream ); else str = afm_stream_read_one( stream ); if ( !str ) break; len = AFM_STREAM_KEY_LEN( stream, str ); switch ( val->type ) { case AFM_VALUE_TYPE_STRING: case AFM_VALUE_TYPE_NAME: { FT_Memory memory = parser->memory; FT_Error error; if ( !FT_QALLOC( val->u.s, len + 1 ) ) { ft_memcpy( val->u.s, str, len ); val->u.s[len] = '\0'; } } break; case AFM_VALUE_TYPE_FIXED: val->u.f = PS_Conv_ToFixed( (FT_Byte**)(void*)&str, (FT_Byte*)str + len, 0 ); break; case AFM_VALUE_TYPE_INTEGER: val->u.i = PS_Conv_ToInt( (FT_Byte**)(void*)&str, (FT_Byte*)str + len ); break; case AFM_VALUE_TYPE_BOOL: val->u.b = FT_BOOL( len == 4 && !ft_strncmp( str, "true", 4 ) ); break; case AFM_VALUE_TYPE_INDEX: if ( parser->get_index ) val->u.i = parser->get_index( str, len, parser->user_data ); else val->u.i = 0; break; } } return i; } FT_LOCAL_DEF( char* ) afm_parser_next_key( AFM_Parser parser, FT_Bool line, FT_UInt* len ) { AFM_Stream stream = parser->stream; char* key = 0; /* make stupid compiler happy */ if ( line ) { while ( 1 ) { /* skip current line */ if ( !AFM_STATUS_EOL( stream ) ) afm_stream_read_string( stream ); stream->status = AFM_STREAM_STATUS_NORMAL; key = afm_stream_read_one( stream ); /* skip empty line */ if ( !key && !AFM_STATUS_EOF( stream ) && AFM_STATUS_EOL( stream ) ) continue; break; } } else { while ( 1 ) { /* skip current column */ while ( !AFM_STATUS_EOC( stream ) ) afm_stream_read_one( stream ); stream->status = AFM_STREAM_STATUS_NORMAL; key = afm_stream_read_one( stream ); /* skip empty column */ if ( !key && !AFM_STATUS_EOF( stream ) &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -