Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenbdflib.c
Go to the documentation of this file.
00001 /* 00002 * Copyright 2000 Computing Research Labs, New Mexico State University 00003 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 00004 * Francesco Zappa Nardelli 00005 * 00006 * Permission is hereby granted, free of charge, to any person obtaining a 00007 * copy of this software and associated documentation files (the "Software"), 00008 * to deal in the Software without restriction, including without limitation 00009 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00010 * and/or sell copies of the Software, and to permit persons to whom the 00011 * Software is furnished to do so, subject to the following conditions: 00012 * 00013 * The above copyright notice and this permission notice shall be included in 00014 * all copies or substantial portions of the Software. 00015 * 00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00019 * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY 00020 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT 00021 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR 00022 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00023 */ 00024 00025 /*************************************************************************/ 00026 /* */ 00027 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */ 00028 /* */ 00029 /* taken from Mark Leisher's xmbdfed package */ 00030 /* */ 00031 /*************************************************************************/ 00032 00033 00034 #include <ft2build.h> 00035 00036 #include FT_FREETYPE_H 00037 #include FT_INTERNAL_DEBUG_H 00038 #include FT_INTERNAL_STREAM_H 00039 #include FT_INTERNAL_OBJECTS_H 00040 00041 #include "bdf.h" 00042 #include "bdferror.h" 00043 00044 00045 /*************************************************************************/ 00046 /* */ 00047 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 00048 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 00049 /* messages during execution. */ 00050 /* */ 00051 #undef FT_COMPONENT 00052 #define FT_COMPONENT trace_bdflib 00053 00054 00055 /*************************************************************************/ 00056 /* */ 00057 /* Default BDF font options. */ 00058 /* */ 00059 /*************************************************************************/ 00060 00061 00062 static const bdf_options_t _bdf_opts = 00063 { 00064 1, /* Correct metrics. */ 00065 1, /* Preserve unencoded glyphs. */ 00066 0, /* Preserve comments. */ 00067 BDF_PROPORTIONAL /* Default spacing. */ 00068 }; 00069 00070 00071 /*************************************************************************/ 00072 /* */ 00073 /* Builtin BDF font properties. */ 00074 /* */ 00075 /*************************************************************************/ 00076 00077 /* List of most properties that might appear in a font. Doesn't include */ 00078 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */ 00079 00080 static const bdf_property_t _bdf_properties[] = 00081 { 00082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } }, 00083 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, 00084 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, 00085 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, 00086 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, 00087 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } }, 00088 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } }, 00089 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } }, 00090 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } }, 00091 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } }, 00092 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } }, 00093 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } }, 00094 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } }, 00095 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } }, 00096 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } }, 00097 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } }, 00098 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, 00099 { (char *)"FONT", BDF_ATOM, 1, { 0 } }, 00100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } }, 00101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } }, 00102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } }, 00103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } }, 00104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } }, 00105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } }, 00106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } }, 00107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } }, 00108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } }, 00109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } }, 00110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, 00111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } }, 00112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, 00113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } }, 00114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } }, 00115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } }, 00116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } }, 00117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } }, 00118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } }, 00119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } }, 00120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } }, 00121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } }, 00122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } }, 00123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } }, 00124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } }, 00125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } }, 00126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } }, 00127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } }, 00128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } }, 00129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, 00130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, 00131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, 00132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 00133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 00134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 00135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 00136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 00137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 00138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, 00139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, 00140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } }, 00141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } }, 00142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } }, 00143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } }, 00144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } }, 00145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } }, 00146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } }, 00147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } }, 00148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } }, 00149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } }, 00150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } }, 00151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } }, 00152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 00153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 00154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 00155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } }, 00156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } }, 00157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } }, 00158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } }, 00159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } }, 00160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } }, 00161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } }, 00162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } }, 00163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } }, 00164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } }, 00165 }; 00166 00167 static const unsigned long 00168 _num_bdf_properties = sizeof ( _bdf_properties ) / 00169 sizeof ( _bdf_properties[0] ); 00170 00171 00172 /*************************************************************************/ 00173 /* */ 00174 /* Hash table utilities for the properties. */ 00175 /* */ 00176 /*************************************************************************/ 00177 00178 /* XXX: Replace this with FreeType's hash functions */ 00179 00180 00181 #define INITIAL_HT_SIZE 241 00182 00183 typedef void 00184 (*hash_free_func)( hashnode node ); 00185 00186 static hashnode* 00187 hash_bucket( const char* key, 00188 hashtable* ht ) 00189 { 00190 const char* kp = key; 00191 unsigned long res = 0; 00192 hashnode* bp = ht->table, *ndp; 00193 00194 00195 /* Mocklisp hash function. */ 00196 while ( *kp ) 00197 res = ( res << 5 ) - res + *kp++; 00198 00199 ndp = bp + ( res % ht->size ); 00200 while ( *ndp ) 00201 { 00202 kp = (*ndp)->key; 00203 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 ) 00204 break; 00205 ndp--; 00206 if ( ndp < bp ) 00207 ndp = bp + ( ht->size - 1 ); 00208 } 00209 00210 return ndp; 00211 } 00212 00213 00214 static FT_Error 00215 hash_rehash( hashtable* ht, 00216 FT_Memory memory ) 00217 { 00218 hashnode* obp = ht->table, *bp, *nbp; 00219 int i, sz = ht->size; 00220 FT_Error error = BDF_Err_Ok; 00221 00222 00223 ht->size <<= 1; 00224 ht->limit = ht->size / 3; 00225 00226 if ( FT_NEW_ARRAY( ht->table, ht->size ) ) 00227 goto Exit; 00228 00229 for ( i = 0, bp = obp; i < sz; i++, bp++ ) 00230 { 00231 if ( *bp ) 00232 { 00233 nbp = hash_bucket( (*bp)->key, ht ); 00234 *nbp = *bp; 00235 } 00236 } 00237 FT_FREE( obp ); 00238 00239 Exit: 00240 return error; 00241 } 00242 00243 00244 static FT_Error 00245 hash_init( hashtable* ht, 00246 FT_Memory memory ) 00247 { 00248 int sz = INITIAL_HT_SIZE; 00249 FT_Error error = BDF_Err_Ok; 00250 00251 00252 ht->size = sz; 00253 ht->limit = sz / 3; 00254 ht->used = 0; 00255 00256 if ( FT_NEW_ARRAY( ht->table, sz ) ) 00257 goto Exit; 00258 00259 Exit: 00260 return error; 00261 } 00262 00263 00264 static void 00265 hash_free( hashtable* ht, 00266 FT_Memory memory ) 00267 { 00268 if ( ht != 0 ) 00269 { 00270 int i, sz = ht->size; 00271 hashnode* bp = ht->table; 00272 00273 00274 for ( i = 0; i < sz; i++, bp++ ) 00275 FT_FREE( *bp ); 00276 00277 FT_FREE( ht->table ); 00278 } 00279 } 00280 00281 00282 static FT_Error 00283 hash_insert( char* key, 00284 size_t data, 00285 hashtable* ht, 00286 FT_Memory memory ) 00287 { 00288 hashnode nn, *bp = hash_bucket( key, ht ); 00289 FT_Error error = BDF_Err_Ok; 00290 00291 00292 nn = *bp; 00293 if ( !nn ) 00294 { 00295 if ( FT_NEW( nn ) ) 00296 goto Exit; 00297 *bp = nn; 00298 00299 nn->key = key; 00300 nn->data = data; 00301 00302 if ( ht->used >= ht->limit ) 00303 { 00304 error = hash_rehash( ht, memory ); 00305 if ( error ) 00306 goto Exit; 00307 } 00308 ht->used++; 00309 } 00310 else 00311 nn->data = data; 00312 00313 Exit: 00314 return error; 00315 } 00316 00317 00318 static hashnode 00319 hash_lookup( const char* key, 00320 hashtable* ht ) 00321 { 00322 hashnode *np = hash_bucket( key, ht ); 00323 00324 00325 return *np; 00326 } 00327 00328 00329 /*************************************************************************/ 00330 /* */ 00331 /* Utility types and functions. */ 00332 /* */ 00333 /*************************************************************************/ 00334 00335 00336 /* Function type for parsing lines of a BDF font. */ 00337 00338 typedef FT_Error 00339 (*_bdf_line_func_t)( char* line, 00340 unsigned long linelen, 00341 unsigned long lineno, 00342 void* call_data, 00343 void* client_data ); 00344 00345 00346 /* List structure for splitting lines into fields. */ 00347 00348 typedef struct _bdf_list_t_ 00349 { 00350 char** field; 00351 unsigned long size; 00352 unsigned long used; 00353 FT_Memory memory; 00354 00355 } _bdf_list_t; 00356 00357 00358 /* Structure used while loading BDF fonts. */ 00359 00360 typedef struct _bdf_parse_t_ 00361 { 00362 unsigned long flags; 00363 unsigned long cnt; 00364 unsigned long row; 00365 00366 short minlb; 00367 short maxlb; 00368 short maxrb; 00369 short maxas; 00370 short maxds; 00371 00372 short rbearing; 00373 00374 char* glyph_name; 00375 long glyph_enc; 00376 00377 bdf_font_t* font; 00378 bdf_options_t* opts; 00379 00380 unsigned long have[2048]; 00381 _bdf_list_t list; 00382 00383 FT_Memory memory; 00384 00385 } _bdf_parse_t; 00386 00387 00388 #define setsbit( m, cc ) \ 00389 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) ) 00390 #define sbitset( m, cc ) \ 00391 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) ) 00392 00393 00394 static void 00395 _bdf_list_init( _bdf_list_t* list, 00396 FT_Memory memory ) 00397 { 00398 FT_ZERO( list ); 00399 list->memory = memory; 00400 } 00401 00402 00403 static void 00404 _bdf_list_done( _bdf_list_t* list ) 00405 { 00406 FT_Memory memory = list->memory; 00407 00408 00409 if ( memory ) 00410 { 00411 FT_FREE( list->field ); 00412 FT_ZERO( list ); 00413 } 00414 } 00415 00416 00417 static FT_Error 00418 _bdf_list_ensure( _bdf_list_t* list, 00419 unsigned long num_items ) /* same as _bdf_list_t.used */ 00420 { 00421 FT_Error error = BDF_Err_Ok; 00422 00423 00424 if ( num_items > list->size ) 00425 { 00426 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */ 00427 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 4; 00428 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) ); 00429 FT_Memory memory = list->memory; 00430 00431 00432 if ( oldsize == bigsize ) 00433 { 00434 error = BDF_Err_Out_Of_Memory; 00435 goto Exit; 00436 } 00437 else if ( newsize < oldsize || newsize > bigsize ) 00438 newsize = bigsize; 00439 00440 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) ) 00441 goto Exit; 00442 00443 list->size = newsize; 00444 } 00445 00446 Exit: 00447 return error; 00448 } 00449 00450 00451 static void 00452 _bdf_list_shift( _bdf_list_t* list, 00453 unsigned long n ) 00454 { 00455 unsigned long i, u; 00456 00457 00458 if ( list == 0 || list->used == 0 || n == 0 ) 00459 return; 00460 00461 if ( n >= list->used ) 00462 { 00463 list->used = 0; 00464 return; 00465 } 00466 00467 for ( u = n, i = 0; u < list->used; i++, u++ ) 00468 list->field[i] = list->field[u]; 00469 list->used -= n; 00470 } 00471 00472 00473 /* An empty string for empty fields. */ 00474 00475 static const char empty[1] = { 0 }; /* XXX eliminate this */ 00476 00477 00478 static char * 00479 _bdf_list_join( _bdf_list_t* list, 00480 int c, 00481 unsigned long *alen ) 00482 { 00483 unsigned long i, j; 00484 char *fp, *dp; 00485 00486 00487 *alen = 0; 00488 00489 if ( list == 0 || list->used == 0 ) 00490 return 0; 00491 00492 dp = list->field[0]; 00493 for ( i = j = 0; i < list->used; i++ ) 00494 { 00495 fp = list->field[i]; 00496 while ( *fp ) 00497 dp[j++] = *fp++; 00498 00499 if ( i + 1 < list->used ) 00500 dp[j++] = (char)c; 00501 } 00502 if ( dp != empty ) 00503 dp[j] = 0; 00504 00505 *alen = j; 00506 return dp; 00507 } 00508 00509 00510 static FT_Error 00511 _bdf_list_split( _bdf_list_t* list, 00512 char* separators, 00513 char* line, 00514 unsigned long linelen ) 00515 { 00516 int mult, final_empty; 00517 char *sp, *ep, *end; 00518 char seps[32]; 00519 FT_Error error = BDF_Err_Ok; 00520 00521 00522 /* Initialize the list. */ 00523 list->used = 0; 00524 00525 /* If the line is empty, then simply return. */ 00526 if ( linelen == 0 || line[0] == 0 ) 00527 goto Exit; 00528 00529 /* In the original code, if the `separators' parameter is NULL or */ 00530 /* empty, the list is split into individual bytes. We don't need */ 00531 /* this, so an error is signaled. */ 00532 if ( separators == 0 || *separators == 0 ) 00533 { 00534 error = BDF_Err_Invalid_Argument; 00535 goto Exit; 00536 } 00537 00538 /* Prepare the separator bitmap. */ 00539 FT_MEM_ZERO( seps, 32 ); 00540 00541 /* If the very last character of the separator string is a plus, then */ 00542 /* set the `mult' flag to indicate that multiple separators should be */ 00543 /* collapsed into one. */ 00544 for ( mult = 0, sp = separators; sp && *sp; sp++ ) 00545 { 00546 if ( *sp == '+' && *( sp + 1 ) == 0 ) 00547 mult = 1; 00548 else 00549 setsbit( seps, *sp ); 00550 } 00551 00552 /* Break the line up into fields. */ 00553 for ( final_empty = 0, sp = ep = line, end = sp + linelen; 00554 sp < end && *sp; ) 00555 { 00556 /* Collect everything that is not a separator. */ 00557 for ( ; *ep && !sbitset( seps, *ep ); ep++ ) 00558 ; 00559 00560 /* Resize the list if necessary. */ 00561 if ( list->used == list->size ) 00562 { 00563 error = _bdf_list_ensure( list, list->used + 1 ); 00564 if ( error ) 00565 goto Exit; 00566 } 00567 00568 /* Assign the field appropriately. */ 00569 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty; 00570 00571 sp = ep; 00572 00573 if ( mult ) 00574 { 00575 /* If multiple separators should be collapsed, do it now by */ 00576 /* setting all the separator characters to 0. */ 00577 for ( ; *ep && sbitset( seps, *ep ); ep++ ) 00578 *ep = 0; 00579 } 00580 else if ( *ep != 0 ) 00581 /* Don't collapse multiple separators by making them 0, so just */ 00582 /* make the one encountered 0. */ 00583 *ep++ = 0; 00584 00585 final_empty = ( ep > sp && *ep == 0 ); 00586 sp = ep; 00587 } 00588 00589 /* Finally, NULL-terminate the list. */ 00590 if ( list->used + final_empty >= list->size ) 00591 { 00592 error = _bdf_list_ensure( list, list->used + final_empty + 1 ); 00593 if ( error ) 00594 goto Exit; 00595 } 00596 00597 if ( final_empty ) 00598 list->field[list->used++] = (char*)empty; 00599 00600 list->field[list->used] = 0; 00601 00602 Exit: 00603 return error; 00604 } 00605 00606 00607 #define NO_SKIP 256 /* this value cannot be stored in a 'char' */ 00608 00609 00610 static FT_Error 00611 _bdf_readstream( FT_Stream stream, 00612 _bdf_line_func_t callback, 00613 void* client_data, 00614 unsigned long *lno ) 00615 { 00616 _bdf_line_func_t cb; 00617 unsigned long lineno, buf_size; 00618 int refill, hold, to_skip; 00619 ptrdiff_t bytes, start, end, cursor, avail; 00620 char* buf = 0; 00621 FT_Memory memory = stream->memory; 00622 FT_Error error = BDF_Err_Ok; 00623 00624 00625 if ( callback == 0 ) 00626 { 00627 error = BDF_Err_Invalid_Argument; 00628 goto Exit; 00629 } 00630 00631 /* initial size and allocation of the input buffer */ 00632 buf_size = 1024; 00633 00634 if ( FT_NEW_ARRAY( buf, buf_size ) ) 00635 goto Exit; 00636 00637 cb = callback; 00638 lineno = 1; 00639 buf[0] = 0; 00640 start = 0; 00641 end = 0; 00642 avail = 0; 00643 cursor = 0; 00644 refill = 1; 00645 to_skip = NO_SKIP; 00646 bytes = 0; /* make compiler happy */ 00647 00648 for (;;) 00649 { 00650 if ( refill ) 00651 { 00652 bytes = (ptrdiff_t)FT_Stream_TryRead( 00653 stream, (FT_Byte*)buf + cursor, 00654 (FT_ULong)( buf_size - cursor ) ); 00655 avail = cursor + bytes; 00656 cursor = 0; 00657 refill = 0; 00658 } 00659 00660 end = start; 00661 00662 /* should we skip an optional character like \n or \r? */ 00663 if ( start < avail && buf[start] == to_skip ) 00664 { 00665 start += 1; 00666 to_skip = NO_SKIP; 00667 continue; 00668 } 00669 00670 /* try to find the end of the line */ 00671 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' ) 00672 end++; 00673 00674 /* if we hit the end of the buffer, try shifting its content */ 00675 /* or even resizing it */ 00676 if ( end >= avail ) 00677 { 00678 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */ 00679 break; /* ignore it then exit */ 00680 00681 if ( start == 0 ) 00682 { 00683 /* this line is definitely too long; try resizing the input */ 00684 /* buffer a bit to handle it. */ 00685 FT_ULong new_size; 00686 00687 00688 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */ 00689 { 00690 error = BDF_Err_Invalid_Argument; 00691 goto Exit; 00692 } 00693 00694 new_size = buf_size * 2; 00695 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) ) 00696 goto Exit; 00697 00698 cursor = buf_size; 00699 buf_size = new_size; 00700 } 00701 else 00702 { 00703 bytes = avail - start; 00704 00705 FT_MEM_COPY( buf, buf + start, bytes ); 00706 00707 cursor = bytes; 00708 avail -= bytes; 00709 start = 0; 00710 } 00711 refill = 1; 00712 continue; 00713 } 00714 00715 /* Temporarily NUL-terminate the line. */ 00716 hold = buf[end]; 00717 buf[end] = 0; 00718 00719 /* XXX: Use encoding independent value for 0x1a */ 00720 if ( buf[start] != '#' && buf[start] != 0x1a && end > start ) 00721 { 00722 error = (*cb)( buf + start, end - start, lineno, 00723 (void*)&cb, client_data ); 00724 /* Redo if we have encountered CHARS without properties. */ 00725 if ( error == -1 ) 00726 error = (*cb)( buf + start, end - start, lineno, 00727 (void*)&cb, client_data ); 00728 if ( error ) 00729 break; 00730 } 00731 00732 lineno += 1; 00733 buf[end] = (char)hold; 00734 start = end + 1; 00735 00736 if ( hold == '\n' ) 00737 to_skip = '\r'; 00738 else if ( hold == '\r' ) 00739 to_skip = '\n'; 00740 else 00741 to_skip = NO_SKIP; 00742 } 00743 00744 *lno = lineno; 00745 00746 Exit: 00747 FT_FREE( buf ); 00748 return error; 00749 } 00750 00751 00752 /* XXX: make this work with EBCDIC also */ 00753 00754 static const unsigned char a2i[128] = 00755 { 00756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00758 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00760 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00, 00761 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 00762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00764 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 00765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 00767 }; 00768 00769 static const unsigned char odigits[32] = 00770 { 00771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 00772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00775 }; 00776 00777 static const unsigned char ddigits[32] = 00778 { 00779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 00780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00783 }; 00784 00785 static const unsigned char hdigits[32] = 00786 { 00787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 00788 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 00789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00791 }; 00792 00793 00794 #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) ) 00795 00796 00797 /* Routine to convert an ASCII string into an unsigned long integer. */ 00798 static unsigned long 00799 _bdf_atoul( char* s, 00800 char** end, 00801 int base ) 00802 { 00803 unsigned long v; 00804 const unsigned char* dmap; 00805 00806 00807 if ( s == 0 || *s == 0 ) 00808 return 0; 00809 00810 /* Make sure the radix is something recognizable. Default to 10. */ 00811 switch ( base ) 00812 { 00813 case 8: 00814 dmap = odigits; 00815 break; 00816 case 16: 00817 dmap = hdigits; 00818 break; 00819 default: 00820 base = 10; 00821 dmap = ddigits; 00822 break; 00823 } 00824 00825 /* Check for the special hex prefix. */ 00826 if ( *s == '0' && 00827 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) 00828 { 00829 base = 16; 00830 dmap = hdigits; 00831 s += 2; 00832 } 00833 00834 for ( v = 0; isdigok( dmap, *s ); s++ ) 00835 v = v * base + a2i[(int)*s]; 00836 00837 if ( end != 0 ) 00838 *end = s; 00839 00840 return v; 00841 } 00842 00843 00844 /* Routine to convert an ASCII string into an signed long integer. */ 00845 static long 00846 _bdf_atol( char* s, 00847 char** end, 00848 int base ) 00849 { 00850 long v, neg; 00851 const unsigned char* dmap; 00852 00853 00854 if ( s == 0 || *s == 0 ) 00855 return 0; 00856 00857 /* Make sure the radix is something recognizable. Default to 10. */ 00858 switch ( base ) 00859 { 00860 case 8: 00861 dmap = odigits; 00862 break; 00863 case 16: 00864 dmap = hdigits; 00865 break; 00866 default: 00867 base = 10; 00868 dmap = ddigits; 00869 break; 00870 } 00871 00872 /* Check for a minus sign. */ 00873 neg = 0; 00874 if ( *s == '-' ) 00875 { 00876 s++; 00877 neg = 1; 00878 } 00879 00880 /* Check for the special hex prefix. */ 00881 if ( *s == '0' && 00882 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) 00883 { 00884 base = 16; 00885 dmap = hdigits; 00886 s += 2; 00887 } 00888 00889 for ( v = 0; isdigok( dmap, *s ); s++ ) 00890 v = v * base + a2i[(int)*s]; 00891 00892 if ( end != 0 ) 00893 *end = s; 00894 00895 return ( !neg ) ? v : -v; 00896 } 00897 00898 00899 /* Routine to convert an ASCII string into an signed short integer. */ 00900 static short 00901 _bdf_atos( char* s, 00902 char** end, 00903 int base ) 00904 { 00905 short v, neg; 00906 const unsigned char* dmap; 00907 00908 00909 if ( s == 0 || *s == 0 ) 00910 return 0; 00911 00912 /* Make sure the radix is something recognizable. Default to 10. */ 00913 switch ( base ) 00914 { 00915 case 8: 00916 dmap = odigits; 00917 break; 00918 case 16: 00919 dmap = hdigits; 00920 break; 00921 default: 00922 base = 10; 00923 dmap = ddigits; 00924 break; 00925 } 00926 00927 /* Check for a minus. */ 00928 neg = 0; 00929 if ( *s == '-' ) 00930 { 00931 s++; 00932 neg = 1; 00933 } 00934 00935 /* Check for the special hex prefix. */ 00936 if ( *s == '0' && 00937 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) ) 00938 { 00939 base = 16; 00940 dmap = hdigits; 00941 s += 2; 00942 } 00943 00944 for ( v = 0; isdigok( dmap, *s ); s++ ) 00945 v = (short)( v * base + a2i[(int)*s] ); 00946 00947 if ( end != 0 ) 00948 *end = s; 00949 00950 return (short)( ( !neg ) ? v : -v ); 00951 } 00952 00953 00954 /* Routine to compare two glyphs by encoding so they can be sorted. */ 00955 static int 00956 by_encoding( const void* a, 00957 const void* b ) 00958 { 00959 bdf_glyph_t *c1, *c2; 00960 00961 00962 c1 = (bdf_glyph_t *)a; 00963 c2 = (bdf_glyph_t *)b; 00964 00965 if ( c1->encoding < c2->encoding ) 00966 return -1; 00967 00968 if ( c1->encoding > c2->encoding ) 00969 return 1; 00970 00971 return 0; 00972 } 00973 00974 00975 static FT_Error 00976 bdf_create_property( char* name, 00977 int format, 00978 bdf_font_t* font ) 00979 { 00980 size_t n; 00981 bdf_property_t* p; 00982 FT_Memory memory = font->memory; 00983 FT_Error error = BDF_Err_Ok; 00984 00985 00986 /* First check to see if the property has */ 00987 /* already been added or not. If it has, then */ 00988 /* simply ignore it. */ 00989 if ( hash_lookup( name, &(font->proptbl) ) ) 00990 goto Exit; 00991 00992 if ( FT_RENEW_ARRAY( font->user_props, 00993 font->nuser_props, 00994 font->nuser_props + 1 ) ) 00995 goto Exit; 00996 00997 p = font->user_props + font->nuser_props; 00998 FT_ZERO( p ); 00999 01000 n = ft_strlen( name ) + 1; 01001 if ( n > FT_ULONG_MAX ) 01002 return BDF_Err_Invalid_Argument; 01003 01004 if ( FT_NEW_ARRAY( p->name, n ) ) 01005 goto Exit; 01006 01007 FT_MEM_COPY( (char *)p->name, name, n ); 01008 01009 p->format = format; 01010 p->builtin = 0; 01011 01012 n = _num_bdf_properties + font->nuser_props; 01013 01014 error = hash_insert( p->name, n, &(font->proptbl), memory ); 01015 if ( error ) 01016 goto Exit; 01017 01018 font->nuser_props++; 01019 01020 Exit: 01021 return error; 01022 } 01023 01024 01025 FT_LOCAL_DEF( bdf_property_t * ) 01026 bdf_get_property( char* name, 01027 bdf_font_t* font ) 01028 { 01029 hashnode hn; 01030 size_t propid; 01031 01032 01033 if ( name == 0 || *name == 0 ) 01034 return 0; 01035 01036 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 ) 01037 return 0; 01038 01039 propid = hn->data; 01040 if ( propid >= _num_bdf_properties ) 01041 return font->user_props + ( propid - _num_bdf_properties ); 01042 01043 return (bdf_property_t*)_bdf_properties + propid; 01044 } 01045 01046 01047 /*************************************************************************/ 01048 /* */ 01049 /* BDF font file parsing flags and functions. */ 01050 /* */ 01051 /*************************************************************************/ 01052 01053 01054 /* Parse flags. */ 01055 01056 #define _BDF_START 0x0001 01057 #define _BDF_FONT_NAME 0x0002 01058 #define _BDF_SIZE 0x0004 01059 #define _BDF_FONT_BBX 0x0008 01060 #define _BDF_PROPS 0x0010 01061 #define _BDF_GLYPHS 0x0020 01062 #define _BDF_GLYPH 0x0040 01063 #define _BDF_ENCODING 0x0080 01064 #define _BDF_SWIDTH 0x0100 01065 #define _BDF_DWIDTH 0x0200 01066 #define _BDF_BBX 0x0400 01067 #define _BDF_BITMAP 0x0800 01068 01069 #define _BDF_SWIDTH_ADJ 0x1000 01070 01071 #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \ 01072 _BDF_ENCODING | \ 01073 _BDF_SWIDTH | \ 01074 _BDF_DWIDTH | \ 01075 _BDF_BBX | \ 01076 _BDF_BITMAP ) 01077 01078 #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL 01079 #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL 01080 01081 01082 /* Auto correction messages. */ 01083 #define ACMSG1 "FONT_ASCENT property missing. " \ 01084 "Added \"FONT_ASCENT %hd\".\n" 01085 #define ACMSG2 "FONT_DESCENT property missing. " \ 01086 "Added \"FONT_DESCENT %hd\".\n" 01087 #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n" 01088 #define ACMSG4 "Font left bearing != actual left bearing. " \ 01089 "Old: %hd New: %hd.\n" 01090 #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n" 01091 #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n" 01092 #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n" 01093 #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n" 01094 #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n" 01095 #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n" 01096 #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n" 01097 #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n" 01098 #define ACMSG13 "Glyph %ld extra rows removed.\n" 01099 #define ACMSG14 "Glyph %ld extra columns removed.\n" 01100 #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n" 01101 01102 /* Error messages. */ 01103 #define ERRMSG1 "[line %ld] Missing \"%s\" line.\n" 01104 #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n" 01105 #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n" 01106 #define ERRMSG4 "[line %ld] BBX too big.\n" 01107 01108 01109 static FT_Error 01110 _bdf_add_comment( bdf_font_t* font, 01111 char* comment, 01112 unsigned long len ) 01113 { 01114 char* cp; 01115 FT_Memory memory = font->memory; 01116 FT_Error error = BDF_Err_Ok; 01117 01118 01119 if ( FT_RENEW_ARRAY( font->comments, 01120 font->comments_len, 01121 font->comments_len + len + 1 ) ) 01122 goto Exit; 01123 01124 cp = font->comments + font->comments_len; 01125 01126 FT_MEM_COPY( cp, comment, len ); 01127 cp[len] = '\n'; 01128 01129 font->comments_len += len + 1; 01130 01131 Exit: 01132 return error; 01133 } 01134 01135 01136 /* Set the spacing from the font name if it exists, or set it to the */ 01137 /* default specified in the options. */ 01138 static FT_Error 01139 _bdf_set_default_spacing( bdf_font_t* font, 01140 bdf_options_t* opts ) 01141 { 01142 size_t len; 01143 char name[256]; 01144 _bdf_list_t list; 01145 FT_Memory memory; 01146 FT_Error error = BDF_Err_Ok; 01147 01148 01149 if ( font == 0 || font->name == 0 || font->name[0] == 0 ) 01150 { 01151 error = BDF_Err_Invalid_Argument; 01152 goto Exit; 01153 } 01154 01155 memory = font->memory; 01156 01157 _bdf_list_init( &list, memory ); 01158 01159 font->spacing = opts->font_spacing; 01160 01161 len = ft_strlen( font->name ) + 1; 01162 /* Limit ourselves to 256 characters in the font name. */ 01163 if ( len >= 256 ) 01164 { 01165 error = BDF_Err_Invalid_Argument; 01166 goto Exit; 01167 } 01168 01169 FT_MEM_COPY( name, font->name, len ); 01170 01171 error = _bdf_list_split( &list, (char *)"-", name, len ); 01172 if ( error ) 01173 goto Fail; 01174 01175 if ( list.used == 15 ) 01176 { 01177 switch ( list.field[11][0] ) 01178 { 01179 case 'C': 01180 case 'c': 01181 font->spacing = BDF_CHARCELL; 01182 break; 01183 case 'M': 01184 case 'm': 01185 font->spacing = BDF_MONOWIDTH; 01186 break; 01187 case 'P': 01188 case 'p': 01189 font->spacing = BDF_PROPORTIONAL; 01190 break; 01191 } 01192 } 01193 01194 Fail: 01195 _bdf_list_done( &list ); 01196 01197 Exit: 01198 return error; 01199 } 01200 01201 01202 /* Determine whether the property is an atom or not. If it is, then */ 01203 /* clean it up so the double quotes are removed if they exist. */ 01204 static int 01205 _bdf_is_atom( char* line, 01206 unsigned long linelen, 01207 char** name, 01208 char** value, 01209 bdf_font_t* font ) 01210 { 01211 int hold; 01212 char *sp, *ep; 01213 bdf_property_t* p; 01214 01215 01216 *name = sp = ep = line; 01217 01218 while ( *ep && *ep != ' ' && *ep != '\t' ) 01219 ep++; 01220 01221 hold = -1; 01222 if ( *ep ) 01223 { 01224 hold = *ep; 01225 *ep = 0; 01226 } 01227 01228 p = bdf_get_property( sp, font ); 01229 01230 /* Restore the character that was saved before any return can happen. */ 01231 if ( hold != -1 ) 01232 *ep = (char)hold; 01233 01234 /* If the property exists and is not an atom, just return here. */ 01235 if ( p && p->format != BDF_ATOM ) 01236 return 0; 01237 01238 /* The property is an atom. Trim all leading and trailing whitespace */ 01239 /* and double quotes for the atom value. */ 01240 sp = ep; 01241 ep = line + linelen; 01242 01243 /* Trim the leading whitespace if it exists. */ 01244 *sp++ = 0; 01245 while ( *sp && 01246 ( *sp == ' ' || *sp == '\t' ) ) 01247 sp++; 01248 01249 /* Trim the leading double quote if it exists. */ 01250 if ( *sp == '"' ) 01251 sp++; 01252 *value = sp; 01253 01254 /* Trim the trailing whitespace if it exists. */ 01255 while ( ep > sp && 01256 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) ) 01257 *--ep = 0; 01258 01259 /* Trim the trailing double quote if it exists. */ 01260 if ( ep > sp && *( ep - 1 ) == '"' ) 01261 *--ep = 0; 01262 01263 return 1; 01264 } 01265 01266 01267 static FT_Error 01268 _bdf_add_property( bdf_font_t* font, 01269 char* name, 01270 char* value ) 01271 { 01272 size_t propid; 01273 hashnode hn; 01274 bdf_property_t *prop, *fp; 01275 FT_Memory memory = font->memory; 01276 FT_Error error = BDF_Err_Ok; 01277 01278 01279 /* First, check to see if the property already exists in the font. */ 01280 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 ) 01281 { 01282 /* The property already exists in the font, so simply replace */ 01283 /* the value of the property with the current value. */ 01284 fp = font->props + hn->data; 01285 01286 switch ( fp->format ) 01287 { 01288 case BDF_ATOM: 01289 /* Delete the current atom if it exists. */ 01290 FT_FREE( fp->value.atom ); 01291 01292 if ( value && value[0] != 0 ) 01293 { 01294 if ( FT_STRDUP( fp->value.atom, value ) ) 01295 goto Exit; 01296 } 01297 break; 01298 01299 case BDF_INTEGER: 01300 fp->value.l = _bdf_atol( value, 0, 10 ); 01301 break; 01302 01303 case BDF_CARDINAL: 01304 fp->value.ul = _bdf_atoul( value, 0, 10 ); 01305 break; 01306 01307 default: 01308 ; 01309 } 01310 01311 goto Exit; 01312 } 01313 01314 /* See whether this property type exists yet or not. */ 01315 /* If not, create it. */ 01316 hn = hash_lookup( name, &(font->proptbl) ); 01317 if ( hn == 0 ) 01318 { 01319 error = bdf_create_property( name, BDF_ATOM, font ); 01320 if ( error ) 01321 goto Exit; 01322 hn = hash_lookup( name, &(font->proptbl) ); 01323 } 01324 01325 /* Allocate another property if this is overflow. */ 01326 if ( font->props_used == font->props_size ) 01327 { 01328 if ( font->props_size == 0 ) 01329 { 01330 if ( FT_NEW_ARRAY( font->props, 1 ) ) 01331 goto Exit; 01332 } 01333 else 01334 { 01335 if ( FT_RENEW_ARRAY( font->props, 01336 font->props_size, 01337 font->props_size + 1 ) ) 01338 goto Exit; 01339 } 01340 01341 fp = font->props + font->props_size; 01342 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) ); 01343 font->props_size++; 01344 } 01345 01346 propid = hn->data; 01347 if ( propid >= _num_bdf_properties ) 01348 prop = font->user_props + ( propid - _num_bdf_properties ); 01349 else 01350 prop = (bdf_property_t*)_bdf_properties + propid; 01351 01352 fp = font->props + font->props_used; 01353 01354 fp->name = prop->name; 01355 fp->format = prop->format; 01356 fp->builtin = prop->builtin; 01357 01358 switch ( prop->format ) 01359 { 01360 case BDF_ATOM: 01361 fp->value.atom = 0; 01362 if ( value != 0 && value[0] ) 01363 { 01364 if ( FT_STRDUP( fp->value.atom, value ) ) 01365 goto Exit; 01366 } 01367 break; 01368 01369 case BDF_INTEGER: 01370 fp->value.l = _bdf_atol( value, 0, 10 ); 01371 break; 01372 01373 case BDF_CARDINAL: 01374 fp->value.ul = _bdf_atoul( value, 0, 10 ); 01375 break; 01376 } 01377 01378 /* If the property happens to be a comment, then it doesn't need */ 01379 /* to be added to the internal hash table. */ 01380 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) 01381 { 01382 /* Add the property to the font property table. */ 01383 error = hash_insert( fp->name, 01384 font->props_used, 01385 (hashtable *)font->internal, 01386 memory ); 01387 if ( error ) 01388 goto Exit; 01389 } 01390 01391 font->props_used++; 01392 01393 /* Some special cases need to be handled here. The DEFAULT_CHAR */ 01394 /* property needs to be located if it exists in the property list, the */ 01395 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */ 01396 /* present, and the SPACING property should override the default */ 01397 /* spacing. */ 01398 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 ) 01399 font->default_char = fp->value.l; 01400 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 ) 01401 font->font_ascent = fp->value.l; 01402 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 ) 01403 font->font_descent = fp->value.l; 01404 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 ) 01405 { 01406 if ( !fp->value.atom ) 01407 { 01408 error = BDF_Err_Invalid_File_Format; 01409 goto Exit; 01410 } 01411 01412 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' ) 01413 font->spacing = BDF_PROPORTIONAL; 01414 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' ) 01415 font->spacing = BDF_MONOWIDTH; 01416 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' ) 01417 font->spacing = BDF_CHARCELL; 01418 } 01419 01420 Exit: 01421 return error; 01422 } 01423 01424 01425 static const unsigned char nibble_mask[8] = 01426 { 01427 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE 01428 }; 01429 01430 01431 /* Actually parse the glyph info and bitmaps. */ 01432 static FT_Error 01433 _bdf_parse_glyphs( char* line, 01434 unsigned long linelen, 01435 unsigned long lineno, 01436 void* call_data, 01437 void* client_data ) 01438 { 01439 int c, mask_index; 01440 char* s; 01441 unsigned char* bp; 01442 unsigned long i, slen, nibbles; 01443 01444 _bdf_parse_t* p; 01445 bdf_glyph_t* glyph; 01446 bdf_font_t* font; 01447 01448 FT_Memory memory; 01449 FT_Error error = BDF_Err_Ok; 01450 01451 FT_UNUSED( call_data ); 01452 FT_UNUSED( lineno ); /* only used in debug mode */ 01453 01454 01455 p = (_bdf_parse_t *)client_data; 01456 01457 font = p->font; 01458 memory = font->memory; 01459 01460 /* Check for a comment. */ 01461 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) 01462 { 01463 linelen -= 7; 01464 01465 s = line + 7; 01466 if ( *s != 0 ) 01467 { 01468 s++; 01469 linelen--; 01470 } 01471 error = _bdf_add_comment( p->font, s, linelen ); 01472 goto Exit; 01473 } 01474 01475 /* The very first thing expected is the number of glyphs. */ 01476 if ( !( p->flags & _BDF_GLYPHS ) ) 01477 { 01478 if ( ft_memcmp( line, "CHARS", 5 ) != 0 ) 01479 { 01480 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" )); 01481 error = BDF_Err_Missing_Chars_Field; 01482 goto Exit; 01483 } 01484 01485 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 01486 if ( error ) 01487 goto Exit; 01488 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 ); 01489 01490 /* Make sure the number of glyphs is non-zero. */ 01491 if ( p->cnt == 0 ) 01492 font->glyphs_size = 64; 01493 01494 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */ 01495 /* number of code points available in Unicode). */ 01496 if ( p->cnt >= 1114112UL ) 01497 { 01498 error = BDF_Err_Invalid_Argument; 01499 goto Exit; 01500 } 01501 01502 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) ) 01503 goto Exit; 01504 01505 p->flags |= _BDF_GLYPHS; 01506 01507 goto Exit; 01508 } 01509 01510 /* Check for the ENDFONT field. */ 01511 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 ) 01512 { 01513 /* Sort the glyphs by encoding. */ 01514 ft_qsort( (char *)font->glyphs, 01515 font->glyphs_used, 01516 sizeof ( bdf_glyph_t ), 01517 by_encoding ); 01518 01519 p->flags &= ~_BDF_START; 01520 01521 goto Exit; 01522 } 01523 01524 /* Check for the ENDCHAR field. */ 01525 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 ) 01526 { 01527 p->glyph_enc = 0; 01528 p->flags &= ~_BDF_GLYPH_BITS; 01529 01530 goto Exit; 01531 } 01532 01533 /* Check to see whether a glyph is being scanned but should be */ 01534 /* ignored because it is an unencoded glyph. */ 01535 if ( ( p->flags & _BDF_GLYPH ) && 01536 p->glyph_enc == -1 && 01537 p->opts->keep_unencoded == 0 ) 01538 goto Exit; 01539 01540 /* Check for the STARTCHAR field. */ 01541 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 ) 01542 { 01543 /* Set the character name in the parse info first until the */ 01544 /* encoding can be checked for an unencoded character. */ 01545 FT_FREE( p->glyph_name ); 01546 01547 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 01548 if ( error ) 01549 goto Exit; 01550 01551 _bdf_list_shift( &p->list, 1 ); 01552 01553 s = _bdf_list_join( &p->list, ' ', &slen ); 01554 01555 if ( !s ) 01556 { 01557 error = BDF_Err_Invalid_File_Format; 01558 goto Exit; 01559 } 01560 01561 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) ) 01562 goto Exit; 01563 01564 FT_MEM_COPY( p->glyph_name, s, slen + 1 ); 01565 01566 p->flags |= _BDF_GLYPH; 01567 01568 goto Exit; 01569 } 01570 01571 /* Check for the ENCODING field. */ 01572 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 ) 01573 { 01574 if ( !( p->flags & _BDF_GLYPH ) ) 01575 { 01576 /* Missing STARTCHAR field. */ 01577 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" )); 01578 error = BDF_Err_Missing_Startchar_Field; 01579 goto Exit; 01580 } 01581 01582 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 01583 if ( error ) 01584 goto Exit; 01585 01586 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 ); 01587 01588 /* Check that the encoding is in the range [0,65536] because */ 01589 /* otherwise p->have (a bitmap with static size) overflows. */ 01590 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 ) 01591 { 01592 error = BDF_Err_Invalid_File_Format; 01593 goto Exit; 01594 } 01595 01596 /* Check to see whether this encoding has already been encountered. */ 01597 /* If it has then change it to unencoded so it gets added if */ 01598 /* indicated. */ 01599 if ( p->glyph_enc >= 0 ) 01600 { 01601 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) ) 01602 { 01603 /* Emit a message saying a glyph has been moved to the */ 01604 /* unencoded area. */ 01605 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12, 01606 p->glyph_enc, p->glyph_name )); 01607 p->glyph_enc = -1; 01608 font->modified = 1; 01609 } 01610 else 01611 _bdf_set_glyph_modified( p->have, p->glyph_enc ); 01612 } 01613 01614 if ( p->glyph_enc >= 0 ) 01615 { 01616 /* Make sure there are enough glyphs allocated in case the */ 01617 /* number of characters happen to be wrong. */ 01618 if ( font->glyphs_used == font->glyphs_size ) 01619 { 01620 if ( FT_RENEW_ARRAY( font->glyphs, 01621 font->glyphs_size, 01622 font->glyphs_size + 64 ) ) 01623 goto Exit; 01624 01625 font->glyphs_size += 64; 01626 } 01627 01628 glyph = font->glyphs + font->glyphs_used++; 01629 glyph->name = p->glyph_name; 01630 glyph->encoding = p->glyph_enc; 01631 01632 /* Reset the initial glyph info. */ 01633 p->glyph_name = 0; 01634 } 01635 else 01636 { 01637 /* Unencoded glyph. Check to see whether it should */ 01638 /* be added or not. */ 01639 if ( p->opts->keep_unencoded != 0 ) 01640 { 01641 /* Allocate the next unencoded glyph. */ 01642 if ( font->unencoded_used == font->unencoded_size ) 01643 { 01644 if ( FT_RENEW_ARRAY( font->unencoded , 01645 font->unencoded_size, 01646 font->unencoded_size + 4 ) ) 01647 goto Exit; 01648 01649 font->unencoded_size += 4; 01650 } 01651 01652 glyph = font->unencoded + font->unencoded_used; 01653 glyph->name = p->glyph_name; 01654 glyph->encoding = font->unencoded_used++; 01655 } 01656 else 01657 /* Free up the glyph name if the unencoded shouldn't be */ 01658 /* kept. */ 01659 FT_FREE( p->glyph_name ); 01660 01661 p->glyph_name = 0; 01662 } 01663 01664 /* Clear the flags that might be added when width and height are */ 01665 /* checked for consistency. */ 01666 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK ); 01667 01668 p->flags |= _BDF_ENCODING; 01669 01670 goto Exit; 01671 } 01672 01673 /* Point at the glyph being constructed. */ 01674 if ( p->glyph_enc == -1 ) 01675 glyph = font->unencoded + ( font->unencoded_used - 1 ); 01676 else 01677 glyph = font->glyphs + ( font->glyphs_used - 1 ); 01678 01679 /* Check to see whether a bitmap is being constructed. */ 01680 if ( p->flags & _BDF_BITMAP ) 01681 { 01682 /* If there are more rows than are specified in the glyph metrics, */ 01683 /* ignore the remaining lines. */ 01684 if ( p->row >= (unsigned long)glyph->bbx.height ) 01685 { 01686 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) ) 01687 { 01688 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding )); 01689 p->flags |= _BDF_GLYPH_HEIGHT_CHECK; 01690 font->modified = 1; 01691 } 01692 01693 goto Exit; 01694 } 01695 01696 /* Only collect the number of nibbles indicated by the glyph */ 01697 /* metrics. If there are more columns, they are simply ignored. */ 01698 nibbles = glyph->bpr << 1; 01699 bp = glyph->bitmap + p->row * glyph->bpr; 01700 01701 for ( i = 0; i < nibbles; i++ ) 01702 { 01703 c = line[i]; 01704 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] ); 01705 if ( i + 1 < nibbles && ( i & 1 ) ) 01706 *++bp = 0; 01707 } 01708 01709 /* Remove possible garbage at the right. */ 01710 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7; 01711 if ( glyph->bbx.width ) 01712 *bp &= nibble_mask[mask_index]; 01713 01714 /* If any line has extra columns, indicate they have been removed. */ 01715 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) && 01716 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) ) 01717 { 01718 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding )); 01719 p->flags |= _BDF_GLYPH_WIDTH_CHECK; 01720 font->modified = 1; 01721 } 01722 01723 p->row++; 01724 goto Exit; 01725 } 01726 01727 /* Expect the SWIDTH (scalable width) field next. */ 01728 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 ) 01729 { 01730 if ( !( p->flags & _BDF_ENCODING ) ) 01731 { 01732 /* Missing ENCODING field. */ 01733 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" )); 01734 error = BDF_Err_Missing_Encoding_Field; 01735 goto Exit; 01736 } 01737 01738 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 01739 if ( error ) 01740 goto Exit; 01741 01742 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); 01743 p->flags |= _BDF_SWIDTH; 01744 01745 goto Exit; 01746 } 01747 01748 /* Expect the DWIDTH (scalable width) field next. */ 01749 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 ) 01750 { 01751 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 01752 if ( error ) 01753 goto Exit; 01754 01755 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 ); 01756 01757 if ( !( p->flags & _BDF_SWIDTH ) ) 01758 { 01759 /* Missing SWIDTH field. Emit an auto correction message and set */ 01760 /* the scalable width from the device width. */ 01761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno )); 01762 01763 glyph->swidth = (unsigned short)FT_MulDiv( 01764 glyph->dwidth, 72000L, 01765 (FT_Long)( font->point_size * 01766 font->resolution_x ) ); 01767 } 01768 01769 p->flags |= _BDF_DWIDTH; 01770 goto Exit; 01771 } 01772 01773 /* Expect the BBX field next. */ 01774 if ( ft_memcmp( line, "BBX", 3 ) == 0 ) 01775 { 01776 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 01777 if ( error ) 01778 goto Exit; 01779 01780 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); 01781 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); 01782 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); 01783 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); 01784 01785 /* Generate the ascent and descent of the character. */ 01786 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset ); 01787 glyph->bbx.descent = (short)( -glyph->bbx.y_offset ); 01788 01789 /* Determine the overall font bounding box as the characters are */ 01790 /* loaded so corrections can be done later if indicated. */ 01791 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas ); 01792 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds ); 01793 01794 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset ); 01795 01796 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb ); 01797 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb ); 01798 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb ); 01799 01800 if ( !( p->flags & _BDF_DWIDTH ) ) 01801 { 01802 /* Missing DWIDTH field. Emit an auto correction message and set */ 01803 /* the device width to the glyph width. */ 01804 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno )); 01805 glyph->dwidth = glyph->bbx.width; 01806 } 01807 01808 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */ 01809 /* value if necessary. */ 01810 if ( p->opts->correct_metrics != 0 ) 01811 { 01812 /* Determine the point size of the glyph. */ 01813 unsigned short sw = (unsigned short)FT_MulDiv( 01814 glyph->dwidth, 72000L, 01815 (FT_Long)( font->point_size * 01816 font->resolution_x ) ); 01817 01818 01819 if ( sw != glyph->swidth ) 01820 { 01821 glyph->swidth = sw; 01822 01823 if ( p->glyph_enc == -1 ) 01824 _bdf_set_glyph_modified( font->umod, 01825 font->unencoded_used - 1 ); 01826 else 01827 _bdf_set_glyph_modified( font->nmod, glyph->encoding ); 01828 01829 p->flags |= _BDF_SWIDTH_ADJ; 01830 font->modified = 1; 01831 } 01832 } 01833 01834 p->flags |= _BDF_BBX; 01835 goto Exit; 01836 } 01837 01838 /* And finally, gather up the bitmap. */ 01839 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 ) 01840 { 01841 unsigned long bitmap_size; 01842 01843 01844 if ( !( p->flags & _BDF_BBX ) ) 01845 { 01846 /* Missing BBX field. */ 01847 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" )); 01848 error = BDF_Err_Missing_Bbx_Field; 01849 goto Exit; 01850 } 01851 01852 /* Allocate enough space for the bitmap. */ 01853 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3; 01854 01855 bitmap_size = glyph->bpr * glyph->bbx.height; 01856 if ( bitmap_size > 0xFFFFU ) 01857 { 01858 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno )); 01859 error = BDF_Err_Bbx_Too_Big; 01860 goto Exit; 01861 } 01862 else 01863 glyph->bytes = (unsigned short)bitmap_size; 01864 01865 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) ) 01866 goto Exit; 01867 01868 p->row = 0; 01869 p->flags |= _BDF_BITMAP; 01870 01871 goto Exit; 01872 } 01873 01874 error = BDF_Err_Invalid_File_Format; 01875 01876 Exit: 01877 if ( error && ( p->flags & _BDF_GLYPH ) ) 01878 FT_FREE( p->glyph_name ); 01879 01880 return error; 01881 } 01882 01883 01884 /* Load the font properties. */ 01885 static FT_Error 01886 _bdf_parse_properties( char* line, 01887 unsigned long linelen, 01888 unsigned long lineno, 01889 void* call_data, 01890 void* client_data ) 01891 { 01892 unsigned long vlen; 01893 _bdf_line_func_t* next; 01894 _bdf_parse_t* p; 01895 char* name; 01896 char* value; 01897 char nbuf[128]; 01898 FT_Error error = BDF_Err_Ok; 01899 01900 FT_UNUSED( lineno ); 01901 01902 01903 next = (_bdf_line_func_t *)call_data; 01904 p = (_bdf_parse_t *) client_data; 01905 01906 /* Check for the end of the properties. */ 01907 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 ) 01908 { 01909 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */ 01910 /* encountered yet, then make sure they are added as properties and */ 01911 /* make sure they are set from the font bounding box info. */ 01912 /* */ 01913 /* This is *always* done regardless of the options, because X11 */ 01914 /* requires these two fields to compile fonts. */ 01915 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 ) 01916 { 01917 p->font->font_ascent = p->font->bbx.ascent; 01918 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); 01919 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf ); 01920 if ( error ) 01921 goto Exit; 01922 01923 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); 01924 p->font->modified = 1; 01925 } 01926 01927 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 ) 01928 { 01929 p->font->font_descent = p->font->bbx.descent; 01930 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); 01931 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf ); 01932 if ( error ) 01933 goto Exit; 01934 01935 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); 01936 p->font->modified = 1; 01937 } 01938 01939 p->flags &= ~_BDF_PROPS; 01940 *next = _bdf_parse_glyphs; 01941 01942 goto Exit; 01943 } 01944 01945 /* Ignore the _XFREE86_GLYPH_RANGES properties. */ 01946 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 ) 01947 goto Exit; 01948 01949 /* Handle COMMENT fields and properties in a special way to preserve */ 01950 /* the spacing. */ 01951 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) 01952 { 01953 name = value = line; 01954 value += 7; 01955 if ( *value ) 01956 *value++ = 0; 01957 error = _bdf_add_property( p->font, name, value ); 01958 if ( error ) 01959 goto Exit; 01960 } 01961 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) ) 01962 { 01963 error = _bdf_add_property( p->font, name, value ); 01964 if ( error ) 01965 goto Exit; 01966 } 01967 else 01968 { 01969 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 01970 if ( error ) 01971 goto Exit; 01972 name = p->list.field[0]; 01973 01974 _bdf_list_shift( &p->list, 1 ); 01975 value = _bdf_list_join( &p->list, ' ', &vlen ); 01976 01977 error = _bdf_add_property( p->font, name, value ); 01978 if ( error ) 01979 goto Exit; 01980 } 01981 01982 Exit: 01983 return error; 01984 } 01985 01986 01987 /* Load the font header. */ 01988 static FT_Error 01989 _bdf_parse_start( char* line, 01990 unsigned long linelen, 01991 unsigned long lineno, 01992 void* call_data, 01993 void* client_data ) 01994 { 01995 unsigned long slen; 01996 _bdf_line_func_t* next; 01997 _bdf_parse_t* p; 01998 bdf_font_t* font; 01999 char *s; 02000 02001 FT_Memory memory = NULL; 02002 FT_Error error = BDF_Err_Ok; 02003 02004 FT_UNUSED( lineno ); /* only used in debug mode */ 02005 02006 02007 next = (_bdf_line_func_t *)call_data; 02008 p = (_bdf_parse_t *) client_data; 02009 02010 if ( p->font ) 02011 memory = p->font->memory; 02012 02013 /* Check for a comment. This is done to handle those fonts that have */ 02014 /* comments before the STARTFONT line for some reason. */ 02015 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 ) 02016 { 02017 if ( p->opts->keep_comments != 0 && p->font != 0 ) 02018 { 02019 linelen -= 7; 02020 02021 s = line + 7; 02022 if ( *s != 0 ) 02023 { 02024 s++; 02025 linelen--; 02026 } 02027 02028 error = _bdf_add_comment( p->font, s, linelen ); 02029 if ( error ) 02030 goto Exit; 02031 /* here font is not defined! */ 02032 } 02033 02034 goto Exit; 02035 } 02036 02037 if ( !( p->flags & _BDF_START ) ) 02038 { 02039 memory = p->memory; 02040 02041 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 ) 02042 { 02043 /* No STARTFONT field is a good indication of a problem. */ 02044 error = BDF_Err_Missing_Startfont_Field; 02045 goto Exit; 02046 } 02047 02048 p->flags = _BDF_START; 02049 font = p->font = 0; 02050 02051 if ( FT_NEW( font ) ) 02052 goto Exit; 02053 p->font = font; 02054 02055 font->memory = p->memory; 02056 p->memory = 0; 02057 02058 { /* setup */ 02059 size_t i; 02060 bdf_property_t* prop; 02061 02062 02063 error = hash_init( &(font->proptbl), memory ); 02064 if ( error ) 02065 goto Exit; 02066 for ( i = 0, prop = (bdf_property_t*)_bdf_properties; 02067 i < _num_bdf_properties; i++, prop++ ) 02068 { 02069 error = hash_insert( prop->name, i, 02070 &(font->proptbl), memory ); 02071 if ( error ) 02072 goto Exit; 02073 } 02074 } 02075 02076 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) ) 02077 goto Exit; 02078 error = hash_init( (hashtable *)p->font->internal,memory ); 02079 if ( error ) 02080 goto Exit; 02081 p->font->spacing = p->opts->font_spacing; 02082 p->font->default_char = -1; 02083 02084 goto Exit; 02085 } 02086 02087 /* Check for the start of the properties. */ 02088 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 ) 02089 { 02090 if ( !( p->flags & _BDF_FONT_BBX ) ) 02091 { 02092 /* Missing the FONTBOUNDINGBOX field. */ 02093 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); 02094 error = BDF_Err_Missing_Fontboundingbox_Field; 02095 goto Exit; 02096 } 02097 02098 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 02099 if ( error ) 02100 goto Exit; 02101 /* at this point, `p->font' can't be NULL */ 02102 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 ); 02103 02104 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) ) 02105 goto Exit; 02106 02107 p->flags |= _BDF_PROPS; 02108 *next = _bdf_parse_properties; 02109 02110 goto Exit; 02111 } 02112 02113 /* Check for the FONTBOUNDINGBOX field. */ 02114 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 ) 02115 { 02116 if ( !( p->flags & _BDF_SIZE ) ) 02117 { 02118 /* Missing the SIZE field. */ 02119 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" )); 02120 error = BDF_Err_Missing_Size_Field; 02121 goto Exit; 02122 } 02123 02124 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 02125 if ( error ) 02126 goto Exit; 02127 02128 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 ); 02129 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 ); 02130 02131 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 ); 02132 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 ); 02133 02134 p->font->bbx.ascent = (short)( p->font->bbx.height + 02135 p->font->bbx.y_offset ); 02136 02137 p->font->bbx.descent = (short)( -p->font->bbx.y_offset ); 02138 02139 p->flags |= _BDF_FONT_BBX; 02140 02141 goto Exit; 02142 } 02143 02144 /* The next thing to check for is the FONT field. */ 02145 if ( ft_memcmp( line, "FONT", 4 ) == 0 ) 02146 { 02147 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 02148 if ( error ) 02149 goto Exit; 02150 _bdf_list_shift( &p->list, 1 ); 02151 02152 s = _bdf_list_join( &p->list, ' ', &slen ); 02153 02154 if ( !s ) 02155 { 02156 error = BDF_Err_Invalid_File_Format; 02157 goto Exit; 02158 } 02159 02160 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */ 02161 FT_FREE( p->font->name ); 02162 02163 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) ) 02164 goto Exit; 02165 FT_MEM_COPY( p->font->name, s, slen + 1 ); 02166 02167 /* If the font name is an XLFD name, set the spacing to the one in */ 02168 /* the font name. If there is no spacing fall back on the default. */ 02169 error = _bdf_set_default_spacing( p->font, p->opts ); 02170 if ( error ) 02171 goto Exit; 02172 02173 p->flags |= _BDF_FONT_NAME; 02174 02175 goto Exit; 02176 } 02177 02178 /* Check for the SIZE field. */ 02179 if ( ft_memcmp( line, "SIZE", 4 ) == 0 ) 02180 { 02181 if ( !( p->flags & _BDF_FONT_NAME ) ) 02182 { 02183 /* Missing the FONT field. */ 02184 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" )); 02185 error = BDF_Err_Missing_Font_Field; 02186 goto Exit; 02187 } 02188 02189 error = _bdf_list_split( &p->list, (char *)" +", line, linelen ); 02190 if ( error ) 02191 goto Exit; 02192 02193 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 ); 02194 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 ); 02195 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 ); 02196 02197 /* Check for the bits per pixel field. */ 02198 if ( p->list.used == 5 ) 02199 { 02200 unsigned short bitcount, i, shift; 02201 02202 02203 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 ); 02204 02205 /* Only values 1, 2, 4, 8 are allowed. */ 02206 shift = p->font->bpp; 02207 bitcount = 0; 02208 for ( i = 0; shift > 0; i++ ) 02209 { 02210 if ( shift & 1 ) 02211 bitcount = i; 02212 shift >>= 1; 02213 } 02214 02215 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) ); 02216 02217 if ( p->font->bpp > shift || p->font->bpp != shift ) 02218 { 02219 /* select next higher value */ 02220 p->font->bpp = (unsigned short)( shift << 1 ); 02221 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp )); 02222 } 02223 } 02224 else 02225 p->font->bpp = 1; 02226 02227 p->flags |= _BDF_SIZE; 02228 02229 goto Exit; 02230 } 02231 02232 /* Check for the CHARS field -- font properties are optional */ 02233 if ( ft_memcmp( line, "CHARS", 5 ) == 0 ) 02234 { 02235 char nbuf[128]; 02236 02237 02238 if ( !( p->flags & _BDF_FONT_BBX ) ) 02239 { 02240 /* Missing the FONTBOUNDINGBOX field. */ 02241 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" )); 02242 error = BDF_Err_Missing_Fontboundingbox_Field; 02243 goto Exit; 02244 } 02245 02246 /* Add the two standard X11 properties which are required */ 02247 /* for compiling fonts. */ 02248 p->font->font_ascent = p->font->bbx.ascent; 02249 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent ); 02250 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf ); 02251 if ( error ) 02252 goto Exit; 02253 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent )); 02254 02255 p->font->font_descent = p->font->bbx.descent; 02256 ft_sprintf( nbuf, "%hd", p->font->bbx.descent ); 02257 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf ); 02258 if ( error ) 02259 goto Exit; 02260 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent )); 02261 02262 p->font->modified = 1; 02263 02264 *next = _bdf_parse_glyphs; 02265 02266 /* A special return value. */ 02267 error = -1; 02268 goto Exit; 02269 } 02270 02271 error = BDF_Err_Invalid_File_Format; 02272 02273 Exit: 02274 return error; 02275 } 02276 02277 02278 /*************************************************************************/ 02279 /* */ 02280 /* API. */ 02281 /* */ 02282 /*************************************************************************/ 02283 02284 02285 FT_LOCAL_DEF( FT_Error ) 02286 bdf_load_font( FT_Stream stream, 02287 FT_Memory extmemory, 02288 bdf_options_t* opts, 02289 bdf_font_t* *font ) 02290 { 02291 unsigned long lineno = 0; /* make compiler happy */ 02292 _bdf_parse_t *p = NULL; 02293 02294 FT_Memory memory = extmemory; 02295 FT_Error error = BDF_Err_Ok; 02296 02297 02298 if ( FT_NEW( p ) ) 02299 goto Exit; 02300 02301 memory = NULL; 02302 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts ); 02303 p->minlb = 32767; 02304 p->memory = extmemory; /* only during font creation */ 02305 02306 _bdf_list_init( &p->list, extmemory ); 02307 02308 error = _bdf_readstream( stream, _bdf_parse_start, 02309 (void *)p, &lineno ); 02310 if ( error ) 02311 goto Fail; 02312 02313 if ( p->font != 0 ) 02314 { 02315 /* If the font is not proportional, set the font's monowidth */ 02316 /* field to the width of the font bounding box. */ 02317 memory = p->font->memory; 02318 02319 if ( p->font->spacing != BDF_PROPORTIONAL ) 02320 p->font->monowidth = p->font->bbx.width; 02321 02322 /* If the number of glyphs loaded is not that of the original count, */ 02323 /* indicate the difference. */ 02324 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used ) 02325 { 02326 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt, 02327 p->font->glyphs_used + p->font->unencoded_used )); 02328 p->font->modified = 1; 02329 } 02330 02331 /* Once the font has been loaded, adjust the overall font metrics if */ 02332 /* necessary. */ 02333 if ( p->opts->correct_metrics != 0 && 02334 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) ) 02335 { 02336 if ( p->maxrb - p->minlb != p->font->bbx.width ) 02337 { 02338 FT_TRACE2(( "bdf_load_font: " ACMSG3, 02339 p->font->bbx.width, p->maxrb - p->minlb )); 02340 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb ); 02341 p->font->modified = 1; 02342 } 02343 02344 if ( p->font->bbx.x_offset != p->minlb ) 02345 { 02346 FT_TRACE2(( "bdf_load_font: " ACMSG4, 02347 p->font->bbx.x_offset, p->minlb )); 02348 p->font->bbx.x_offset = p->minlb; 02349 p->font->modified = 1; 02350 } 02351 02352 if ( p->font->bbx.ascent != p->maxas ) 02353 { 02354 FT_TRACE2(( "bdf_load_font: " ACMSG5, 02355 p->font->bbx.ascent, p->maxas )); 02356 p->font->bbx.ascent = p->maxas; 02357 p->font->modified = 1; 02358 } 02359 02360 if ( p->font->bbx.descent != p->maxds ) 02361 { 02362 FT_TRACE2(( "bdf_load_font: " ACMSG6, 02363 p->font->bbx.descent, p->maxds )); 02364 p->font->bbx.descent = p->maxds; 02365 p->font->bbx.y_offset = (short)( -p->maxds ); 02366 p->font->modified = 1; 02367 } 02368 02369 if ( p->maxas + p->maxds != p->font->bbx.height ) 02370 { 02371 FT_TRACE2(( "bdf_load_font: " ACMSG7, 02372 p->font->bbx.height, p->maxas + p->maxds )); 02373 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds ); 02374 } 02375 02376 if ( p->flags & _BDF_SWIDTH_ADJ ) 02377 FT_TRACE2(( "bdf_load_font: " ACMSG8 )); 02378 } 02379 } 02380 02381 if ( p->flags & _BDF_START ) 02382 { 02383 { 02384 /* The ENDFONT field was never reached or did not exist. */ 02385 if ( !( p->flags & _BDF_GLYPHS ) ) 02386 { 02387 /* Error happened while parsing header. */ 02388 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno )); 02389 error = BDF_Err_Corrupted_Font_Header; 02390 goto Exit; 02391 } 02392 else 02393 { 02394 /* Error happened when parsing glyphs. */ 02395 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno )); 02396 error = BDF_Err_Corrupted_Font_Glyphs; 02397 goto Exit; 02398 } 02399 } 02400 } 02401 02402 if ( p->font != 0 ) 02403 { 02404 /* Make sure the comments are NULL terminated if they exist. */ 02405 memory = p->font->memory; 02406 02407 if ( p->font->comments_len > 0 ) 02408 { 02409 if ( FT_RENEW_ARRAY( p->font->comments, 02410 p->font->comments_len, 02411 p->font->comments_len + 1 ) ) 02412 goto Fail; 02413 02414 p->font->comments[p->font->comments_len] = 0; 02415 } 02416 } 02417 else if ( error == BDF_Err_Ok ) 02418 error = BDF_Err_Invalid_File_Format; 02419 02420 *font = p->font; 02421 02422 Exit: 02423 if ( p ) 02424 { 02425 _bdf_list_done( &p->list ); 02426 02427 memory = extmemory; 02428 02429 FT_FREE( p ); 02430 } 02431 02432 return error; 02433 02434 Fail: 02435 bdf_free_font( p->font ); 02436 02437 memory = extmemory; 02438 02439 FT_FREE( p->font ); 02440 02441 goto Exit; 02442 } 02443 02444 02445 FT_LOCAL_DEF( void ) 02446 bdf_free_font( bdf_font_t* font ) 02447 { 02448 bdf_property_t* prop; 02449 unsigned long i; 02450 bdf_glyph_t* glyphs; 02451 FT_Memory memory; 02452 02453 02454 if ( font == 0 ) 02455 return; 02456 02457 memory = font->memory; 02458 02459 FT_FREE( font->name ); 02460 02461 /* Free up the internal hash table of property names. */ 02462 if ( font->internal ) 02463 { 02464 hash_free( (hashtable *)font->internal, memory ); 02465 FT_FREE( font->internal ); 02466 } 02467 02468 /* Free up the comment info. */ 02469 FT_FREE( font->comments ); 02470 02471 /* Free up the properties. */ 02472 for ( i = 0; i < font->props_size; i++ ) 02473 { 02474 if ( font->props[i].format == BDF_ATOM ) 02475 FT_FREE( font->props[i].value.atom ); 02476 } 02477 02478 FT_FREE( font->props ); 02479 02480 /* Free up the character info. */ 02481 for ( i = 0, glyphs = font->glyphs; 02482 i < font->glyphs_used; i++, glyphs++ ) 02483 { 02484 FT_FREE( glyphs->name ); 02485 FT_FREE( glyphs->bitmap ); 02486 } 02487 02488 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used; 02489 i++, glyphs++ ) 02490 { 02491 FT_FREE( glyphs->name ); 02492 FT_FREE( glyphs->bitmap ); 02493 } 02494 02495 FT_FREE( font->glyphs ); 02496 FT_FREE( font->unencoded ); 02497 02498 /* Free up the overflow storage if it was used. */ 02499 for ( i = 0, glyphs = font->overflow.glyphs; 02500 i < font->overflow.glyphs_used; i++, glyphs++ ) 02501 { 02502 FT_FREE( glyphs->name ); 02503 FT_FREE( glyphs->bitmap ); 02504 } 02505 02506 FT_FREE( font->overflow.glyphs ); 02507 02508 /* bdf_cleanup */ 02509 hash_free( &(font->proptbl), memory ); 02510 02511 /* Free up the user defined properties. */ 02512 for ( prop = font->user_props, i = 0; 02513 i < font->nuser_props; i++, prop++ ) 02514 { 02515 FT_FREE( prop->name ); 02516 if ( prop->format == BDF_ATOM ) 02517 FT_FREE( prop->value.atom ); 02518 } 02519 02520 FT_FREE( font->user_props ); 02521 02522 /* FREE( font ); */ /* XXX Fixme */ 02523 } 02524 02525 02526 FT_LOCAL_DEF( bdf_property_t * ) 02527 bdf_get_font_property( bdf_font_t* font, 02528 const char* name ) 02529 { 02530 hashnode hn; 02531 02532 02533 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 ) 02534 return 0; 02535 02536 hn = hash_lookup( name, (hashtable *)font->internal ); 02537 02538 return hn ? ( font->props + hn->data ) : 0; 02539 } 02540 02541 02542 /* END */ Generated on Sat May 26 2012 04:32:39 for ReactOS by
1.7.6.1
|