PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/src/freetype/src/bdf/bdflib.c

https://bitbucket.org/cabalistic/ogredeps/
C | 2613 lines | 1817 code | 526 blank | 270 comment | 454 complexity | 6e31146d0142cd3803006e5f21d225c8 MD5 | raw file
Possible License(s): LGPL-3.0, BSD-3-Clause, CPL-1.0, Unlicense, GPL-2.0, GPL-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, BSD-2-Clause, LGPL-2.1
  1. /*
  2. * Copyright 2000 Computing Research Labs, New Mexico State University
  3. * Copyright 2001-2012
  4. * Francesco Zappa Nardelli
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the "Software"),
  8. * to deal in the Software without restriction, including without limitation
  9. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10. * and/or sell copies of the Software, and to permit persons to whom the
  11. * Software is furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19. * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
  20. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
  21. * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
  22. * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. */
  24. /*************************************************************************/
  25. /* */
  26. /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
  27. /* */
  28. /* taken from Mark Leisher's xmbdfed package */
  29. /* */
  30. /*************************************************************************/
  31. #include <ft2build.h>
  32. #include FT_FREETYPE_H
  33. #include FT_INTERNAL_DEBUG_H
  34. #include FT_INTERNAL_STREAM_H
  35. #include FT_INTERNAL_OBJECTS_H
  36. #include "bdf.h"
  37. #include "bdferror.h"
  38. /*************************************************************************/
  39. /* */
  40. /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
  41. /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
  42. /* messages during execution. */
  43. /* */
  44. #undef FT_COMPONENT
  45. #define FT_COMPONENT trace_bdflib
  46. /*************************************************************************/
  47. /* */
  48. /* Default BDF font options. */
  49. /* */
  50. /*************************************************************************/
  51. static const bdf_options_t _bdf_opts =
  52. {
  53. 1, /* Correct metrics. */
  54. 1, /* Preserve unencoded glyphs. */
  55. 0, /* Preserve comments. */
  56. BDF_PROPORTIONAL /* Default spacing. */
  57. };
  58. /*************************************************************************/
  59. /* */
  60. /* Builtin BDF font properties. */
  61. /* */
  62. /*************************************************************************/
  63. /* List of most properties that might appear in a font. Doesn't include */
  64. /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
  65. static const bdf_property_t _bdf_properties[] =
  66. {
  67. { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
  68. { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
  69. { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
  70. { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
  71. { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
  72. { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
  73. { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
  74. { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
  75. { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
  76. { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
  77. { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
  78. { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
  79. { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
  80. { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
  81. { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
  82. { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
  83. { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
  84. { (char *)"FONT", BDF_ATOM, 1, { 0 } },
  85. { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
  86. { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
  87. { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
  88. { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
  89. { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
  90. { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
  91. { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
  92. { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
  93. { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
  94. { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
  95. { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
  96. { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
  97. { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
  98. { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
  99. { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
  100. { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
  101. { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
  102. { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
  103. { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
  104. { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
  105. { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
  106. { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
  107. { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
  108. { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
  109. { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
  110. { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
  111. { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
  112. { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
  113. { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
  114. { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
  115. { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
  116. { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
  117. { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
  118. { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
  119. { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
  120. { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
  121. { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
  122. { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
  123. { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
  124. { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
  125. { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
  126. { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
  127. { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
  128. { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
  129. { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
  130. { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
  131. { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
  132. { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
  133. { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
  134. { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
  135. { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
  136. { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
  137. { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
  138. { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
  139. { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
  140. { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
  141. { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
  142. { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
  143. { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
  144. { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
  145. { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
  146. { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
  147. { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
  148. { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
  149. { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
  150. };
  151. static const unsigned long
  152. _num_bdf_properties = sizeof ( _bdf_properties ) /
  153. sizeof ( _bdf_properties[0] );
  154. /* Auto correction messages. */
  155. #define ACMSG1 "FONT_ASCENT property missing. " \
  156. "Added `FONT_ASCENT %hd'.\n"
  157. #define ACMSG2 "FONT_DESCENT property missing. " \
  158. "Added `FONT_DESCENT %hd'.\n"
  159. #define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
  160. #define ACMSG4 "Font left bearing != actual left bearing. " \
  161. "Old: %hd New: %hd.\n"
  162. #define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
  163. #define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
  164. #define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
  165. #define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
  166. #define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
  167. #define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
  168. #define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
  169. #define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
  170. #define ACMSG13 "Glyph %ld extra rows removed.\n"
  171. #define ACMSG14 "Glyph %ld extra columns removed.\n"
  172. #define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
  173. #define ACMSG16 "Glyph %ld missing columns padded with zero bits.\n"
  174. /* Error messages. */
  175. #define ERRMSG1 "[line %ld] Missing `%s' line.\n"
  176. #define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
  177. #define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
  178. #define ERRMSG4 "[line %ld] BBX too big.\n"
  179. #define ERRMSG5 "[line %ld] `%s' value too big.\n"
  180. #define ERRMSG6 "[line %ld] Input line too long.\n"
  181. #define ERRMSG7 "[line %ld] Font name too long.\n"
  182. #define ERRMSG8 "[line %ld] Invalid `%s' value.\n"
  183. #define ERRMSG9 "[line %ld] Invalid keyword.\n"
  184. /* Debug messages. */
  185. #define DBGMSG1 " [%6ld] %s" /* no \n */
  186. #define DBGMSG2 " (0x%lX)\n"
  187. /*************************************************************************/
  188. /* */
  189. /* Hash table utilities for the properties. */
  190. /* */
  191. /*************************************************************************/
  192. /* XXX: Replace this with FreeType's hash functions */
  193. #define INITIAL_HT_SIZE 241
  194. typedef void
  195. (*hash_free_func)( hashnode node );
  196. static hashnode*
  197. hash_bucket( const char* key,
  198. hashtable* ht )
  199. {
  200. const char* kp = key;
  201. unsigned long res = 0;
  202. hashnode* bp = ht->table, *ndp;
  203. /* Mocklisp hash function. */
  204. while ( *kp )
  205. res = ( res << 5 ) - res + *kp++;
  206. ndp = bp + ( res % ht->size );
  207. while ( *ndp )
  208. {
  209. kp = (*ndp)->key;
  210. if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
  211. break;
  212. ndp--;
  213. if ( ndp < bp )
  214. ndp = bp + ( ht->size - 1 );
  215. }
  216. return ndp;
  217. }
  218. static FT_Error
  219. hash_rehash( hashtable* ht,
  220. FT_Memory memory )
  221. {
  222. hashnode* obp = ht->table, *bp, *nbp;
  223. int i, sz = ht->size;
  224. FT_Error error = BDF_Err_Ok;
  225. ht->size <<= 1;
  226. ht->limit = ht->size / 3;
  227. if ( FT_NEW_ARRAY( ht->table, ht->size ) )
  228. goto Exit;
  229. for ( i = 0, bp = obp; i < sz; i++, bp++ )
  230. {
  231. if ( *bp )
  232. {
  233. nbp = hash_bucket( (*bp)->key, ht );
  234. *nbp = *bp;
  235. }
  236. }
  237. FT_FREE( obp );
  238. Exit:
  239. return error;
  240. }
  241. static FT_Error
  242. hash_init( hashtable* ht,
  243. FT_Memory memory )
  244. {
  245. int sz = INITIAL_HT_SIZE;
  246. FT_Error error = BDF_Err_Ok;
  247. ht->size = sz;
  248. ht->limit = sz / 3;
  249. ht->used = 0;
  250. if ( FT_NEW_ARRAY( ht->table, sz ) )
  251. goto Exit;
  252. Exit:
  253. return error;
  254. }
  255. static void
  256. hash_free( hashtable* ht,
  257. FT_Memory memory )
  258. {
  259. if ( ht != 0 )
  260. {
  261. int i, sz = ht->size;
  262. hashnode* bp = ht->table;
  263. for ( i = 0; i < sz; i++, bp++ )
  264. FT_FREE( *bp );
  265. FT_FREE( ht->table );
  266. }
  267. }
  268. static FT_Error
  269. hash_insert( char* key,
  270. size_t data,
  271. hashtable* ht,
  272. FT_Memory memory )
  273. {
  274. hashnode nn, *bp = hash_bucket( key, ht );
  275. FT_Error error = BDF_Err_Ok;
  276. nn = *bp;
  277. if ( !nn )
  278. {
  279. if ( FT_NEW( nn ) )
  280. goto Exit;
  281. *bp = nn;
  282. nn->key = key;
  283. nn->data = data;
  284. if ( ht->used >= ht->limit )
  285. {
  286. error = hash_rehash( ht, memory );
  287. if ( error )
  288. goto Exit;
  289. }
  290. ht->used++;
  291. }
  292. else
  293. nn->data = data;
  294. Exit:
  295. return error;
  296. }
  297. static hashnode
  298. hash_lookup( const char* key,
  299. hashtable* ht )
  300. {
  301. hashnode *np = hash_bucket( key, ht );
  302. return *np;
  303. }
  304. /*************************************************************************/
  305. /* */
  306. /* Utility types and functions. */
  307. /* */
  308. /*************************************************************************/
  309. /* Function type for parsing lines of a BDF font. */
  310. typedef FT_Error
  311. (*_bdf_line_func_t)( char* line,
  312. unsigned long linelen,
  313. unsigned long lineno,
  314. void* call_data,
  315. void* client_data );
  316. /* List structure for splitting lines into fields. */
  317. typedef struct _bdf_list_t_
  318. {
  319. char** field;
  320. unsigned long size;
  321. unsigned long used;
  322. FT_Memory memory;
  323. } _bdf_list_t;
  324. /* Structure used while loading BDF fonts. */
  325. typedef struct _bdf_parse_t_
  326. {
  327. unsigned long flags;
  328. unsigned long cnt;
  329. unsigned long row;
  330. short minlb;
  331. short maxlb;
  332. short maxrb;
  333. short maxas;
  334. short maxds;
  335. short rbearing;
  336. char* glyph_name;
  337. long glyph_enc;
  338. bdf_font_t* font;
  339. bdf_options_t* opts;
  340. unsigned long have[34816]; /* must be in sync with `nmod' and `umod' */
  341. /* arrays from `bdf_font_t' structure */
  342. _bdf_list_t list;
  343. FT_Memory memory;
  344. } _bdf_parse_t;
  345. #define setsbit( m, cc ) \
  346. ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
  347. #define sbitset( m, cc ) \
  348. ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
  349. static void
  350. _bdf_list_init( _bdf_list_t* list,
  351. FT_Memory memory )
  352. {
  353. FT_ZERO( list );
  354. list->memory = memory;
  355. }
  356. static void
  357. _bdf_list_done( _bdf_list_t* list )
  358. {
  359. FT_Memory memory = list->memory;
  360. if ( memory )
  361. {
  362. FT_FREE( list->field );
  363. FT_ZERO( list );
  364. }
  365. }
  366. static FT_Error
  367. _bdf_list_ensure( _bdf_list_t* list,
  368. unsigned long num_items ) /* same as _bdf_list_t.used */
  369. {
  370. FT_Error error = BDF_Err_Ok;
  371. if ( num_items > list->size )
  372. {
  373. unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
  374. unsigned long newsize = oldsize + ( oldsize >> 1 ) + 5;
  375. unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
  376. FT_Memory memory = list->memory;
  377. if ( oldsize == bigsize )
  378. {
  379. error = BDF_Err_Out_Of_Memory;
  380. goto Exit;
  381. }
  382. else if ( newsize < oldsize || newsize > bigsize )
  383. newsize = bigsize;
  384. if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
  385. goto Exit;
  386. list->size = newsize;
  387. }
  388. Exit:
  389. return error;
  390. }
  391. static void
  392. _bdf_list_shift( _bdf_list_t* list,
  393. unsigned long n )
  394. {
  395. unsigned long i, u;
  396. if ( list == 0 || list->used == 0 || n == 0 )
  397. return;
  398. if ( n >= list->used )
  399. {
  400. list->used = 0;
  401. return;
  402. }
  403. for ( u = n, i = 0; u < list->used; i++, u++ )
  404. list->field[i] = list->field[u];
  405. list->used -= n;
  406. }
  407. /* An empty string for empty fields. */
  408. static const char empty[1] = { 0 }; /* XXX eliminate this */
  409. static char *
  410. _bdf_list_join( _bdf_list_t* list,
  411. int c,
  412. unsigned long *alen )
  413. {
  414. unsigned long i, j;
  415. char *fp, *dp;
  416. *alen = 0;
  417. if ( list == 0 || list->used == 0 )
  418. return 0;
  419. dp = list->field[0];
  420. for ( i = j = 0; i < list->used; i++ )
  421. {
  422. fp = list->field[i];
  423. while ( *fp )
  424. dp[j++] = *fp++;
  425. if ( i + 1 < list->used )
  426. dp[j++] = (char)c;
  427. }
  428. if ( dp != empty )
  429. dp[j] = 0;
  430. *alen = j;
  431. return dp;
  432. }
  433. /* The code below ensures that we have at least 4 + 1 `field' */
  434. /* elements in `list' (which are possibly NULL) so that we */
  435. /* don't have to check the number of fields in most cases. */
  436. static FT_Error
  437. _bdf_list_split( _bdf_list_t* list,
  438. char* separators,
  439. char* line,
  440. unsigned long linelen )
  441. {
  442. int mult, final_empty;
  443. char *sp, *ep, *end;
  444. char seps[32];
  445. FT_Error error = BDF_Err_Ok;
  446. /* Initialize the list. */
  447. list->used = 0;
  448. if ( list->size )
  449. {
  450. list->field[0] = (char*)empty;
  451. list->field[1] = (char*)empty;
  452. list->field[2] = (char*)empty;
  453. list->field[3] = (char*)empty;
  454. }
  455. /* If the line is empty, then simply return. */
  456. if ( linelen == 0 || line[0] == 0 )
  457. goto Exit;
  458. /* In the original code, if the `separators' parameter is NULL or */
  459. /* empty, the list is split into individual bytes. We don't need */
  460. /* this, so an error is signaled. */
  461. if ( separators == 0 || *separators == 0 )
  462. {
  463. error = BDF_Err_Invalid_Argument;
  464. goto Exit;
  465. }
  466. /* Prepare the separator bitmap. */
  467. FT_MEM_ZERO( seps, 32 );
  468. /* If the very last character of the separator string is a plus, then */
  469. /* set the `mult' flag to indicate that multiple separators should be */
  470. /* collapsed into one. */
  471. for ( mult = 0, sp = separators; sp && *sp; sp++ )
  472. {
  473. if ( *sp == '+' && *( sp + 1 ) == 0 )
  474. mult = 1;
  475. else
  476. setsbit( seps, *sp );
  477. }
  478. /* Break the line up into fields. */
  479. for ( final_empty = 0, sp = ep = line, end = sp + linelen;
  480. sp < end && *sp; )
  481. {
  482. /* Collect everything that is not a separator. */
  483. for ( ; *ep && !sbitset( seps, *ep ); ep++ )
  484. ;
  485. /* Resize the list if necessary. */
  486. if ( list->used == list->size )
  487. {
  488. error = _bdf_list_ensure( list, list->used + 1 );
  489. if ( error )
  490. goto Exit;
  491. }
  492. /* Assign the field appropriately. */
  493. list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
  494. sp = ep;
  495. if ( mult )
  496. {
  497. /* If multiple separators should be collapsed, do it now by */
  498. /* setting all the separator characters to 0. */
  499. for ( ; *ep && sbitset( seps, *ep ); ep++ )
  500. *ep = 0;
  501. }
  502. else if ( *ep != 0 )
  503. /* Don't collapse multiple separators by making them 0, so just */
  504. /* make the one encountered 0. */
  505. *ep++ = 0;
  506. final_empty = ( ep > sp && *ep == 0 );
  507. sp = ep;
  508. }
  509. /* Finally, NULL-terminate the list. */
  510. if ( list->used + final_empty >= list->size )
  511. {
  512. error = _bdf_list_ensure( list, list->used + final_empty + 1 );
  513. if ( error )
  514. goto Exit;
  515. }
  516. if ( final_empty )
  517. list->field[list->used++] = (char*)empty;
  518. list->field[list->used] = 0;
  519. Exit:
  520. return error;
  521. }
  522. #define NO_SKIP 256 /* this value cannot be stored in a 'char' */
  523. static FT_Error
  524. _bdf_readstream( FT_Stream stream,
  525. _bdf_line_func_t callback,
  526. void* client_data,
  527. unsigned long *lno )
  528. {
  529. _bdf_line_func_t cb;
  530. unsigned long lineno, buf_size;
  531. int refill, hold, to_skip;
  532. ptrdiff_t bytes, start, end, cursor, avail;
  533. char* buf = 0;
  534. FT_Memory memory = stream->memory;
  535. FT_Error error = BDF_Err_Ok;
  536. if ( callback == 0 )
  537. {
  538. error = BDF_Err_Invalid_Argument;
  539. goto Exit;
  540. }
  541. /* initial size and allocation of the input buffer */
  542. buf_size = 1024;
  543. if ( FT_NEW_ARRAY( buf, buf_size ) )
  544. goto Exit;
  545. cb = callback;
  546. lineno = 1;
  547. buf[0] = 0;
  548. start = 0;
  549. end = 0;
  550. avail = 0;
  551. cursor = 0;
  552. refill = 1;
  553. to_skip = NO_SKIP;
  554. bytes = 0; /* make compiler happy */
  555. for (;;)
  556. {
  557. if ( refill )
  558. {
  559. bytes = (ptrdiff_t)FT_Stream_TryRead(
  560. stream, (FT_Byte*)buf + cursor,
  561. (FT_ULong)( buf_size - cursor ) );
  562. avail = cursor + bytes;
  563. cursor = 0;
  564. refill = 0;
  565. }
  566. end = start;
  567. /* should we skip an optional character like \n or \r? */
  568. if ( start < avail && buf[start] == to_skip )
  569. {
  570. start += 1;
  571. to_skip = NO_SKIP;
  572. continue;
  573. }
  574. /* try to find the end of the line */
  575. while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
  576. end++;
  577. /* if we hit the end of the buffer, try shifting its content */
  578. /* or even resizing it */
  579. if ( end >= avail )
  580. {
  581. if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
  582. break; /* ignore it then exit */
  583. if ( start == 0 )
  584. {
  585. /* this line is definitely too long; try resizing the input */
  586. /* buffer a bit to handle it. */
  587. FT_ULong new_size;
  588. if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
  589. {
  590. FT_ERROR(( "_bdf_readstream: " ERRMSG6, lineno ));
  591. error = BDF_Err_Invalid_Argument;
  592. goto Exit;
  593. }
  594. new_size = buf_size * 2;
  595. if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
  596. goto Exit;
  597. cursor = buf_size;
  598. buf_size = new_size;
  599. }
  600. else
  601. {
  602. bytes = avail - start;
  603. FT_MEM_COPY( buf, buf + start, bytes );
  604. cursor = bytes;
  605. avail -= bytes;
  606. start = 0;
  607. }
  608. refill = 1;
  609. continue;
  610. }
  611. /* Temporarily NUL-terminate the line. */
  612. hold = buf[end];
  613. buf[end] = 0;
  614. /* XXX: Use encoding independent value for 0x1a */
  615. if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
  616. {
  617. error = (*cb)( buf + start, end - start, lineno,
  618. (void*)&cb, client_data );
  619. /* Redo if we have encountered CHARS without properties. */
  620. if ( error == -1 )
  621. error = (*cb)( buf + start, end - start, lineno,
  622. (void*)&cb, client_data );
  623. if ( error )
  624. break;
  625. }
  626. lineno += 1;
  627. buf[end] = (char)hold;
  628. start = end + 1;
  629. if ( hold == '\n' )
  630. to_skip = '\r';
  631. else if ( hold == '\r' )
  632. to_skip = '\n';
  633. else
  634. to_skip = NO_SKIP;
  635. }
  636. *lno = lineno;
  637. Exit:
  638. FT_FREE( buf );
  639. return error;
  640. }
  641. /* XXX: make this work with EBCDIC also */
  642. static const unsigned char a2i[128] =
  643. {
  644. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  645. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  646. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  647. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  648. 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
  649. 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
  650. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  651. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  652. 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
  653. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  654. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  655. };
  656. static const unsigned char odigits[32] =
  657. {
  658. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
  659. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  660. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  661. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  662. };
  663. static const unsigned char ddigits[32] =
  664. {
  665. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
  666. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  667. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  668. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  669. };
  670. static const unsigned char hdigits[32] =
  671. {
  672. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
  673. 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
  674. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  675. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  676. };
  677. #define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
  678. /* Routine to convert an ASCII string into an unsigned long integer. */
  679. static unsigned long
  680. _bdf_atoul( char* s,
  681. char** end,
  682. int base )
  683. {
  684. unsigned long v;
  685. const unsigned char* dmap;
  686. if ( s == 0 || *s == 0 )
  687. return 0;
  688. /* Make sure the radix is something recognizable. Default to 10. */
  689. switch ( base )
  690. {
  691. case 8:
  692. dmap = odigits;
  693. break;
  694. case 16:
  695. dmap = hdigits;
  696. break;
  697. default:
  698. base = 10;
  699. dmap = ddigits;
  700. break;
  701. }
  702. /* Check for the special hex prefix. */
  703. if ( *s == '0' &&
  704. ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
  705. {
  706. base = 16;
  707. dmap = hdigits;
  708. s += 2;
  709. }
  710. for ( v = 0; isdigok( dmap, *s ); s++ )
  711. v = v * base + a2i[(int)*s];
  712. if ( end != 0 )
  713. *end = s;
  714. return v;
  715. }
  716. /* Routine to convert an ASCII string into an signed long integer. */
  717. static long
  718. _bdf_atol( char* s,
  719. char** end,
  720. int base )
  721. {
  722. long v, neg;
  723. const unsigned char* dmap;
  724. if ( s == 0 || *s == 0 )
  725. return 0;
  726. /* Make sure the radix is something recognizable. Default to 10. */
  727. switch ( base )
  728. {
  729. case 8:
  730. dmap = odigits;
  731. break;
  732. case 16:
  733. dmap = hdigits;
  734. break;
  735. default:
  736. base = 10;
  737. dmap = ddigits;
  738. break;
  739. }
  740. /* Check for a minus sign. */
  741. neg = 0;
  742. if ( *s == '-' )
  743. {
  744. s++;
  745. neg = 1;
  746. }
  747. /* Check for the special hex prefix. */
  748. if ( *s == '0' &&
  749. ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
  750. {
  751. base = 16;
  752. dmap = hdigits;
  753. s += 2;
  754. }
  755. for ( v = 0; isdigok( dmap, *s ); s++ )
  756. v = v * base + a2i[(int)*s];
  757. if ( end != 0 )
  758. *end = s;
  759. return ( !neg ) ? v : -v;
  760. }
  761. /* Routine to convert an ASCII string into an signed short integer. */
  762. static short
  763. _bdf_atos( char* s,
  764. char** end,
  765. int base )
  766. {
  767. short v, neg;
  768. const unsigned char* dmap;
  769. if ( s == 0 || *s == 0 )
  770. return 0;
  771. /* Make sure the radix is something recognizable. Default to 10. */
  772. switch ( base )
  773. {
  774. case 8:
  775. dmap = odigits;
  776. break;
  777. case 16:
  778. dmap = hdigits;
  779. break;
  780. default:
  781. base = 10;
  782. dmap = ddigits;
  783. break;
  784. }
  785. /* Check for a minus. */
  786. neg = 0;
  787. if ( *s == '-' )
  788. {
  789. s++;
  790. neg = 1;
  791. }
  792. /* Check for the special hex prefix. */
  793. if ( *s == '0' &&
  794. ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
  795. {
  796. base = 16;
  797. dmap = hdigits;
  798. s += 2;
  799. }
  800. for ( v = 0; isdigok( dmap, *s ); s++ )
  801. v = (short)( v * base + a2i[(int)*s] );
  802. if ( end != 0 )
  803. *end = s;
  804. return (short)( ( !neg ) ? v : -v );
  805. }
  806. /* Routine to compare two glyphs by encoding so they can be sorted. */
  807. static int
  808. by_encoding( const void* a,
  809. const void* b )
  810. {
  811. bdf_glyph_t *c1, *c2;
  812. c1 = (bdf_glyph_t *)a;
  813. c2 = (bdf_glyph_t *)b;
  814. if ( c1->encoding < c2->encoding )
  815. return -1;
  816. if ( c1->encoding > c2->encoding )
  817. return 1;
  818. return 0;
  819. }
  820. static FT_Error
  821. bdf_create_property( char* name,
  822. int format,
  823. bdf_font_t* font )
  824. {
  825. size_t n;
  826. bdf_property_t* p;
  827. FT_Memory memory = font->memory;
  828. FT_Error error = BDF_Err_Ok;
  829. /* First check whether the property has */
  830. /* already been added or not. If it has, then */
  831. /* simply ignore it. */
  832. if ( hash_lookup( name, &(font->proptbl) ) )
  833. goto Exit;
  834. if ( FT_RENEW_ARRAY( font->user_props,
  835. font->nuser_props,
  836. font->nuser_props + 1 ) )
  837. goto Exit;
  838. p = font->user_props + font->nuser_props;
  839. FT_ZERO( p );
  840. n = ft_strlen( name ) + 1;
  841. if ( n > FT_ULONG_MAX )
  842. return BDF_Err_Invalid_Argument;
  843. if ( FT_NEW_ARRAY( p->name, n ) )
  844. goto Exit;
  845. FT_MEM_COPY( (char *)p->name, name, n );
  846. p->format = format;
  847. p->builtin = 0;
  848. n = _num_bdf_properties + font->nuser_props;
  849. error = hash_insert( p->name, n, &(font->proptbl), memory );
  850. if ( error )
  851. goto Exit;
  852. font->nuser_props++;
  853. Exit:
  854. return error;
  855. }
  856. FT_LOCAL_DEF( bdf_property_t * )
  857. bdf_get_property( char* name,
  858. bdf_font_t* font )
  859. {
  860. hashnode hn;
  861. size_t propid;
  862. if ( name == 0 || *name == 0 )
  863. return 0;
  864. if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
  865. return 0;
  866. propid = hn->data;
  867. if ( propid >= _num_bdf_properties )
  868. return font->user_props + ( propid - _num_bdf_properties );
  869. return (bdf_property_t*)_bdf_properties + propid;
  870. }
  871. /*************************************************************************/
  872. /* */
  873. /* BDF font file parsing flags and functions. */
  874. /* */
  875. /*************************************************************************/
  876. /* Parse flags. */
  877. #define _BDF_START 0x0001
  878. #define _BDF_FONT_NAME 0x0002
  879. #define _BDF_SIZE 0x0004
  880. #define _BDF_FONT_BBX 0x0008
  881. #define _BDF_PROPS 0x0010
  882. #define _BDF_GLYPHS 0x0020
  883. #define _BDF_GLYPH 0x0040
  884. #define _BDF_ENCODING 0x0080
  885. #define _BDF_SWIDTH 0x0100
  886. #define _BDF_DWIDTH 0x0200
  887. #define _BDF_BBX 0x0400
  888. #define _BDF_BITMAP 0x0800
  889. #define _BDF_SWIDTH_ADJ 0x1000
  890. #define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
  891. _BDF_ENCODING | \
  892. _BDF_SWIDTH | \
  893. _BDF_DWIDTH | \
  894. _BDF_BBX | \
  895. _BDF_BITMAP )
  896. #define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
  897. #define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
  898. static FT_Error
  899. _bdf_add_comment( bdf_font_t* font,
  900. char* comment,
  901. unsigned long len )
  902. {
  903. char* cp;
  904. FT_Memory memory = font->memory;
  905. FT_Error error = BDF_Err_Ok;
  906. if ( FT_RENEW_ARRAY( font->comments,
  907. font->comments_len,
  908. font->comments_len + len + 1 ) )
  909. goto Exit;
  910. cp = font->comments + font->comments_len;
  911. FT_MEM_COPY( cp, comment, len );
  912. cp[len] = '\n';
  913. font->comments_len += len + 1;
  914. Exit:
  915. return error;
  916. }
  917. /* Set the spacing from the font name if it exists, or set it to the */
  918. /* default specified in the options. */
  919. static FT_Error
  920. _bdf_set_default_spacing( bdf_font_t* font,
  921. bdf_options_t* opts,
  922. unsigned long lineno )
  923. {
  924. size_t len;
  925. char name[256];
  926. _bdf_list_t list;
  927. FT_Memory memory;
  928. FT_Error error = BDF_Err_Ok;
  929. if ( font == 0 || font->name == 0 || font->name[0] == 0 )
  930. {
  931. error = BDF_Err_Invalid_Argument;
  932. goto Exit;
  933. }
  934. memory = font->memory;
  935. _bdf_list_init( &list, memory );
  936. font->spacing = opts->font_spacing;
  937. len = ft_strlen( font->name ) + 1;
  938. /* Limit ourselves to 256 characters in the font name. */
  939. if ( len >= 256 )
  940. {
  941. FT_ERROR(( "_bdf_set_default_spacing: " ERRMSG7, lineno ));
  942. error = BDF_Err_Invalid_Argument;
  943. goto Exit;
  944. }
  945. FT_MEM_COPY( name, font->name, len );
  946. error = _bdf_list_split( &list, (char *)"-", name, len );
  947. if ( error )
  948. goto Fail;
  949. if ( list.used == 15 )
  950. {
  951. switch ( list.field[11][0] )
  952. {
  953. case 'C':
  954. case 'c':
  955. font->spacing = BDF_CHARCELL;
  956. break;
  957. case 'M':
  958. case 'm':
  959. font->spacing = BDF_MONOWIDTH;
  960. break;
  961. case 'P':
  962. case 'p':
  963. font->spacing = BDF_PROPORTIONAL;
  964. break;
  965. }
  966. }
  967. Fail:
  968. _bdf_list_done( &list );
  969. Exit:
  970. return error;
  971. }
  972. /* Determine whether the property is an atom or not. If it is, then */
  973. /* clean it up so the double quotes are removed if they exist. */
  974. static int
  975. _bdf_is_atom( char* line,
  976. unsigned long linelen,
  977. char** name,
  978. char** value,
  979. bdf_font_t* font )
  980. {
  981. int hold;
  982. char *sp, *ep;
  983. bdf_property_t* p;
  984. *name = sp = ep = line;
  985. while ( *ep && *ep != ' ' && *ep != '\t' )
  986. ep++;
  987. hold = -1;
  988. if ( *ep )
  989. {
  990. hold = *ep;
  991. *ep = 0;
  992. }
  993. p = bdf_get_property( sp, font );
  994. /* Restore the character that was saved before any return can happen. */
  995. if ( hold != -1 )
  996. *ep = (char)hold;
  997. /* If the property exists and is not an atom, just return here. */
  998. if ( p && p->format != BDF_ATOM )
  999. return 0;
  1000. /* The property is an atom. Trim all leading and trailing whitespace */
  1001. /* and double quotes for the atom value. */
  1002. sp = ep;
  1003. ep = line + linelen;
  1004. /* Trim the leading whitespace if it exists. */
  1005. if ( *sp )
  1006. *sp++ = 0;
  1007. while ( *sp &&
  1008. ( *sp == ' ' || *sp == '\t' ) )
  1009. sp++;
  1010. /* Trim the leading double quote if it exists. */
  1011. if ( *sp == '"' )
  1012. sp++;
  1013. *value = sp;
  1014. /* Trim the trailing whitespace if it exists. */
  1015. while ( ep > sp &&
  1016. ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
  1017. *--ep = 0;
  1018. /* Trim the trailing double quote if it exists. */
  1019. if ( ep > sp && *( ep - 1 ) == '"' )
  1020. *--ep = 0;
  1021. return 1;
  1022. }
  1023. static FT_Error
  1024. _bdf_add_property( bdf_font_t* font,
  1025. char* name,
  1026. char* value,
  1027. unsigned long lineno )
  1028. {
  1029. size_t propid;
  1030. hashnode hn;
  1031. bdf_property_t *prop, *fp;
  1032. FT_Memory memory = font->memory;
  1033. FT_Error error = BDF_Err_Ok;
  1034. /* First, check whether the property already exists in the font. */
  1035. if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
  1036. {
  1037. /* The property already exists in the font, so simply replace */
  1038. /* the value of the property with the current value. */
  1039. fp = font->props + hn->data;
  1040. switch ( fp->format )
  1041. {
  1042. case BDF_ATOM:
  1043. /* Delete the current atom if it exists. */
  1044. FT_FREE( fp->value.atom );
  1045. if ( value && value[0] != 0 )
  1046. {
  1047. if ( FT_STRDUP( fp->value.atom, value ) )
  1048. goto Exit;
  1049. }
  1050. break;
  1051. case BDF_INTEGER:
  1052. fp->value.l = _bdf_atol( value, 0, 10 );
  1053. break;
  1054. case BDF_CARDINAL:
  1055. fp->value.ul = _bdf_atoul( value, 0, 10 );
  1056. break;
  1057. default:
  1058. ;
  1059. }
  1060. goto Exit;
  1061. }
  1062. /* See whether this property type exists yet or not. */
  1063. /* If not, create it. */
  1064. hn = hash_lookup( name, &(font->proptbl) );
  1065. if ( hn == 0 )
  1066. {
  1067. error = bdf_create_property( name, BDF_ATOM, font );
  1068. if ( error )
  1069. goto Exit;
  1070. hn = hash_lookup( name, &(font->proptbl) );
  1071. }
  1072. /* Allocate another property if this is overflow. */
  1073. if ( font->props_used == font->props_size )
  1074. {
  1075. if ( font->props_size == 0 )
  1076. {
  1077. if ( FT_NEW_ARRAY( font->props, 1 ) )
  1078. goto Exit;
  1079. }
  1080. else
  1081. {
  1082. if ( FT_RENEW_ARRAY( font->props,
  1083. font->props_size,
  1084. font->props_size + 1 ) )
  1085. goto Exit;
  1086. }
  1087. fp = font->props + font->props_size;
  1088. FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
  1089. font->props_size++;
  1090. }
  1091. propid = hn->data;
  1092. if ( propid >= _num_bdf_properties )
  1093. prop = font->user_props + ( propid - _num_bdf_properties );
  1094. else
  1095. prop = (bdf_property_t*)_bdf_properties + propid;
  1096. fp = font->props + font->props_used;
  1097. fp->name = prop->name;
  1098. fp->format = prop->format;
  1099. fp->builtin = prop->builtin;
  1100. switch ( prop->format )
  1101. {
  1102. case BDF_ATOM:
  1103. fp->value.atom = 0;
  1104. if ( value != 0 && value[0] )
  1105. {
  1106. if ( FT_STRDUP( fp->value.atom, value ) )
  1107. goto Exit;
  1108. }
  1109. break;
  1110. case BDF_INTEGER:
  1111. fp->value.l = _bdf_atol( value, 0, 10 );
  1112. break;
  1113. case BDF_CARDINAL:
  1114. fp->value.ul = _bdf_atoul( value, 0, 10 );
  1115. break;
  1116. }
  1117. /* If the property happens to be a comment, then it doesn't need */
  1118. /* to be added to the internal hash table. */
  1119. if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
  1120. {
  1121. /* Add the property to the font property table. */
  1122. error = hash_insert( fp->name,
  1123. font->props_used,
  1124. (hashtable *)font->internal,
  1125. memory );
  1126. if ( error )
  1127. goto Exit;
  1128. }
  1129. font->props_used++;
  1130. /* Some special cases need to be handled here. The DEFAULT_CHAR */
  1131. /* property needs to be located if it exists in the property list, the */
  1132. /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
  1133. /* present, and the SPACING property should override the default */
  1134. /* spacing. */
  1135. if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
  1136. font->default_char = fp->value.l;
  1137. else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
  1138. font->font_ascent = fp->value.l;
  1139. else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
  1140. font->font_descent = fp->value.l;
  1141. else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
  1142. {
  1143. if ( !fp->value.atom )
  1144. {
  1145. FT_ERROR(( "_bdf_add_property: " ERRMSG8, lineno, "SPACING" ));
  1146. error = BDF_Err_Invalid_File_Format;
  1147. goto Exit;
  1148. }
  1149. if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
  1150. font->spacing = BDF_PROPORTIONAL;
  1151. else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
  1152. font->spacing = BDF_MONOWIDTH;
  1153. else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
  1154. font->spacing = BDF_CHARCELL;
  1155. }
  1156. Exit:
  1157. return error;
  1158. }
  1159. static const unsigned char nibble_mask[8] =
  1160. {
  1161. 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
  1162. };
  1163. /* Actually parse the glyph info and bitmaps. */
  1164. static FT_Error
  1165. _bdf_parse_glyphs( char* line,
  1166. unsigned long linelen,
  1167. unsigned long lineno,
  1168. void* call_data,
  1169. void* client_data )
  1170. {
  1171. int c, mask_index;
  1172. char* s;
  1173. unsigned char* bp;
  1174. unsigned long i, slen, nibbles;
  1175. _bdf_parse_t* p;
  1176. bdf_glyph_t* glyph;
  1177. bdf_font_t* font;
  1178. FT_Memory memory;
  1179. FT_Error error = BDF_Err_Ok;
  1180. FT_UNUSED( call_data );
  1181. FT_UNUSED( lineno ); /* only used in debug mode */
  1182. p = (_bdf_parse_t *)client_data;
  1183. font = p->font;
  1184. memory = font->memory;
  1185. /* Check for a comment. */
  1186. if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
  1187. {
  1188. linelen -= 7;
  1189. s = line + 7;
  1190. if ( *s != 0 )
  1191. {
  1192. s++;
  1193. linelen--;
  1194. }
  1195. error = _bdf_add_comment( p->font, s, linelen );
  1196. goto Exit;
  1197. }
  1198. /* The very first thing expected is the number of glyphs. */
  1199. if ( !( p->flags & _BDF_GLYPHS ) )
  1200. {
  1201. if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
  1202. {
  1203. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
  1204. error = BDF_Err_Missing_Chars_Field;
  1205. goto Exit;
  1206. }
  1207. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1208. if ( error )
  1209. goto Exit;
  1210. p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
  1211. /* Make sure the number of glyphs is non-zero. */
  1212. if ( p->cnt == 0 )
  1213. font->glyphs_size = 64;
  1214. /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
  1215. /* number of code points available in Unicode). */
  1216. if ( p->cnt >= 0x110000UL )
  1217. {
  1218. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "CHARS" ));
  1219. error = BDF_Err_Invalid_Argument;
  1220. goto Exit;
  1221. }
  1222. if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
  1223. goto Exit;
  1224. p->flags |= _BDF_GLYPHS;
  1225. goto Exit;
  1226. }
  1227. /* Check for the ENDFONT field. */
  1228. if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
  1229. {
  1230. /* Sort the glyphs by encoding. */
  1231. ft_qsort( (char *)font->glyphs,
  1232. font->glyphs_used,
  1233. sizeof ( bdf_glyph_t ),
  1234. by_encoding );
  1235. p->flags &= ~_BDF_START;
  1236. goto Exit;
  1237. }
  1238. /* Check for the ENDCHAR field. */
  1239. if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
  1240. {
  1241. p->glyph_enc = 0;
  1242. p->flags &= ~_BDF_GLYPH_BITS;
  1243. goto Exit;
  1244. }
  1245. /* Check whether a glyph is being scanned but should be */
  1246. /* ignored because it is an unencoded glyph. */
  1247. if ( ( p->flags & _BDF_GLYPH ) &&
  1248. p->glyph_enc == -1 &&
  1249. p->opts->keep_unencoded == 0 )
  1250. goto Exit;
  1251. /* Check for the STARTCHAR field. */
  1252. if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
  1253. {
  1254. /* Set the character name in the parse info first until the */
  1255. /* encoding can be checked for an unencoded character. */
  1256. FT_FREE( p->glyph_name );
  1257. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1258. if ( error )
  1259. goto Exit;
  1260. _bdf_list_shift( &p->list, 1 );
  1261. s = _bdf_list_join( &p->list, ' ', &slen );
  1262. if ( !s )
  1263. {
  1264. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG8, lineno, "STARTCHAR" ));
  1265. error = BDF_Err_Invalid_File_Format;
  1266. goto Exit;
  1267. }
  1268. if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
  1269. goto Exit;
  1270. FT_MEM_COPY( p->glyph_name, s, slen + 1 );
  1271. p->flags |= _BDF_GLYPH;
  1272. FT_TRACE4(( DBGMSG1, lineno, s ));
  1273. goto Exit;
  1274. }
  1275. /* Check for the ENCODING field. */
  1276. if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
  1277. {
  1278. if ( !( p->flags & _BDF_GLYPH ) )
  1279. {
  1280. /* Missing STARTCHAR field. */
  1281. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
  1282. error = BDF_Err_Missing_Startchar_Field;
  1283. goto Exit;
  1284. }
  1285. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1286. if ( error )
  1287. goto Exit;
  1288. p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
  1289. /* Normalize negative encoding values. The specification only */
  1290. /* allows -1, but we can be more generous here. */
  1291. if ( p->glyph_enc < -1 )
  1292. p->glyph_enc = -1;
  1293. /* Check for alternative encoding format. */
  1294. if ( p->glyph_enc == -1 && p->list.used > 2 )
  1295. p->glyph_enc = _bdf_atol( p->list.field[2], 0, 10 );
  1296. FT_TRACE4(( DBGMSG2, p->glyph_enc ));
  1297. /* Check that the encoding is in the Unicode range because */
  1298. /* otherwise p->have (a bitmap with static size) overflows. */
  1299. if ( p->glyph_enc > 0 &&
  1300. (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
  1301. {
  1302. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG5, lineno, "ENCODING" ));
  1303. error = BDF_Err_Invalid_File_Format;
  1304. goto Exit;
  1305. }
  1306. /* Check whether this encoding has already been encountered. */
  1307. /* If it has then change it to unencoded so it gets added if */
  1308. /* indicated. */
  1309. if ( p->glyph_enc >= 0 )
  1310. {
  1311. if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
  1312. {
  1313. /* Emit a message saying a glyph has been moved to the */
  1314. /* unencoded area. */
  1315. FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
  1316. p->glyph_enc, p->glyph_name ));
  1317. p->glyph_enc = -1;
  1318. font->modified = 1;
  1319. }
  1320. else
  1321. _bdf_set_glyph_modified( p->have, p->glyph_enc );
  1322. }
  1323. if ( p->glyph_enc >= 0 )
  1324. {
  1325. /* Make sure there are enough glyphs allocated in case the */
  1326. /* number of characters happen to be wrong. */
  1327. if ( font->glyphs_used == font->glyphs_size )
  1328. {
  1329. if ( FT_RENEW_ARRAY( font->glyphs,
  1330. font->glyphs_size,
  1331. font->glyphs_size + 64 ) )
  1332. goto Exit;
  1333. font->glyphs_size += 64;
  1334. }
  1335. glyph = font->glyphs + font->glyphs_used++;
  1336. glyph->name = p->glyph_name;
  1337. glyph->encoding = p->glyph_enc;
  1338. /* Reset the initial glyph info. */
  1339. p->glyph_name = 0;
  1340. }
  1341. else
  1342. {
  1343. /* Unencoded glyph. Check whether it should */
  1344. /* be added or not. */
  1345. if ( p->opts->keep_unencoded != 0 )
  1346. {
  1347. /* Allocate the next unencoded glyph. */
  1348. if ( font->unencoded_used == font->unencoded_size )
  1349. {
  1350. if ( FT_RENEW_ARRAY( font->unencoded ,
  1351. font->unencoded_size,
  1352. font->unencoded_size + 4 ) )
  1353. goto Exit;
  1354. font->unencoded_size += 4;
  1355. }
  1356. glyph = font->unencoded + font->unencoded_used;
  1357. glyph->name = p->glyph_name;
  1358. glyph->encoding = font->unencoded_used++;
  1359. }
  1360. else
  1361. /* Free up the glyph name if the unencoded shouldn't be */
  1362. /* kept. */
  1363. FT_FREE( p->glyph_name );
  1364. p->glyph_name = 0;
  1365. }
  1366. /* Clear the flags that might be added when width and height are */
  1367. /* checked for consistency. */
  1368. p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
  1369. p->flags |= _BDF_ENCODING;
  1370. goto Exit;
  1371. }
  1372. /* Point at the glyph being constructed. */
  1373. if ( p->glyph_enc == -1 )
  1374. glyph = font->unencoded + ( font->unencoded_used - 1 );
  1375. else
  1376. glyph = font->glyphs + ( font->glyphs_used - 1 );
  1377. /* Check whether a bitmap is being constructed. */
  1378. if ( p->flags & _BDF_BITMAP )
  1379. {
  1380. /* If there are more rows than are specified in the glyph metrics, */
  1381. /* ignore the remaining lines. */
  1382. if ( p->row >= (unsigned long)glyph->bbx.height )
  1383. {
  1384. if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
  1385. {
  1386. FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
  1387. p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
  1388. font->modified = 1;
  1389. }
  1390. goto Exit;
  1391. }
  1392. /* Only collect the number of nibbles indicated by the glyph */
  1393. /* metrics. If there are more columns, they are simply ignored. */
  1394. nibbles = glyph->bpr << 1;
  1395. bp = glyph->bitmap + p->row * glyph->bpr;
  1396. for ( i = 0; i < nibbles; i++ )
  1397. {
  1398. c = line[i];
  1399. if ( !isdigok( hdigits, c ) )
  1400. break;
  1401. *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
  1402. if ( i + 1 < nibbles && ( i & 1 ) )
  1403. *++bp = 0;
  1404. }
  1405. /* If any line has not enough columns, */
  1406. /* indicate they have been padded with zero bits. */
  1407. if ( i < nibbles &&
  1408. !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
  1409. {
  1410. FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG16, glyph->encoding ));
  1411. p->flags |= _BDF_GLYPH_WIDTH_CHECK;
  1412. font->modified = 1;
  1413. }
  1414. /* Remove possible garbage at the right. */
  1415. mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
  1416. if ( glyph->bbx.width )
  1417. *bp &= nibble_mask[mask_index];
  1418. /* If any line has extra columns, indicate they have been removed. */
  1419. if ( i == nibbles &&
  1420. isdigok( hdigits, line[nibbles] ) &&
  1421. !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
  1422. {
  1423. FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
  1424. p->flags |= _BDF_GLYPH_WIDTH_CHECK;
  1425. font->modified = 1;
  1426. }
  1427. p->row++;
  1428. goto Exit;
  1429. }
  1430. /* Expect the SWIDTH (scalable width) field next. */
  1431. if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
  1432. {
  1433. if ( !( p->flags & _BDF_ENCODING ) )
  1434. goto Missing_Encoding;
  1435. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1436. if ( error )
  1437. goto Exit;
  1438. glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
  1439. p->flags |= _BDF_SWIDTH;
  1440. goto Exit;
  1441. }
  1442. /* Expect the DWIDTH (scalable width) field next. */
  1443. if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
  1444. {
  1445. if ( !( p->flags & _BDF_ENCODING ) )
  1446. goto Missing_Encoding;
  1447. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1448. if ( error )
  1449. goto Exit;
  1450. glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
  1451. if ( !( p->flags & _BDF_SWIDTH ) )
  1452. {
  1453. /* Missing SWIDTH field. Emit an auto correction message and set */
  1454. /* the scalable width from the device width. */
  1455. FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
  1456. glyph->swidth = (unsigned short)FT_MulDiv(
  1457. glyph->dwidth, 72000L,
  1458. (FT_Long)( font->point_size *
  1459. font->resolution_x ) );
  1460. }
  1461. p->flags |= _BDF_DWIDTH;
  1462. goto Exit;
  1463. }
  1464. /* Expect the BBX field next. */
  1465. if ( ft_memcmp( line, "BBX", 3 ) == 0 )
  1466. {
  1467. if ( !( p->flags & _BDF_ENCODING ) )
  1468. goto Missing_Encoding;
  1469. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1470. if ( error )
  1471. goto Exit;
  1472. glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
  1473. glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
  1474. glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
  1475. glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
  1476. /* Generate the ascent and descent of the character. */
  1477. glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
  1478. glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
  1479. /* Determine the overall font bounding box as the characters are */
  1480. /* loaded so corrections can be done later if indicated. */
  1481. p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
  1482. p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
  1483. p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
  1484. p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
  1485. p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
  1486. p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
  1487. if ( !( p->flags & _BDF_DWIDTH ) )
  1488. {
  1489. /* Missing DWIDTH field. Emit an auto correction message and set */
  1490. /* the device width to the glyph width. */
  1491. FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
  1492. glyph->dwidth = glyph->bbx.width;
  1493. }
  1494. /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
  1495. /* value if necessary. */
  1496. if ( p->opts->correct_metrics != 0 )
  1497. {
  1498. /* Determine the point size of the glyph. */
  1499. unsigned short sw = (unsigned short)FT_MulDiv(
  1500. glyph->dwidth, 72000L,
  1501. (FT_Long)( font->point_size *
  1502. font->resolution_x ) );
  1503. if ( sw != glyph->swidth )
  1504. {
  1505. glyph->swidth = sw;
  1506. if ( p->glyph_enc == -1 )
  1507. _bdf_set_glyph_modified( font->umod,
  1508. font->unencoded_used - 1 );
  1509. else
  1510. _bdf_set_glyph_modified( font->nmod, glyph->encoding );
  1511. p->flags |= _BDF_SWIDTH_ADJ;
  1512. font->modified = 1;
  1513. }
  1514. }
  1515. p->flags |= _BDF_BBX;
  1516. goto Exit;
  1517. }
  1518. /* And finally, gather up the bitmap. */
  1519. if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
  1520. {
  1521. unsigned long bitmap_size;
  1522. if ( !( p->flags & _BDF_BBX ) )
  1523. {
  1524. /* Missing BBX field. */
  1525. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
  1526. error = BDF_Err_Missing_Bbx_Field;
  1527. goto Exit;
  1528. }
  1529. /* Allocate enough space for the bitmap. */
  1530. glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
  1531. bitmap_size = glyph->bpr * glyph->bbx.height;
  1532. if ( glyph->bpr > 0xFFFFU || bitmap_size > 0xFFFFU )
  1533. {
  1534. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
  1535. error = BDF_Err_Bbx_Too_Big;
  1536. goto Exit;
  1537. }
  1538. else
  1539. glyph->bytes = (unsigned short)bitmap_size;
  1540. if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
  1541. goto Exit;
  1542. p->row = 0;
  1543. p->flags |= _BDF_BITMAP;
  1544. goto Exit;
  1545. }
  1546. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG9, lineno ));
  1547. error = BDF_Err_Invalid_File_Format;
  1548. goto Exit;
  1549. Missing_Encoding:
  1550. /* Missing ENCODING field. */
  1551. FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
  1552. error = BDF_Err_Missing_Encoding_Field;
  1553. Exit:
  1554. if ( error && ( p->flags & _BDF_GLYPH ) )
  1555. FT_FREE( p->glyph_name );
  1556. return error;
  1557. }
  1558. /* Load the font properties. */
  1559. static FT_Error
  1560. _bdf_parse_properties( char* line,
  1561. unsigned long linelen,
  1562. unsigned long lineno,
  1563. void* call_data,
  1564. void* client_data )
  1565. {
  1566. unsigned long vlen;
  1567. _bdf_line_func_t* next;
  1568. _bdf_parse_t* p;
  1569. char* name;
  1570. char* value;
  1571. char nbuf[128];
  1572. FT_Error error = BDF_Err_Ok;
  1573. FT_UNUSED( lineno );
  1574. next = (_bdf_line_func_t *)call_data;
  1575. p = (_bdf_parse_t *) client_data;
  1576. /* Check for the end of the properties. */
  1577. if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
  1578. {
  1579. /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
  1580. /* encountered yet, then make sure they are added as properties and */
  1581. /* make sure they are set from the font bounding box info. */
  1582. /* */
  1583. /* This is *always* done regardless of the options, because X11 */
  1584. /* requires these two fields to compile fonts. */
  1585. if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
  1586. {
  1587. p->font->font_ascent = p->font->bbx.ascent;
  1588. ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
  1589. error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
  1590. nbuf, lineno );
  1591. if ( error )
  1592. goto Exit;
  1593. FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
  1594. p->font->modified = 1;
  1595. }
  1596. if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
  1597. {
  1598. p->font->font_descent = p->font->bbx.descent;
  1599. ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
  1600. error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
  1601. nbuf, lineno );
  1602. if ( error )
  1603. goto Exit;
  1604. FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
  1605. p->font->modified = 1;
  1606. }
  1607. p->flags &= ~_BDF_PROPS;
  1608. *next = _bdf_parse_glyphs;
  1609. goto Exit;
  1610. }
  1611. /* Ignore the _XFREE86_GLYPH_RANGES properties. */
  1612. if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
  1613. goto Exit;
  1614. /* Handle COMMENT fields and properties in a special way to preserve */
  1615. /* the spacing. */
  1616. if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
  1617. {
  1618. name = value = line;
  1619. value += 7;
  1620. if ( *value )
  1621. *value++ = 0;
  1622. error = _bdf_add_property( p->font, name, value, lineno );
  1623. if ( error )
  1624. goto Exit;
  1625. }
  1626. else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
  1627. {
  1628. error = _bdf_add_property( p->font, name, value, lineno );
  1629. if ( error )
  1630. goto Exit;
  1631. }
  1632. else
  1633. {
  1634. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1635. if ( error )
  1636. goto Exit;
  1637. name = p->list.field[0];
  1638. _bdf_list_shift( &p->list, 1 );
  1639. value = _bdf_list_join( &p->list, ' ', &vlen );
  1640. error = _bdf_add_property( p->font, name, value, lineno );
  1641. if ( error )
  1642. goto Exit;
  1643. }
  1644. Exit:
  1645. return error;
  1646. }
  1647. /* Load the font header. */
  1648. static FT_Error
  1649. _bdf_parse_start( char* line,
  1650. unsigned long linelen,
  1651. unsigned long lineno,
  1652. void* call_data,
  1653. void* client_data )
  1654. {
  1655. unsigned long slen;
  1656. _bdf_line_func_t* next;
  1657. _bdf_parse_t* p;
  1658. bdf_font_t* font;
  1659. char *s;
  1660. FT_Memory memory = NULL;
  1661. FT_Error error = BDF_Err_Ok;
  1662. FT_UNUSED( lineno ); /* only used in debug mode */
  1663. next = (_bdf_line_func_t *)call_data;
  1664. p = (_bdf_parse_t *) client_data;
  1665. if ( p->font )
  1666. memory = p->font->memory;
  1667. /* Check for a comment. This is done to handle those fonts that have */
  1668. /* comments before the STARTFONT line for some reason. */
  1669. if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
  1670. {
  1671. if ( p->opts->keep_comments != 0 && p->font != 0 )
  1672. {
  1673. linelen -= 7;
  1674. s = line + 7;
  1675. if ( *s != 0 )
  1676. {
  1677. s++;
  1678. linelen--;
  1679. }
  1680. error = _bdf_add_comment( p->font, s, linelen );
  1681. if ( error )
  1682. goto Exit;
  1683. /* here font is not defined! */
  1684. }
  1685. goto Exit;
  1686. }
  1687. if ( !( p->flags & _BDF_START ) )
  1688. {
  1689. memory = p->memory;
  1690. if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
  1691. {
  1692. /* we don't emit an error message since this code gets */
  1693. /* explicitly caught one level higher */
  1694. error = BDF_Err_Missing_Startfont_Field;
  1695. goto Exit;
  1696. }
  1697. p->flags = _BDF_START;
  1698. font = p->font = 0;
  1699. if ( FT_NEW( font ) )
  1700. goto Exit;
  1701. p->font = font;
  1702. font->memory = p->memory;
  1703. p->memory = 0;
  1704. { /* setup */
  1705. size_t i;
  1706. bdf_property_t* prop;
  1707. error = hash_init( &(font->proptbl), memory );
  1708. if ( error )
  1709. goto Exit;
  1710. for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
  1711. i < _num_bdf_properties; i++, prop++ )
  1712. {
  1713. error = hash_insert( prop->name, i,
  1714. &(font->proptbl), memory );
  1715. if ( error )
  1716. goto Exit;
  1717. }
  1718. }
  1719. if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
  1720. goto Exit;
  1721. error = hash_init( (hashtable *)p->font->internal,memory );
  1722. if ( error )
  1723. goto Exit;
  1724. p->font->spacing = p->opts->font_spacing;
  1725. p->font->default_char = -1;
  1726. goto Exit;
  1727. }
  1728. /* Check for the start of the properties. */
  1729. if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
  1730. {
  1731. if ( !( p->flags & _BDF_FONT_BBX ) )
  1732. {
  1733. /* Missing the FONTBOUNDINGBOX field. */
  1734. FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
  1735. error = BDF_Err_Missing_Fontboundingbox_Field;
  1736. goto Exit;
  1737. }
  1738. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1739. if ( error )
  1740. goto Exit;
  1741. /* at this point, `p->font' can't be NULL */
  1742. p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
  1743. if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
  1744. goto Exit;
  1745. p->flags |= _BDF_PROPS;
  1746. *next = _bdf_parse_properties;
  1747. goto Exit;
  1748. }
  1749. /* Check for the FONTBOUNDINGBOX field. */
  1750. if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
  1751. {
  1752. if ( !( p->flags & _BDF_SIZE ) )
  1753. {
  1754. /* Missing the SIZE field. */
  1755. FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
  1756. error = BDF_Err_Missing_Size_Field;
  1757. goto Exit;
  1758. }
  1759. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1760. if ( error )
  1761. goto Exit;
  1762. p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
  1763. p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
  1764. p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
  1765. p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
  1766. p->font->bbx.ascent = (short)( p->font->bbx.height +
  1767. p->font->bbx.y_offset );
  1768. p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
  1769. p->flags |= _BDF_FONT_BBX;
  1770. goto Exit;
  1771. }
  1772. /* The next thing to check for is the FONT field. */
  1773. if ( ft_memcmp( line, "FONT", 4 ) == 0 )
  1774. {
  1775. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1776. if ( error )
  1777. goto Exit;
  1778. _bdf_list_shift( &p->list, 1 );
  1779. s = _bdf_list_join( &p->list, ' ', &slen );
  1780. if ( !s )
  1781. {
  1782. FT_ERROR(( "_bdf_parse_start: " ERRMSG8, lineno, "FONT" ));
  1783. error = BDF_Err_Invalid_File_Format;
  1784. goto Exit;
  1785. }
  1786. /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
  1787. FT_FREE( p->font->name );
  1788. if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
  1789. goto Exit;
  1790. FT_MEM_COPY( p->font->name, s, slen + 1 );
  1791. /* If the font name is an XLFD name, set the spacing to the one in */
  1792. /* the font name. If there is no spacing fall back on the default. */
  1793. error = _bdf_set_default_spacing( p->font, p->opts, lineno );
  1794. if ( error )
  1795. goto Exit;
  1796. p->flags |= _BDF_FONT_NAME;
  1797. goto Exit;
  1798. }
  1799. /* Check for the SIZE field. */
  1800. if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
  1801. {
  1802. if ( !( p->flags & _BDF_FONT_NAME ) )
  1803. {
  1804. /* Missing the FONT field. */
  1805. FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
  1806. error = BDF_Err_Missing_Font_Field;
  1807. goto Exit;
  1808. }
  1809. error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
  1810. if ( error )
  1811. goto Exit;
  1812. p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
  1813. p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
  1814. p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
  1815. /* Check for the bits per pixel field. */
  1816. if ( p->list.used == 5 )
  1817. {
  1818. unsigned short bitcount, i, shift;
  1819. p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
  1820. /* Only values 1, 2, 4, 8 are allowed. */
  1821. shift = p->font->bpp;
  1822. bitcount = 0;
  1823. for ( i = 0; shift > 0; i++ )
  1824. {
  1825. if ( shift & 1 )
  1826. bitcount = i;
  1827. shift >>= 1;
  1828. }
  1829. shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
  1830. if ( p->font->bpp > shift || p->font->bpp != shift )
  1831. {
  1832. /* select next higher value */
  1833. p->font->bpp = (unsigned short)( shift << 1 );
  1834. FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
  1835. }
  1836. }
  1837. else
  1838. p->font->bpp = 1;
  1839. p->flags |= _BDF_SIZE;
  1840. goto Exit;
  1841. }
  1842. /* Check for the CHARS field -- font properties are optional */
  1843. if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
  1844. {
  1845. char nbuf[128];
  1846. if ( !( p->flags & _BDF_FONT_BBX ) )
  1847. {
  1848. /* Missing the FONTBOUNDINGBOX field. */
  1849. FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
  1850. error = BDF_Err_Missing_Fontboundingbox_Field;
  1851. goto Exit;
  1852. }
  1853. /* Add the two standard X11 properties which are required */
  1854. /* for compiling fonts. */
  1855. p->font->font_ascent = p->font->bbx.ascent;
  1856. ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
  1857. error = _bdf_add_property( p->font, (char *)"FONT_ASCENT",
  1858. nbuf, lineno );
  1859. if ( error )
  1860. goto Exit;
  1861. FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
  1862. p->font->font_descent = p->font->bbx.descent;
  1863. ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
  1864. error = _bdf_add_property( p->font, (char *)"FONT_DESCENT",
  1865. nbuf, lineno );
  1866. if ( error )
  1867. goto Exit;
  1868. FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
  1869. p->font->modified = 1;
  1870. *next = _bdf_parse_glyphs;
  1871. /* A special return value. */
  1872. error = -1;
  1873. goto Exit;
  1874. }
  1875. FT_ERROR(( "_bdf_parse_start: " ERRMSG9, lineno ));
  1876. error = BDF_Err_Invalid_File_Format;
  1877. Exit:
  1878. return error;
  1879. }
  1880. /*************************************************************************/
  1881. /* */
  1882. /* API. */
  1883. /* */
  1884. /*************************************************************************/
  1885. FT_LOCAL_DEF( FT_Error )
  1886. bdf_load_font( FT_Stream stream,
  1887. FT_Memory extmemory,
  1888. bdf_options_t* opts,
  1889. bdf_font_t* *font )
  1890. {
  1891. unsigned long lineno = 0; /* make compiler happy */
  1892. _bdf_parse_t *p = NULL;
  1893. FT_Memory memory = extmemory;
  1894. FT_Error error = BDF_Err_Ok;
  1895. if ( FT_NEW( p ) )
  1896. goto Exit;
  1897. memory = NULL;
  1898. p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
  1899. p->minlb = 32767;
  1900. p->memory = extmemory; /* only during font creation */
  1901. _bdf_list_init( &p->list, extmemory );
  1902. error = _bdf_readstream( stream, _bdf_parse_start,
  1903. (void *)p, &lineno );
  1904. if ( error )
  1905. goto Fail;
  1906. if ( p->font != 0 )
  1907. {
  1908. /* If the font is not proportional, set the font's monowidth */
  1909. /* field to the width of the font bounding box. */
  1910. memory = p->font->memory;
  1911. if ( p->font->spacing != BDF_PROPORTIONAL )
  1912. p->font->monowidth = p->font->bbx.width;
  1913. /* If the number of glyphs loaded is not that of the original count, */
  1914. /* indicate the difference. */
  1915. if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
  1916. {
  1917. FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
  1918. p->font->glyphs_used + p->font->unencoded_used ));
  1919. p->font->modified = 1;
  1920. }
  1921. /* Once the font has been loaded, adjust the overall font metrics if */
  1922. /* necessary. */
  1923. if ( p->opts->correct_metrics != 0 &&
  1924. ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
  1925. {
  1926. if ( p->maxrb - p->minlb != p->font->bbx.width )
  1927. {
  1928. FT_TRACE2(( "bdf_load_font: " ACMSG3,
  1929. p->font->bbx.width, p->maxrb - p->minlb ));
  1930. p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
  1931. p->font->modified = 1;
  1932. }
  1933. if ( p->font->bbx.x_offset != p->minlb )
  1934. {
  1935. FT_TRACE2(( "bdf_load_font: " ACMSG4,
  1936. p->font->bbx.x_offset, p->minlb ));
  1937. p->font->bbx.x_offset = p->minlb;
  1938. p->font->modified = 1;
  1939. }
  1940. if ( p->font->bbx.ascent != p->maxas )
  1941. {
  1942. FT_TRACE2(( "bdf_load_font: " ACMSG5,
  1943. p->font->bbx.ascent, p->maxas ));
  1944. p->font->bbx.ascent = p->maxas;
  1945. p->font->modified = 1;
  1946. }
  1947. if ( p->font->bbx.descent != p->maxds )
  1948. {
  1949. FT_TRACE2(( "bdf_load_font: " ACMSG6,
  1950. p->font->bbx.descent, p->maxds ));
  1951. p->font->bbx.descent = p->maxds;
  1952. p->font->bbx.y_offset = (short)( -p->maxds );
  1953. p->font->modified = 1;
  1954. }
  1955. if ( p->maxas + p->maxds != p->font->bbx.height )
  1956. {
  1957. FT_TRACE2(( "bdf_load_font: " ACMSG7,
  1958. p->font->bbx.height, p->maxas + p->maxds ));
  1959. p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
  1960. }
  1961. if ( p->flags & _BDF_SWIDTH_ADJ )
  1962. FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
  1963. }
  1964. }
  1965. if ( p->flags & _BDF_START )
  1966. {
  1967. /* The ENDFONT field was never reached or did not exist. */
  1968. if ( !( p->flags & _BDF_GLYPHS ) )
  1969. {
  1970. /* Error happened while parsing header. */
  1971. FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
  1972. error = BDF_Err_Corrupted_Font_Header;
  1973. goto Exit;
  1974. }
  1975. else
  1976. {
  1977. /* Error happened when parsing glyphs. */
  1978. FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
  1979. error = BDF_Err_Corrupted_Font_Glyphs;
  1980. goto Exit;
  1981. }
  1982. }
  1983. if ( p->font != 0 )
  1984. {
  1985. /* Make sure the comments are NULL terminated if they exist. */
  1986. memory = p->font->memory;
  1987. if ( p->font->comments_len > 0 )
  1988. {
  1989. if ( FT_RENEW_ARRAY( p->font->comments,
  1990. p->font->comments_len,
  1991. p->font->comments_len + 1 ) )
  1992. goto Fail;
  1993. p->font->comments[p->font->comments_len] = 0;
  1994. }
  1995. }
  1996. else if ( error == BDF_Err_Ok )
  1997. error = BDF_Err_Invalid_File_Format;
  1998. *font = p->font;
  1999. Exit:
  2000. if ( p )
  2001. {
  2002. _bdf_list_done( &p->list );
  2003. memory = extmemory;
  2004. FT_FREE( p );
  2005. }
  2006. return error;
  2007. Fail:
  2008. bdf_free_font( p->font );
  2009. memory = extmemory;
  2010. FT_FREE( p->font );
  2011. goto Exit;
  2012. }
  2013. FT_LOCAL_DEF( void )
  2014. bdf_free_font( bdf_font_t* font )
  2015. {
  2016. bdf_property_t* prop;
  2017. unsigned long i;
  2018. bdf_glyph_t* glyphs;
  2019. FT_Memory memory;
  2020. if ( font == 0 )
  2021. return;
  2022. memory = font->memory;
  2023. FT_FREE( font->name );
  2024. /* Free up the internal hash table of property names. */
  2025. if ( font->internal )
  2026. {
  2027. hash_free( (hashtable *)font->internal, memory );
  2028. FT_FREE( font->internal );
  2029. }
  2030. /* Free up the comment info. */
  2031. FT_FREE( font->comments );
  2032. /* Free up the properties. */
  2033. for ( i = 0; i < font->props_size; i++ )
  2034. {
  2035. if ( font->props[i].format == BDF_ATOM )
  2036. FT_FREE( font->props[i].value.atom );
  2037. }
  2038. FT_FREE( font->props );
  2039. /* Free up the character info. */
  2040. for ( i = 0, glyphs = font->glyphs;
  2041. i < font->glyphs_used; i++, glyphs++ )
  2042. {
  2043. FT_FREE( glyphs->name );
  2044. FT_FREE( glyphs->bitmap );
  2045. }
  2046. for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
  2047. i++, glyphs++ )
  2048. {
  2049. FT_FREE( glyphs->name );
  2050. FT_FREE( glyphs->bitmap );
  2051. }
  2052. FT_FREE( font->glyphs );
  2053. FT_FREE( font->unencoded );
  2054. /* Free up the overflow storage if it was used. */
  2055. for ( i = 0, glyphs = font->overflow.glyphs;
  2056. i < font->overflow.glyphs_used; i++, glyphs++ )
  2057. {
  2058. FT_FREE( glyphs->name );
  2059. FT_FREE( glyphs->bitmap );
  2060. }
  2061. FT_FREE( font->overflow.glyphs );
  2062. /* bdf_cleanup */
  2063. hash_free( &(font->proptbl), memory );
  2064. /* Free up the user defined properties. */
  2065. for ( prop = font->user_props, i = 0;
  2066. i < font->nuser_props; i++, prop++ )
  2067. {
  2068. FT_FREE( prop->name );
  2069. if ( prop->format == BDF_ATOM )
  2070. FT_FREE( prop->value.atom );
  2071. }
  2072. FT_FREE( font->user_props );
  2073. /* FREE( font ); */ /* XXX Fixme */
  2074. }
  2075. FT_LOCAL_DEF( bdf_property_t * )
  2076. bdf_get_font_property( bdf_font_t* font,
  2077. const char* name )
  2078. {
  2079. hashnode hn;
  2080. if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
  2081. return 0;
  2082. hn = hash_lookup( name, (hashtable *)font->internal );
  2083. return hn ? ( font->props + hn->data ) : 0;
  2084. }
  2085. /* END */