blob: c8afc019fa8c030ddf9202e964f1b8b7846f983d [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lembergb66efef2009-03-12 08:07:49 +00003 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
Werner Lemberg442bfb82007-02-12 21:44:10 +00004 * Francesco Zappa Nardelli
David Turner993a8d02002-05-18 12:03:43 +00005 *
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
Werner Lemberg7cf4d372002-05-21 14:13:01 +000025 /*************************************************************************/
26 /* */
27 /* This file is based on bdf.c,v 1.22 2000/03/16 20:08:50 */
28 /* */
29 /* taken from Mark Leisher's xmbdfed package */
30 /* */
31 /*************************************************************************/
32
David Turner993a8d02002-05-18 12:03:43 +000033
34#include <ft2build.h>
35
Werner Lemberg02d4d592002-05-28 22:38:05 +000036#include FT_FREETYPE_H
David Turner993a8d02002-05-18 12:03:43 +000037#include FT_INTERNAL_DEBUG_H
38#include FT_INTERNAL_STREAM_H
39#include FT_INTERNAL_OBJECTS_H
40
41#include "bdf.h"
David Turner993a8d02002-05-18 12:03:43 +000042#include "bdferror.h"
43
David Turner993a8d02002-05-18 12:03:43 +000044
Werner Lemberg7cf4d372002-05-21 14:13:01 +000045 /*************************************************************************/
46 /* */
47 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
48 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
49 /* messages during execution. */
50 /* */
51#undef FT_COMPONENT
52#define FT_COMPONENT trace_bdflib
David Turner993a8d02002-05-18 12:03:43 +000053
David Turner993a8d02002-05-18 12:03:43 +000054
Werner Lemberg7cf4d372002-05-21 14:13:01 +000055 /*************************************************************************/
56 /* */
57 /* Default BDF font options. */
58 /* */
59 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000060
David Turner993a8d02002-05-18 12:03:43 +000061
David Turnerb1b47622002-05-21 21:17:43 +000062 static const bdf_options_t _bdf_opts =
Werner Lemberg7cf4d372002-05-21 14:13:01 +000063 {
David Turner993a8d02002-05-18 12:03:43 +000064 1, /* Correct metrics. */
65 1, /* Preserve unencoded glyphs. */
Werner Lemberg7cf4d372002-05-21 14:13:01 +000066 0, /* Preserve comments. */
67 BDF_PROPORTIONAL /* Default spacing. */
68 };
David Turner993a8d02002-05-18 12:03:43 +000069
David Turner993a8d02002-05-18 12:03:43 +000070
Werner Lemberg7cf4d372002-05-21 14:13:01 +000071 /*************************************************************************/
72 /* */
73 /* Builtin BDF font properties. */
74 /* */
75 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +000076
Werner Lemberg7cf4d372002-05-21 14:13:01 +000077 /* List of most properties that might appear in a font. Doesn't include */
78 /* the RAW_* and AXIS_* properties in X11R6 polymorphic fonts. */
David Turner993a8d02002-05-18 12:03:43 +000079
David Turnerb1b47622002-05-21 21:17:43 +000080 static const bdf_property_t _bdf_properties[] =
David Turner993a8d02002-05-18 12:03:43 +000081 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +000082 { (char *)"ADD_STYLE_NAME", BDF_ATOM, 1, { 0 } },
83 { (char *)"AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
84 { (char *)"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
85 { (char *)"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
86 { (char *)"CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
87 { (char *)"CHARSET_COLLECTIONS", BDF_ATOM, 1, { 0 } },
88 { (char *)"CHARSET_ENCODING", BDF_ATOM, 1, { 0 } },
89 { (char *)"CHARSET_REGISTRY", BDF_ATOM, 1, { 0 } },
90 { (char *)"COMMENT", BDF_ATOM, 1, { 0 } },
91 { (char *)"COPYRIGHT", BDF_ATOM, 1, { 0 } },
92 { (char *)"DEFAULT_CHAR", BDF_CARDINAL, 1, { 0 } },
93 { (char *)"DESTINATION", BDF_CARDINAL, 1, { 0 } },
94 { (char *)"DEVICE_FONT_NAME", BDF_ATOM, 1, { 0 } },
95 { (char *)"END_SPACE", BDF_INTEGER, 1, { 0 } },
96 { (char *)"FACE_NAME", BDF_ATOM, 1, { 0 } },
97 { (char *)"FAMILY_NAME", BDF_ATOM, 1, { 0 } },
98 { (char *)"FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
99 { (char *)"FONT", BDF_ATOM, 1, { 0 } },
100 { (char *)"FONTNAME_REGISTRY", BDF_ATOM, 1, { 0 } },
101 { (char *)"FONT_ASCENT", BDF_INTEGER, 1, { 0 } },
102 { (char *)"FONT_DESCENT", BDF_INTEGER, 1, { 0 } },
103 { (char *)"FOUNDRY", BDF_ATOM, 1, { 0 } },
104 { (char *)"FULL_NAME", BDF_ATOM, 1, { 0 } },
105 { (char *)"ITALIC_ANGLE", BDF_INTEGER, 1, { 0 } },
106 { (char *)"MAX_SPACE", BDF_INTEGER, 1, { 0 } },
107 { (char *)"MIN_SPACE", BDF_INTEGER, 1, { 0 } },
108 { (char *)"NORM_SPACE", BDF_INTEGER, 1, { 0 } },
109 { (char *)"NOTICE", BDF_ATOM, 1, { 0 } },
110 { (char *)"PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
111 { (char *)"POINT_SIZE", BDF_INTEGER, 1, { 0 } },
112 { (char *)"QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
113 { (char *)"RAW_ASCENT", BDF_INTEGER, 1, { 0 } },
114 { (char *)"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1, { 0 } },
115 { (char *)"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1, { 0 } },
116 { (char *)"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1, { 0 } },
117 { (char *)"RAW_CAP_HEIGHT", BDF_INTEGER, 1, { 0 } },
118 { (char *)"RAW_DESCENT", BDF_INTEGER, 1, { 0 } },
119 { (char *)"RAW_END_SPACE", BDF_INTEGER, 1, { 0 } },
120 { (char *)"RAW_FIGURE_WIDTH", BDF_INTEGER, 1, { 0 } },
121 { (char *)"RAW_MAX_SPACE", BDF_INTEGER, 1, { 0 } },
122 { (char *)"RAW_MIN_SPACE", BDF_INTEGER, 1, { 0 } },
123 { (char *)"RAW_NORM_SPACE", BDF_INTEGER, 1, { 0 } },
124 { (char *)"RAW_PIXEL_SIZE", BDF_INTEGER, 1, { 0 } },
125 { (char *)"RAW_POINT_SIZE", BDF_INTEGER, 1, { 0 } },
126 { (char *)"RAW_PIXELSIZE", BDF_INTEGER, 1, { 0 } },
127 { (char *)"RAW_POINTSIZE", BDF_INTEGER, 1, { 0 } },
128 { (char *)"RAW_QUAD_WIDTH", BDF_INTEGER, 1, { 0 } },
129 { (char *)"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
130 { (char *)"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
131 { (char *)"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
132 { (char *)"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
133 { (char *)"RAW_SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
134 { (char *)"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
135 { (char *)"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
136 { (char *)"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
137 { (char *)"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
138 { (char *)"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
139 { (char *)"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
140 { (char *)"RAW_X_HEIGHT", BDF_INTEGER, 1, { 0 } },
141 { (char *)"RELATIVE_SETWIDTH", BDF_CARDINAL, 1, { 0 } },
142 { (char *)"RELATIVE_WEIGHT", BDF_CARDINAL, 1, { 0 } },
143 { (char *)"RESOLUTION", BDF_INTEGER, 1, { 0 } },
144 { (char *)"RESOLUTION_X", BDF_CARDINAL, 1, { 0 } },
145 { (char *)"RESOLUTION_Y", BDF_CARDINAL, 1, { 0 } },
146 { (char *)"SETWIDTH_NAME", BDF_ATOM, 1, { 0 } },
147 { (char *)"SLANT", BDF_ATOM, 1, { 0 } },
148 { (char *)"SMALL_CAP_SIZE", BDF_INTEGER, 1, { 0 } },
149 { (char *)"SPACING", BDF_ATOM, 1, { 0 } },
150 { (char *)"STRIKEOUT_ASCENT", BDF_INTEGER, 1, { 0 } },
151 { (char *)"STRIKEOUT_DESCENT", BDF_INTEGER, 1, { 0 } },
152 { (char *)"SUBSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
153 { (char *)"SUBSCRIPT_X", BDF_INTEGER, 1, { 0 } },
154 { (char *)"SUBSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
155 { (char *)"SUPERSCRIPT_SIZE", BDF_INTEGER, 1, { 0 } },
156 { (char *)"SUPERSCRIPT_X", BDF_INTEGER, 1, { 0 } },
157 { (char *)"SUPERSCRIPT_Y", BDF_INTEGER, 1, { 0 } },
158 { (char *)"UNDERLINE_POSITION", BDF_INTEGER, 1, { 0 } },
159 { (char *)"UNDERLINE_THICKNESS", BDF_INTEGER, 1, { 0 } },
160 { (char *)"WEIGHT", BDF_CARDINAL, 1, { 0 } },
161 { (char *)"WEIGHT_NAME", BDF_ATOM, 1, { 0 } },
162 { (char *)"X_HEIGHT", BDF_INTEGER, 1, { 0 } },
163 { (char *)"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1, { 0 } },
164 { (char *)"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1, { 0 } },
165 };
David Turner993a8d02002-05-18 12:03:43 +0000166
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000167 static const unsigned long
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000168 _num_bdf_properties = sizeof ( _bdf_properties ) /
169 sizeof ( _bdf_properties[0] );
David Turner993a8d02002-05-18 12:03:43 +0000170
171
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000172 /*************************************************************************/
173 /* */
174 /* Hash table utilities for the properties. */
175 /* */
176 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +0000177
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000178 /* XXX: Replace this with FreeType's hash functions */
David Turner993a8d02002-05-18 12:03:43 +0000179
David Turner993a8d02002-05-18 12:03:43 +0000180
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000181#define INITIAL_HT_SIZE 241
182
183 typedef void
184 (*hash_free_func)( hashnode node );
185
186 static hashnode*
Werner Lemberg428c2e42003-04-25 05:35:04 +0000187 hash_bucket( const char* key,
188 hashtable* ht )
David Turner993a8d02002-05-18 12:03:43 +0000189 {
Werner Lemberg428c2e42003-04-25 05:35:04 +0000190 const char* kp = key;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000191 unsigned long res = 0;
192 hashnode* bp = ht->table, *ndp;
193
194
195 /* Mocklisp hash function. */
196 while ( *kp )
197 res = ( res << 5 ) - res + *kp++;
198
199 ndp = bp + ( res % ht->size );
200 while ( *ndp )
David Turner993a8d02002-05-18 12:03:43 +0000201 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000202 kp = (*ndp)->key;
203 if ( kp[0] == key[0] && ft_strcmp( kp, key ) == 0 )
204 break;
205 ndp--;
206 if ( ndp < bp )
207 ndp = bp + ( ht->size - 1 );
David Turner993a8d02002-05-18 12:03:43 +0000208 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000209
210 return ndp;
David Turner993a8d02002-05-18 12:03:43 +0000211 }
David Turner993a8d02002-05-18 12:03:43 +0000212
213
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000214 static FT_Error
215 hash_rehash( hashtable* ht,
216 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000217 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000218 hashnode* obp = ht->table, *bp, *nbp;
David Turner993a8d02002-05-18 12:03:43 +0000219 int i, sz = ht->size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000220 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000221
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000222
223 ht->size <<= 1;
224 ht->limit = ht->size / 3;
225
226 if ( FT_NEW_ARRAY( ht->table, ht->size ) )
227 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000228
229 for ( i = 0, bp = obp; i < sz; i++, bp++ )
David Turner993a8d02002-05-18 12:03:43 +0000230 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000231 if ( *bp )
232 {
233 nbp = hash_bucket( (*bp)->key, ht );
234 *nbp = *bp;
235 }
David Turner993a8d02002-05-18 12:03:43 +0000236 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000237 FT_FREE( obp );
238
239 Exit:
240 return error;
David Turner993a8d02002-05-18 12:03:43 +0000241 }
David Turner993a8d02002-05-18 12:03:43 +0000242
243
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000244 static FT_Error
245 hash_init( hashtable* ht,
246 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000247 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000248 int sz = INITIAL_HT_SIZE;
249 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000250
David Turner993a8d02002-05-18 12:03:43 +0000251
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000252 ht->size = sz;
253 ht->limit = sz / 3;
254 ht->used = 0;
David Turner993a8d02002-05-18 12:03:43 +0000255
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000256 if ( FT_NEW_ARRAY( ht->table, sz ) )
257 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000258
259 Exit:
260 return error;
David Turner993a8d02002-05-18 12:03:43 +0000261 }
David Turner993a8d02002-05-18 12:03:43 +0000262
263
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000264 static void
265 hash_free( hashtable* ht,
266 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000267 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000268 if ( ht != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000269 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000270 int i, sz = ht->size;
271 hashnode* bp = ht->table;
David Turner993a8d02002-05-18 12:03:43 +0000272
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000273
274 for ( i = 0; i < sz; i++, bp++ )
275 FT_FREE( *bp );
276
277 FT_FREE( ht->table );
278 }
David Turner993a8d02002-05-18 12:03:43 +0000279 }
280
David Turner993a8d02002-05-18 12:03:43 +0000281
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000282 static FT_Error
283 hash_insert( char* key,
284 void* data,
285 hashtable* ht,
286 FT_Memory memory )
David Turner993a8d02002-05-18 12:03:43 +0000287 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000288 hashnode nn, *bp = hash_bucket( key, ht );
289 FT_Error error = BDF_Err_Ok;
290
291
292 nn = *bp;
293 if ( !nn )
294 {
295 if ( FT_NEW( nn ) )
296 goto Exit;
297 *bp = nn;
298
299 nn->key = key;
300 nn->data = data;
301
302 if ( ht->used >= ht->limit )
303 {
304 error = hash_rehash( ht, memory );
305 if ( error )
306 goto Exit;
307 }
308 ht->used++;
309 }
David Turner993a8d02002-05-18 12:03:43 +0000310 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000311 nn->data = data;
312
313 Exit:
314 return error;
David Turner993a8d02002-05-18 12:03:43 +0000315 }
316
David Turner993a8d02002-05-18 12:03:43 +0000317
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000318 static hashnode
Werner Lemberg428c2e42003-04-25 05:35:04 +0000319 hash_lookup( const char* key,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000320 hashtable* ht )
321 {
322 hashnode *np = hash_bucket( key, ht );
323
324
325 return *np;
326 }
327
328
329 /*************************************************************************/
330 /* */
331 /* Utility types and functions. */
332 /* */
333 /*************************************************************************/
334
335
336 /* Function type for parsing lines of a BDF font. */
337
338 typedef FT_Error
339 (*_bdf_line_func_t)( char* line,
340 unsigned long linelen,
341 unsigned long lineno,
342 void* call_data,
343 void* client_data );
344
345
346 /* List structure for splitting lines into fields. */
347
348 typedef struct _bdf_list_t_
349 {
350 char** field;
351 unsigned long size;
352 unsigned long used;
David Turner68df4f72005-03-15 18:18:57 +0000353 FT_Memory memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000354
355 } _bdf_list_t;
356
357
358 /* Structure used while loading BDF fonts. */
359
360 typedef struct _bdf_parse_t_
361 {
362 unsigned long flags;
363 unsigned long cnt;
364 unsigned long row;
365
366 short minlb;
367 short maxlb;
368 short maxrb;
369 short maxas;
370 short maxds;
371
372 short rbearing;
373
374 char* glyph_name;
375 long glyph_enc;
376
377 bdf_font_t* font;
378 bdf_options_t* opts;
379
380 unsigned long have[2048];
381 _bdf_list_t list;
382
383 FT_Memory memory;
384
385 } _bdf_parse_t;
386
387
Werner Lemberga08b2172007-03-28 07:17:17 +0000388#define setsbit( m, cc ) \
389 ( m[(FT_Byte)(cc) >> 3] |= (FT_Byte)( 1 << ( (cc) & 7 ) ) )
390#define sbitset( m, cc ) \
391 ( m[(FT_Byte)(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000392
393
David Turner68df4f72005-03-15 18:18:57 +0000394 static void
395 _bdf_list_init( _bdf_list_t* list,
396 FT_Memory memory )
397 {
Werner Lembergebf55852005-03-16 01:49:54 +0000398 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000399 list->memory = memory;
400 }
401
Werner Lembergebf55852005-03-16 01:49:54 +0000402
David Turner68df4f72005-03-15 18:18:57 +0000403 static void
404 _bdf_list_done( _bdf_list_t* list )
405 {
406 FT_Memory memory = list->memory;
407
Werner Lembergebf55852005-03-16 01:49:54 +0000408
David Turner68df4f72005-03-15 18:18:57 +0000409 if ( memory )
410 {
411 FT_FREE( list->field );
Werner Lembergebf55852005-03-16 01:49:54 +0000412 FT_ZERO( list );
David Turner68df4f72005-03-15 18:18:57 +0000413 }
414 }
415
416
417 static FT_Error
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900418 _bdf_list_ensure( _bdf_list_t* list,
419 unsigned long num_items ) /* same as _bdf_list_t.used */
David Turner68df4f72005-03-15 18:18:57 +0000420 {
Werner Lembergebf55852005-03-16 01:49:54 +0000421 FT_Error error = BDF_Err_Ok;
422
David Turner68df4f72005-03-15 18:18:57 +0000423
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900424 if ( num_items > list->size )
David Turner68df4f72005-03-15 18:18:57 +0000425 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900426 unsigned long oldsize = list->size; /* same as _bdf_list_t.size */
427 unsigned long newsize = oldsize + ( oldsize >> 1 ) + 4;
428 unsigned long bigsize = (unsigned long)( FT_INT_MAX / sizeof ( char* ) );
429 FT_Memory memory = list->memory;
David Turner68df4f72005-03-15 18:18:57 +0000430
Werner Lembergebf55852005-03-16 01:49:54 +0000431
David Turner68df4f72005-03-15 18:18:57 +0000432 if ( oldsize == bigsize )
433 {
Werner Lembergebf55852005-03-16 01:49:54 +0000434 error = BDF_Err_Out_Of_Memory;
David Turner68df4f72005-03-15 18:18:57 +0000435 goto Exit;
436 }
437 else if ( newsize < oldsize || newsize > bigsize )
438 newsize = bigsize;
439
440 if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
441 goto Exit;
442
443 list->size = newsize;
444 }
Werner Lembergebf55852005-03-16 01:49:54 +0000445
David Turner68df4f72005-03-15 18:18:57 +0000446 Exit:
447 return error;
448 }
449
450
451 static void
452 _bdf_list_shift( _bdf_list_t* list,
453 unsigned long n )
454 {
455 unsigned long i, u;
456
457
458 if ( list == 0 || list->used == 0 || n == 0 )
459 return;
460
461 if ( n >= list->used )
462 {
463 list->used = 0;
464 return;
465 }
466
467 for ( u = n, i = 0; u < list->used; i++, u++ )
468 list->field[i] = list->field[u];
469 list->used -= n;
470 }
471
472
473 static char *
474 _bdf_list_join( _bdf_list_t* list,
475 int c,
476 unsigned long *alen )
477 {
478 unsigned long i, j;
479 char *fp, *dp;
480
481
482 *alen = 0;
483
484 if ( list == 0 || list->used == 0 )
485 return 0;
486
487 dp = list->field[0];
488 for ( i = j = 0; i < list->used; i++ )
489 {
490 fp = list->field[i];
491 while ( *fp )
492 dp[j++] = *fp++;
493
494 if ( i + 1 < list->used )
495 dp[j++] = (char)c;
496 }
497 dp[j] = 0;
498
499 *alen = j;
500 return dp;
501 }
502
503
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000504 /* An empty string for empty fields. */
505
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000506 static const char empty[1] = { 0 }; /* XXX eliminate this */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000507
508
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000509 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000510 _bdf_list_split( _bdf_list_t* list,
511 char* separators,
512 char* line,
513 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000514 {
515 int mult, final_empty;
516 char *sp, *ep, *end;
517 char seps[32];
518 FT_Error error = BDF_Err_Ok;
519
520
521 /* Initialize the list. */
522 list->used = 0;
523
524 /* If the line is empty, then simply return. */
525 if ( linelen == 0 || line[0] == 0 )
526 goto Exit;
527
528 /* In the original code, if the `separators' parameter is NULL or */
529 /* empty, the list is split into individual bytes. We don't need */
530 /* this, so an error is signaled. */
531 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000532 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000533 error = BDF_Err_Invalid_Argument;
534 goto Exit;
535 }
536
537 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000538 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000539
540 /* If the very last character of the separator string is a plus, then */
541 /* set the `mult' flag to indicate that multiple separators should be */
542 /* collapsed into one. */
543 for ( mult = 0, sp = separators; sp && *sp; sp++ )
544 {
545 if ( *sp == '+' && *( sp + 1 ) == 0 )
546 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000547 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000548 setsbit( seps, *sp );
549 }
550
551 /* Break the line up into fields. */
552 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
553 sp < end && *sp; )
554 {
555 /* Collect everything that is not a separator. */
556 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
557 ;
558
559 /* Resize the list if necessary. */
560 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000561 {
Werner Lembergebf55852005-03-16 01:49:54 +0000562 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000563 if ( error )
564 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000565 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000566
567 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000568 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000569
570 sp = ep;
571
572 if ( mult )
573 {
574 /* If multiple separators should be collapsed, do it now by */
575 /* setting all the separator characters to 0. */
576 for ( ; *ep && sbitset( seps, *ep ); ep++ )
577 *ep = 0;
578 }
579 else if ( *ep != 0 )
580 /* Don't collapse multiple separators by making them 0, so just */
581 /* make the one encountered 0. */
582 *ep++ = 0;
583
584 final_empty = ( ep > sp && *ep == 0 );
585 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000586 }
587
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000588 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000589 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000590 {
Werner Lembergebf55852005-03-16 01:49:54 +0000591 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000592 if ( error )
593 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000594 }
595
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000596 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000597 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000598
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000599 list->field[list->used] = 0;
600
601 Exit:
602 return error;
David Turner993a8d02002-05-18 12:03:43 +0000603 }
604
David Turner993a8d02002-05-18 12:03:43 +0000605
David Turner68df4f72005-03-15 18:18:57 +0000606#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000607
Werner Lembergebf55852005-03-16 01:49:54 +0000608
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000609 static FT_Error
610 _bdf_readstream( FT_Stream stream,
611 _bdf_line_func_t callback,
612 void* client_data,
613 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000614 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000615 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000616 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900617 int refill, hold, to_skip;
618 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000619 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000620 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000621 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000622
David Turner993a8d02002-05-18 12:03:43 +0000623
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000624 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000625 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000626 error = BDF_Err_Invalid_Argument;
627 goto Exit;
628 }
David Turner993a8d02002-05-18 12:03:43 +0000629
Werner Lembergebf55852005-03-16 01:49:54 +0000630 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000631 buf_size = 1024;
632
633 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000634 goto Exit;
635
Werner Lembergebf55852005-03-16 01:49:54 +0000636 cb = callback;
637 lineno = 1;
638 buf[0] = 0;
639 start = 0;
640 end = 0;
641 avail = 0;
642 cursor = 0;
643 refill = 1;
644 to_skip = NO_SKIP;
645 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000646
David Turner68df4f72005-03-15 18:18:57 +0000647 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000648 {
David Turner68df4f72005-03-15 18:18:57 +0000649 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000650 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900651 bytes = (ptrdiff_t)FT_Stream_TryRead( stream, (FT_Byte*)buf + cursor,
652 (FT_ULong)(buf_size - cursor) );
David Turner68df4f72005-03-15 18:18:57 +0000653 avail = cursor + bytes;
654 cursor = 0;
655 refill = 0;
656 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000657
David Turner68df4f72005-03-15 18:18:57 +0000658 end = start;
659
Werner Lembergebf55852005-03-16 01:49:54 +0000660 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000661 if ( start < avail && buf[start] == to_skip )
662 {
663 start += 1;
664 to_skip = NO_SKIP;
665 continue;
666 }
667
668 /* try to find the end of the line */
669 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
670 end++;
671
Werner Lembergebf55852005-03-16 01:49:54 +0000672 /* if we hit the end of the buffer, try shifting its content */
673 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000674 if ( end >= avail )
675 {
676 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
677 break; /* ignore it then exit */
678
679 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000680 {
Werner Lembergebf55852005-03-16 01:49:54 +0000681 /* this line is definitely too long; try resizing the input */
682 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000683 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000684
Werner Lembergebf55852005-03-16 01:49:54 +0000685
686 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000687 {
688 error = BDF_Err_Invalid_Argument;
689 goto Exit;
690 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000691
Werner Lembergebf55852005-03-16 01:49:54 +0000692 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000693 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
694 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000695
David Turner68df4f72005-03-15 18:18:57 +0000696 cursor = buf_size;
697 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000698 }
699 else
700 {
David Turner68df4f72005-03-15 18:18:57 +0000701 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000702
Werner Lembergebf55852005-03-16 01:49:54 +0000703 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000704
David Turner68df4f72005-03-15 18:18:57 +0000705 cursor = bytes;
706 avail -= bytes;
707 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000708 }
David Turner68df4f72005-03-15 18:18:57 +0000709 refill = 1;
710 continue;
David Turner993a8d02002-05-18 12:03:43 +0000711 }
David Turner68df4f72005-03-15 18:18:57 +0000712
713 /* Temporarily NUL-terminate the line. */
714 hold = buf[end];
715 buf[end] = 0;
716
717 /* XXX: Use encoding independent value for 0x1a */
718 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
719 {
Werner Lembergebf55852005-03-16 01:49:54 +0000720 error = (*cb)( buf + start, end - start, lineno,
721 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000722 if ( error )
723 break;
724 }
725
726 lineno += 1;
727 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000728 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000729
730 if ( hold == '\n' )
731 to_skip = '\r';
732 else if ( hold == '\r' )
733 to_skip = '\n';
734 else
735 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000736 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000737
David Turner68df4f72005-03-15 18:18:57 +0000738 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000739
740 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000741 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000742 return error;
David Turner993a8d02002-05-18 12:03:43 +0000743 }
David Turner993a8d02002-05-18 12:03:43 +0000744
745
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000746 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000747
David Turnerb1b47622002-05-21 21:17:43 +0000748 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000749 {
David Turner993a8d02002-05-18 12:03:43 +0000750 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
755 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
757 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
758 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000761 };
David Turner993a8d02002-05-18 12:03:43 +0000762
David Turnerb1b47622002-05-21 21:17:43 +0000763 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000764 {
David Turner993a8d02002-05-18 12:03:43 +0000765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000769 };
David Turner993a8d02002-05-18 12:03:43 +0000770
David Turnerb1b47622002-05-21 21:17:43 +0000771 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000772 {
David Turner993a8d02002-05-18 12:03:43 +0000773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000777 };
David Turner993a8d02002-05-18 12:03:43 +0000778
David Turnerb1b47622002-05-21 21:17:43 +0000779 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000780 {
David Turner993a8d02002-05-18 12:03:43 +0000781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
782 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
783 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000785 };
David Turner993a8d02002-05-18 12:03:43 +0000786
David Turner993a8d02002-05-18 12:03:43 +0000787
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000788#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000789
David Turner993a8d02002-05-18 12:03:43 +0000790
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000791 /* Routine to convert an ASCII string into an unsigned long integer. */
792 static unsigned long
793 _bdf_atoul( char* s,
794 char** end,
795 int base )
David Turner993a8d02002-05-18 12:03:43 +0000796 {
David Turnerb1b47622002-05-21 21:17:43 +0000797 unsigned long v;
798 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000799
800
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000801 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000802 return 0;
803
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000804 /* Make sure the radix is something recognizable. Default to 10. */
805 switch ( base )
806 {
807 case 8:
808 dmap = odigits;
809 break;
810 case 16:
811 dmap = hdigits;
812 break;
813 default:
814 base = 10;
815 dmap = ddigits;
816 break;
David Turner993a8d02002-05-18 12:03:43 +0000817 }
818
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000819 /* Check for the special hex prefix. */
820 if ( *s == '0' &&
821 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
822 {
823 base = 16;
824 dmap = hdigits;
825 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000826 }
827
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000828 for ( v = 0; isdigok( dmap, *s ); s++ )
829 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000830
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000831 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000832 *end = s;
833
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000834 return v;
835 }
David Turner993a8d02002-05-18 12:03:43 +0000836
David Turner993a8d02002-05-18 12:03:43 +0000837
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000838 /* Routine to convert an ASCII string into an signed long integer. */
839 static long
840 _bdf_atol( char* s,
841 char** end,
842 int base )
843 {
David Turnerb1b47622002-05-21 21:17:43 +0000844 long v, neg;
845 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000846
847
848 if ( s == 0 || *s == 0 )
849 return 0;
850
851 /* Make sure the radix is something recognizable. Default to 10. */
852 switch ( base )
853 {
854 case 8:
855 dmap = odigits;
856 break;
857 case 16:
858 dmap = hdigits;
859 break;
860 default:
861 base = 10;
862 dmap = ddigits;
863 break;
864 }
865
866 /* Check for a minus sign. */
867 neg = 0;
868 if ( *s == '-' )
869 {
870 s++;
871 neg = 1;
872 }
873
874 /* Check for the special hex prefix. */
875 if ( *s == '0' &&
876 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
877 {
878 base = 16;
879 dmap = hdigits;
880 s += 2;
881 }
882
883 for ( v = 0; isdigok( dmap, *s ); s++ )
884 v = v * base + a2i[(int)*s];
885
886 if ( end != 0 )
887 *end = s;
888
889 return ( !neg ) ? v : -v;
890 }
891
892
893 /* Routine to convert an ASCII string into an signed short integer. */
894 static short
895 _bdf_atos( char* s,
896 char** end,
897 int base )
898 {
David Turnerb1b47622002-05-21 21:17:43 +0000899 short v, neg;
900 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000901
902
903 if ( s == 0 || *s == 0 )
904 return 0;
905
906 /* Make sure the radix is something recognizable. Default to 10. */
907 switch ( base )
908 {
909 case 8:
910 dmap = odigits;
911 break;
912 case 16:
913 dmap = hdigits;
914 break;
915 default:
916 base = 10;
917 dmap = ddigits;
918 break;
919 }
920
921 /* Check for a minus. */
922 neg = 0;
923 if ( *s == '-' )
924 {
925 s++;
926 neg = 1;
927 }
928
929 /* Check for the special hex prefix. */
930 if ( *s == '0' &&
931 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
932 {
933 base = 16;
934 dmap = hdigits;
935 s += 2;
936 }
937
938 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000939 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000940
941 if ( end != 0 )
942 *end = s;
943
Werner Lemberg233302a2002-05-22 05:41:06 +0000944 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000945 }
946
947
948 /* Routine to compare two glyphs by encoding so they can be sorted. */
949 static int
950 by_encoding( const void* a,
951 const void* b )
952 {
953 bdf_glyph_t *c1, *c2;
954
955
956 c1 = (bdf_glyph_t *)a;
957 c2 = (bdf_glyph_t *)b;
958
959 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000960 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000961
962 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000963 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000964
David Turner993a8d02002-05-18 12:03:43 +0000965 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000966 }
967
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000968
969 static FT_Error
970 bdf_create_property( char* name,
971 int format,
972 bdf_font_t* font )
973 {
974 unsigned long n;
975 bdf_property_t* p;
976 FT_Memory memory = font->memory;
977 FT_Error error = BDF_Err_Ok;
978
979
980 /* First check to see if the property has */
981 /* already been added or not. If it has, then */
982 /* simply ignore it. */
983 if ( hash_lookup( name, &(font->proptbl) ) )
984 goto Exit;
985
David Turner68df4f72005-03-15 18:18:57 +0000986 if ( FT_RENEW_ARRAY( font->user_props,
987 font->nuser_props,
988 font->nuser_props + 1 ) )
989 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000990
991 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000992 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000993
994 n = (unsigned long)( ft_strlen( name ) + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000995
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000996 if ( FT_NEW_ARRAY( p->name, n ) )
997 goto Exit;
998
999 FT_MEM_COPY( (char *)p->name, name, n );
1000
1001 p->format = format;
1002 p->builtin = 0;
1003
1004 n = _num_bdf_properties + font->nuser_props;
1005
1006 error = hash_insert( p->name, (void *)n, &(font->proptbl), memory );
1007 if ( error )
1008 goto Exit;
1009
1010 font->nuser_props++;
1011
1012 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001013 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001014 }
David Turner993a8d02002-05-18 12:03:43 +00001015
1016
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001017 FT_LOCAL_DEF( bdf_property_t * )
1018 bdf_get_property( char* name,
1019 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001020 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001021 hashnode hn;
1022 unsigned long propid;
1023
1024
1025 if ( name == 0 || *name == 0 )
1026 return 0;
1027
1028 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1029 return 0;
1030
1031 propid = (unsigned long)hn->data;
1032 if ( propid >= _num_bdf_properties )
1033 return font->user_props + ( propid - _num_bdf_properties );
1034
Werner Lemberg233302a2002-05-22 05:41:06 +00001035 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001036 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001037
1038
1039 /*************************************************************************/
1040 /* */
1041 /* BDF font file parsing flags and functions. */
1042 /* */
1043 /*************************************************************************/
1044
1045
1046 /* Parse flags. */
1047
1048#define _BDF_START 0x0001
1049#define _BDF_FONT_NAME 0x0002
1050#define _BDF_SIZE 0x0004
1051#define _BDF_FONT_BBX 0x0008
1052#define _BDF_PROPS 0x0010
1053#define _BDF_GLYPHS 0x0020
1054#define _BDF_GLYPH 0x0040
1055#define _BDF_ENCODING 0x0080
1056#define _BDF_SWIDTH 0x0100
1057#define _BDF_DWIDTH 0x0200
1058#define _BDF_BBX 0x0400
1059#define _BDF_BITMAP 0x0800
1060
1061#define _BDF_SWIDTH_ADJ 0x1000
1062
1063#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1064 _BDF_ENCODING | \
1065 _BDF_SWIDTH | \
1066 _BDF_DWIDTH | \
1067 _BDF_BBX | \
1068 _BDF_BITMAP )
1069
Werner Lembergf1c2b912006-01-13 14:53:28 +00001070#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1071#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001072
1073
1074 /* Auto correction messages. */
1075#define ACMSG1 "FONT_ASCENT property missing. " \
1076 "Added \"FONT_ASCENT %hd\".\n"
1077#define ACMSG2 "FONT_DESCENT property missing. " \
1078 "Added \"FONT_DESCENT %hd\".\n"
1079#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1080#define ACMSG4 "Font left bearing != actual left bearing. " \
1081 "Old: %hd New: %hd.\n"
1082#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1083#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1084#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1085#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1086#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1087#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1088#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1089#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1090#define ACMSG13 "Glyph %ld extra rows removed.\n"
1091#define ACMSG14 "Glyph %ld extra columns removed.\n"
1092#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1093
1094 /* Error messages. */
1095#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1096#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1097#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
Werner Lemberg26170df2006-03-26 07:19:07 +00001098#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001099
1100
1101 static FT_Error
1102 _bdf_add_comment( bdf_font_t* font,
1103 char* comment,
1104 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001105 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001106 char* cp;
1107 FT_Memory memory = font->memory;
1108 FT_Error error = BDF_Err_Ok;
1109
1110
David Turner68df4f72005-03-15 18:18:57 +00001111 if ( FT_RENEW_ARRAY( font->comments,
1112 font->comments_len,
1113 font->comments_len + len + 1 ) )
1114 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001115
1116 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001117
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001118 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001119 cp[len] = '\n';
1120
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001121 font->comments_len += len + 1;
1122
1123 Exit:
1124 return error;
David Turner993a8d02002-05-18 12:03:43 +00001125 }
1126
David Turner993a8d02002-05-18 12:03:43 +00001127
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001128 /* Set the spacing from the font name if it exists, or set it to the */
1129 /* default specified in the options. */
1130 static FT_Error
1131 _bdf_set_default_spacing( bdf_font_t* font,
1132 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001133 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001134 unsigned long len;
Werner Lemberga08b2172007-03-28 07:17:17 +00001135 char name[256];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001136 _bdf_list_t list;
1137 FT_Memory memory;
1138 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001139
David Turner993a8d02002-05-18 12:03:43 +00001140
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001141 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1142 {
1143 error = BDF_Err_Invalid_Argument;
1144 goto Exit;
1145 }
David Turner993a8d02002-05-18 12:03:43 +00001146
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001147 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001148
David Turner68df4f72005-03-15 18:18:57 +00001149 _bdf_list_init( &list, memory );
1150
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001151 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 len = (unsigned long)( ft_strlen( font->name ) + 1 );
Werner Lemberga08b2172007-03-28 07:17:17 +00001154 /* Limit ourselves to 256 characters in the font name. */
1155 if ( len >= 256 )
1156 {
1157 error = BDF_Err_Invalid_Argument;
1158 goto Exit;
1159 }
1160
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001161 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001162
David Turner68df4f72005-03-15 18:18:57 +00001163 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001164 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001165 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001166
1167 if ( list.used == 15 )
1168 {
1169 switch ( list.field[11][0] )
1170 {
1171 case 'C':
1172 case 'c':
1173 font->spacing = BDF_CHARCELL;
1174 break;
1175 case 'M':
1176 case 'm':
1177 font->spacing = BDF_MONOWIDTH;
1178 break;
1179 case 'P':
1180 case 'p':
1181 font->spacing = BDF_PROPORTIONAL;
1182 break;
David Turner993a8d02002-05-18 12:03:43 +00001183 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001184 }
1185
David Turner68df4f72005-03-15 18:18:57 +00001186 Fail:
1187 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001188
1189 Exit:
1190 return error;
David Turner993a8d02002-05-18 12:03:43 +00001191 }
David Turner993a8d02002-05-18 12:03:43 +00001192
1193
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001194 /* Determine whether the property is an atom or not. If it is, then */
1195 /* clean it up so the double quotes are removed if they exist. */
1196 static int
1197 _bdf_is_atom( char* line,
1198 unsigned long linelen,
1199 char** name,
1200 char** value,
1201 bdf_font_t* font )
1202 {
1203 int hold;
1204 char *sp, *ep;
1205 bdf_property_t* p;
1206
David Turner993a8d02002-05-18 12:03:43 +00001207
1208 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001209
1210 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001211 ep++;
1212
1213 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001214 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001215 {
1216 hold = *ep;
1217 *ep = 0;
1218 }
1219
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001220 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001221
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222 /* Restore the character that was saved before any return can happen. */
1223 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001224 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001225
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001226 /* If the property exists and is not an atom, just return here. */
1227 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001228 return 0;
1229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001230 /* The property is an atom. Trim all leading and trailing whitespace */
1231 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001232 sp = ep;
1233 ep = line + linelen;
1234
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001235 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001236 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001237 while ( *sp &&
1238 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001239 sp++;
1240
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001241 /* Trim the leading double quote if it exists. */
1242 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001243 sp++;
1244 *value = sp;
1245
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001246 /* Trim the trailing whitespace if it exists. */
1247 while ( ep > sp &&
1248 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001249 *--ep = 0;
1250
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001251 /* Trim the trailing double quote if it exists. */
1252 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001253 *--ep = 0;
1254
1255 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001256 }
David Turner993a8d02002-05-18 12:03:43 +00001257
1258
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 static FT_Error
1260 _bdf_add_property( bdf_font_t* font,
1261 char* name,
1262 char* value )
1263 {
1264 unsigned long propid;
1265 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001266 bdf_property_t *prop, *fp;
1267 FT_Memory memory = font->memory;
1268 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001269
David Turner993a8d02002-05-18 12:03:43 +00001270
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001271 /* First, check to see if the property already exists in the font. */
1272 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001273 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 /* The property already exists in the font, so simply replace */
1275 /* the value of the property with the current value. */
1276 fp = font->props + (unsigned long)hn->data;
1277
David Turnerb1b47622002-05-21 21:17:43 +00001278 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001279 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001280 case BDF_ATOM:
1281 /* Delete the current atom if it exists. */
1282 FT_FREE( fp->value.atom );
1283
David Turnerc0f9c4a2007-02-12 14:55:03 +00001284 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001286 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 break;
1290
1291 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001292 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001293 break;
1294
1295 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001296 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001297 break;
David Turnerd490e372002-05-28 23:40:37 +00001298
David Turnerb1b47622002-05-21 21:17:43 +00001299 default:
1300 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 }
David Turnerd490e372002-05-28 23:40:37 +00001302
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001303 goto Exit;
1304 }
1305
1306 /* See whether this property type exists yet or not. */
1307 /* If not, create it. */
1308 hn = hash_lookup( name, &(font->proptbl) );
1309 if ( hn == 0 )
1310 {
1311 error = bdf_create_property( name, BDF_ATOM, font );
1312 if ( error )
1313 goto Exit;
1314 hn = hash_lookup( name, &(font->proptbl) );
1315 }
1316
1317 /* Allocate another property if this is overflow. */
1318 if ( font->props_used == font->props_size )
1319 {
1320 if ( font->props_size == 0 )
1321 {
1322 if ( FT_NEW_ARRAY( font->props, 1 ) )
1323 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001324 }
1325 else
1326 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001327 if ( FT_RENEW_ARRAY( font->props,
1328 font->props_size,
1329 font->props_size + 1 ) )
1330 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001331 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001332
David Turner993a8d02002-05-18 12:03:43 +00001333 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001334 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001335 font->props_size++;
1336 }
1337
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001338 propid = (unsigned long)hn->data;
1339 if ( propid >= _num_bdf_properties )
1340 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001341 else
David Turnerb1b47622002-05-21 21:17:43 +00001342 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001343
1344 fp = font->props + font->props_used;
1345
1346 fp->name = prop->name;
1347 fp->format = prop->format;
1348 fp->builtin = prop->builtin;
1349
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001350 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001351 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001353 fp->value.atom = 0;
1354 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001355 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001356 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001358 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001359 break;
David Turner993a8d02002-05-18 12:03:43 +00001360
1361 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001362 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001363 break;
1364
1365 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001366 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001367 break;
David Turner993a8d02002-05-18 12:03:43 +00001368 }
1369
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001370 /* If the property happens to be a comment, then it doesn't need */
1371 /* to be added to the internal hash table. */
1372 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1373 /* Add the property to the font property table. */
1374 error = hash_insert( fp->name,
1375 (void *)font->props_used,
1376 (hashtable *)font->internal,
1377 memory );
1378 if ( error )
1379 goto Exit;
1380 }
David Turner993a8d02002-05-18 12:03:43 +00001381
1382 font->props_used++;
1383
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001384 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1385 /* property needs to be located if it exists in the property list, the */
1386 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1387 /* present, and the SPACING property should override the default */
1388 /* spacing. */
1389 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001390 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001391 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001392 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001394 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001396 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001397 if ( !fp->value.atom )
1398 {
1399 error = BDF_Err_Invalid_File_Format;
1400 goto Exit;
1401 }
1402
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001403 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001404 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001406 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001408 font->spacing = BDF_CHARCELL;
1409 }
1410
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411 Exit:
1412 return error;
David Turner993a8d02002-05-18 12:03:43 +00001413 }
1414
David Turner993a8d02002-05-18 12:03:43 +00001415
David Turnerb1b47622002-05-21 21:17:43 +00001416 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001417 {
1418 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1419 };
1420
1421
1422 /* Actually parse the glyph info and bitmaps. */
1423 static FT_Error
1424 _bdf_parse_glyphs( char* line,
1425 unsigned long linelen,
1426 unsigned long lineno,
1427 void* call_data,
1428 void* client_data )
1429 {
1430 int c, mask_index;
1431 char* s;
1432 unsigned char* bp;
1433 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001434
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001435 _bdf_parse_t* p;
1436 bdf_glyph_t* glyph;
1437 bdf_font_t* font;
1438
1439 FT_Memory memory;
1440 FT_Error error = BDF_Err_Ok;
1441
Werner Lemberg319c00d2003-04-23 19:48:24 +00001442 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443 FT_UNUSED( lineno ); /* only used in debug mode */
1444
1445
Werner Lemberg319c00d2003-04-23 19:48:24 +00001446 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447
1448 font = p->font;
1449 memory = font->memory;
1450
1451 /* Check for a comment. */
1452 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1453 {
1454 linelen -= 7;
1455
1456 s = line + 7;
1457 if ( *s != 0 )
1458 {
1459 s++;
1460 linelen--;
1461 }
1462 error = _bdf_add_comment( p->font, s, linelen );
1463 goto Exit;
1464 }
1465
1466 /* The very first thing expected is the number of glyphs. */
1467 if ( !( p->flags & _BDF_GLYPHS ) )
1468 {
1469 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1470 {
1471 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1472 error = BDF_Err_Missing_Chars_Field;
1473 goto Exit;
1474 }
1475
David Turner68df4f72005-03-15 18:18:57 +00001476 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001477 if ( error )
1478 goto Exit;
1479 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1480
1481 /* Make sure the number of glyphs is non-zero. */
1482 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001483 font->glyphs_size = 64;
1484
Werner Lemberga08b2172007-03-28 07:17:17 +00001485 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1486 /* number of code points available in Unicode). */
1487 if ( p->cnt >= 1114112UL )
1488 {
1489 error = BDF_Err_Invalid_Argument;
1490 goto Exit;
1491 }
1492
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001493 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1494 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001495
David Turner993a8d02002-05-18 12:03:43 +00001496 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001497
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001498 goto Exit;
1499 }
1500
1501 /* Check for the ENDFONT field. */
1502 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1503 {
1504 /* Sort the glyphs by encoding. */
1505 ft_qsort( (char *)font->glyphs,
1506 font->glyphs_used,
1507 sizeof ( bdf_glyph_t ),
1508 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001509
1510 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001511
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001512 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001513 }
1514
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001515 /* Check for the ENDCHAR field. */
1516 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1517 {
1518 p->glyph_enc = 0;
1519 p->flags &= ~_BDF_GLYPH_BITS;
1520
1521 goto Exit;
1522 }
1523
1524 /* Check to see whether a glyph is being scanned but should be */
1525 /* ignored because it is an unencoded glyph. */
1526 if ( ( p->flags & _BDF_GLYPH ) &&
1527 p->glyph_enc == -1 &&
1528 p->opts->keep_unencoded == 0 )
1529 goto Exit;
1530
1531 /* Check for the STARTCHAR field. */
1532 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1533 {
1534 /* Set the character name in the parse info first until the */
1535 /* encoding can be checked for an unencoded character. */
1536 FT_FREE( p->glyph_name );
1537
David Turner68df4f72005-03-15 18:18:57 +00001538 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001539 if ( error )
1540 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541
David Turner68df4f72005-03-15 18:18:57 +00001542 _bdf_list_shift( &p->list, 1 );
1543
1544 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001545
Werner Lembergba03af62007-05-30 13:57:02 +00001546 if ( !s )
1547 {
1548 error = BDF_Err_Invalid_File_Format;
1549 goto Exit;
1550 }
1551
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001552 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1553 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001554
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001555 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1556
1557 p->flags |= _BDF_GLYPH;
1558
1559 goto Exit;
1560 }
1561
1562 /* Check for the ENCODING field. */
1563 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1564 {
1565 if ( !( p->flags & _BDF_GLYPH ) )
1566 {
1567 /* Missing STARTCHAR field. */
1568 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1569 error = BDF_Err_Missing_Startchar_Field;
1570 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001571 }
1572
David Turner68df4f72005-03-15 18:18:57 +00001573 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001574 if ( error )
1575 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001576
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001577 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001578
David Turner481838e2006-02-23 12:40:14 +00001579 /* Check that the encoding is in the range [0,65536] because */
1580 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001581 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001582 {
1583 error = BDF_Err_Invalid_File_Format;
1584 goto Exit;
1585 }
1586
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001587 /* Check to see whether this encoding has already been encountered. */
1588 /* If it has then change it to unencoded so it gets added if */
1589 /* indicated. */
1590 if ( p->glyph_enc >= 0 )
1591 {
1592 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1593 {
1594 /* Emit a message saying a glyph has been moved to the */
1595 /* unencoded area. */
1596 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1597 p->glyph_enc, p->glyph_name ));
1598 p->glyph_enc = -1;
1599 font->modified = 1;
1600 }
1601 else
1602 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1603 }
1604
1605 if ( p->glyph_enc >= 0 )
1606 {
1607 /* Make sure there are enough glyphs allocated in case the */
1608 /* number of characters happen to be wrong. */
1609 if ( font->glyphs_used == font->glyphs_size )
1610 {
1611 if ( FT_RENEW_ARRAY( font->glyphs,
1612 font->glyphs_size,
1613 font->glyphs_size + 64 ) )
1614 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001615
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001616 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001617 }
1618
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001619 glyph = font->glyphs + font->glyphs_used++;
1620 glyph->name = p->glyph_name;
1621 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001622
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001623 /* Reset the initial glyph info. */
1624 p->glyph_name = 0;
1625 }
1626 else
1627 {
1628 /* Unencoded glyph. Check to see whether it should */
1629 /* be added or not. */
1630 if ( p->opts->keep_unencoded != 0 )
1631 {
1632 /* Allocate the next unencoded glyph. */
1633 if ( font->unencoded_used == font->unencoded_size )
1634 {
David Turner68df4f72005-03-15 18:18:57 +00001635 if ( FT_RENEW_ARRAY( font->unencoded ,
1636 font->unencoded_size,
1637 font->unencoded_size + 4 ) )
1638 goto Exit;
1639
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001640 font->unencoded_size += 4;
1641 }
1642
1643 glyph = font->unencoded + font->unencoded_used;
1644 glyph->name = p->glyph_name;
1645 glyph->encoding = font->unencoded_used++;
1646 }
1647 else
1648 /* Free up the glyph name if the unencoded shouldn't be */
1649 /* kept. */
1650 FT_FREE( p->glyph_name );
1651
1652 p->glyph_name = 0;
1653 }
1654
1655 /* Clear the flags that might be added when width and height are */
1656 /* checked for consistency. */
1657 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1658
1659 p->flags |= _BDF_ENCODING;
1660
1661 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001662 }
1663
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001664 /* Point at the glyph being constructed. */
1665 if ( p->glyph_enc == -1 )
1666 glyph = font->unencoded + ( font->unencoded_used - 1 );
1667 else
1668 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001669
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001670 /* Check to see whether a bitmap is being constructed. */
1671 if ( p->flags & _BDF_BITMAP )
1672 {
1673 /* If there are more rows than are specified in the glyph metrics, */
1674 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001675 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001676 {
1677 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1678 {
1679 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1680 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001681 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001682 }
1683
1684 goto Exit;
1685 }
1686
1687 /* Only collect the number of nibbles indicated by the glyph */
1688 /* metrics. If there are more columns, they are simply ignored. */
1689 nibbles = glyph->bpr << 1;
1690 bp = glyph->bitmap + p->row * glyph->bpr;
1691
David Turnerb698eed2006-02-23 14:50:13 +00001692 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001693 {
1694 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001695 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001696 if ( i + 1 < nibbles && ( i & 1 ) )
1697 *++bp = 0;
1698 }
1699
1700 /* Remove possible garbage at the right. */
1701 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001702 if ( glyph->bbx.width )
1703 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001704
1705 /* If any line has extra columns, indicate they have been removed. */
1706 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1707 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1708 {
1709 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1710 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1711 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001712 }
1713
1714 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001715 goto Exit;
1716 }
David Turner993a8d02002-05-18 12:03:43 +00001717
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001718 /* Expect the SWIDTH (scalable width) field next. */
1719 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1720 {
1721 if ( !( p->flags & _BDF_ENCODING ) )
1722 {
1723 /* Missing ENCODING field. */
1724 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1725 error = BDF_Err_Missing_Encoding_Field;
1726 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001727 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001728
David Turner68df4f72005-03-15 18:18:57 +00001729 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001730 if ( error )
1731 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001732
David Turnerb1b47622002-05-21 21:17:43 +00001733 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001734 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001735
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001736 goto Exit;
1737 }
David Turner993a8d02002-05-18 12:03:43 +00001738
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001739 /* Expect the DWIDTH (scalable width) field next. */
1740 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1741 {
David Turner68df4f72005-03-15 18:18:57 +00001742 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001743 if ( error )
1744 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001745
David Turnerb1b47622002-05-21 21:17:43 +00001746 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001747
1748 if ( !( p->flags & _BDF_SWIDTH ) )
1749 {
1750 /* Missing SWIDTH field. Emit an auto correction message and set */
1751 /* the scalable width from the device width. */
1752 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1753
Werner Lemberg02d4d592002-05-28 22:38:05 +00001754 glyph->swidth = (unsigned short)FT_MulDiv(
1755 glyph->dwidth, 72000L,
1756 (FT_Long)( font->point_size *
1757 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001758 }
1759
1760 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001761 goto Exit;
1762 }
David Turner993a8d02002-05-18 12:03:43 +00001763
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001764 /* Expect the BBX field next. */
1765 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1766 {
David Turner68df4f72005-03-15 18:18:57 +00001767 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001768 if ( error )
1769 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001770
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001771 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1772 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1773 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1774 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1775
1776 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001777 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1778 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001779
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 /* Determine the overall font bounding box as the characters are */
1781 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001782 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1783 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001784
David Turnerb1b47622002-05-21 21:17:43 +00001785 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001786
Werner Lembergdfa46192004-03-05 09:26:24 +00001787 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1788 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1789 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001790
1791 if ( !( p->flags & _BDF_DWIDTH ) )
1792 {
1793 /* Missing DWIDTH field. Emit an auto correction message and set */
1794 /* the device width to the glyph width. */
1795 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1796 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001797 }
1798
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1800 /* value if necessary. */
1801 if ( p->opts->correct_metrics != 0 )
1802 {
1803 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001804 unsigned short sw = (unsigned short)FT_MulDiv(
1805 glyph->dwidth, 72000L,
1806 (FT_Long)( font->point_size *
1807 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001808
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001809
1810 if ( sw != glyph->swidth )
1811 {
1812 glyph->swidth = sw;
1813
1814 if ( p->glyph_enc == -1 )
1815 _bdf_set_glyph_modified( font->umod,
1816 font->unencoded_used - 1 );
1817 else
1818 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1819
1820 p->flags |= _BDF_SWIDTH_ADJ;
1821 font->modified = 1;
1822 }
David Turner993a8d02002-05-18 12:03:43 +00001823 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001824
David Turner993a8d02002-05-18 12:03:43 +00001825 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001826 goto Exit;
1827 }
David Turner993a8d02002-05-18 12:03:43 +00001828
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001829 /* And finally, gather up the bitmap. */
1830 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1831 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001832 unsigned long bitmap_size;
1833
1834
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001835 if ( !( p->flags & _BDF_BBX ) )
1836 {
1837 /* Missing BBX field. */
1838 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1839 error = BDF_Err_Missing_Bbx_Field;
1840 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001841 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001842
1843 /* Allocate enough space for the bitmap. */
1844 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001845
1846 bitmap_size = glyph->bpr * glyph->bbx.height;
1847 if ( bitmap_size > 0xFFFFU )
1848 {
1849 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1850 error = BDF_Err_Bbx_Too_Big;
1851 goto Exit;
1852 }
1853 else
1854 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001855
1856 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1857 goto Exit;
1858
1859 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001860 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001861
1862 goto Exit;
1863 }
1864
1865 error = BDF_Err_Invalid_File_Format;
1866
1867 Exit:
1868 return error;
David Turner993a8d02002-05-18 12:03:43 +00001869 }
1870
David Turner993a8d02002-05-18 12:03:43 +00001871
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001872 /* Load the font properties. */
1873 static FT_Error
1874 _bdf_parse_properties( char* line,
1875 unsigned long linelen,
1876 unsigned long lineno,
1877 void* call_data,
1878 void* client_data )
1879 {
1880 unsigned long vlen;
1881 _bdf_line_func_t* next;
1882 _bdf_parse_t* p;
1883 char* name;
1884 char* value;
1885 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001886 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001887
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001888 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001889
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001890
1891 next = (_bdf_line_func_t *)call_data;
1892 p = (_bdf_parse_t *) client_data;
1893
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001894 /* Check for the end of the properties. */
1895 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1896 {
1897 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1898 /* encountered yet, then make sure they are added as properties and */
1899 /* make sure they are set from the font bounding box info. */
1900 /* */
1901 /* This is *always* done regardless of the options, because X11 */
1902 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001903 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001904 {
1905 p->font->font_ascent = p->font->bbx.ascent;
1906 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1907 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1908 if ( error )
1909 goto Exit;
1910
1911 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1912 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001913 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001914
Werner Lemberg428c2e42003-04-25 05:35:04 +00001915 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916 {
1917 p->font->font_descent = p->font->bbx.descent;
1918 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1919 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1920 if ( error )
1921 goto Exit;
1922
1923 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1924 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001925 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926
David Turner993a8d02002-05-18 12:03:43 +00001927 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001929
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001930 goto Exit;
1931 }
David Turner993a8d02002-05-18 12:03:43 +00001932
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001933 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1934 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1935 goto Exit;
1936
1937 /* Handle COMMENT fields and properties in a special way to preserve */
1938 /* the spacing. */
1939 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1940 {
David Turner993a8d02002-05-18 12:03:43 +00001941 name = value = line;
1942 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001943 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001944 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 error = _bdf_add_property( p->font, name, value );
1946 if ( error )
1947 goto Exit;
1948 }
1949 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1950 {
1951 error = _bdf_add_property( p->font, name, value );
1952 if ( error )
1953 goto Exit;
1954 }
1955 else
1956 {
David Turner68df4f72005-03-15 18:18:57 +00001957 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001958 if ( error )
1959 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001960 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001961
David Turner68df4f72005-03-15 18:18:57 +00001962 _bdf_list_shift( &p->list, 1 );
1963 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001964
1965 error = _bdf_add_property( p->font, name, value );
1966 if ( error )
1967 goto Exit;
1968 }
1969
1970 Exit:
1971 return error;
David Turner993a8d02002-05-18 12:03:43 +00001972 }
1973
David Turner993a8d02002-05-18 12:03:43 +00001974
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001975 /* Load the font header. */
1976 static FT_Error
1977 _bdf_parse_start( char* line,
1978 unsigned long linelen,
1979 unsigned long lineno,
1980 void* call_data,
1981 void* client_data )
1982 {
1983 unsigned long slen;
1984 _bdf_line_func_t* next;
1985 _bdf_parse_t* p;
1986 bdf_font_t* font;
1987 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001988
David Turnerd490e372002-05-28 23:40:37 +00001989 FT_Memory memory = NULL;
1990 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001991
1992 FT_UNUSED( lineno ); /* only used in debug mode */
1993
1994
1995 next = (_bdf_line_func_t *)call_data;
1996 p = (_bdf_parse_t *) client_data;
1997
1998 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00001999 memory = p->font->memory;
2000
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002001 /* Check for a comment. This is done to handle those fonts that have */
2002 /* comments before the STARTFONT line for some reason. */
2003 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2004 {
2005 if ( p->opts->keep_comments != 0 && p->font != 0 )
2006 {
2007 linelen -= 7;
2008
2009 s = line + 7;
2010 if ( *s != 0 )
2011 {
2012 s++;
2013 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002014 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002015
2016 error = _bdf_add_comment( p->font, s, linelen );
2017 if ( error )
2018 goto Exit;
2019 /* here font is not defined! */
2020 }
2021
2022 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002023 }
2024
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002025 if ( !( p->flags & _BDF_START ) )
2026 {
2027 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002028
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002029 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2030 {
2031 /* No STARTFONT field is a good indication of a problem. */
2032 error = BDF_Err_Missing_Startfont_Field;
2033 goto Exit;
2034 }
David Turner993a8d02002-05-18 12:03:43 +00002035
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036 p->flags = _BDF_START;
2037 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002038
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002039 if ( FT_NEW( font ) )
2040 goto Exit;
2041 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002042
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 font->memory = p->memory;
2044 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002045
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046 { /* setup */
2047 unsigned long i;
2048 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002049
David Turner993a8d02002-05-18 12:03:43 +00002050
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002051 error = hash_init( &(font->proptbl), memory );
2052 if ( error )
2053 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002054 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 i < _num_bdf_properties; i++, prop++ )
2056 {
2057 error = hash_insert( prop->name, (void *)i,
2058 &(font->proptbl), memory );
2059 if ( error )
2060 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002061 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002062 }
2063
2064 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2065 goto Exit;
2066 error = hash_init( (hashtable *)p->font->internal,memory );
2067 if ( error )
2068 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002069 p->font->spacing = p->opts->font_spacing;
2070 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002071
2072 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002073 }
2074
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002075 /* Check for the start of the properties. */
2076 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2077 {
David Turner68df4f72005-03-15 18:18:57 +00002078 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002079 if ( error )
2080 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002081 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2083
2084 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2085 goto Exit;
2086
2087 p->flags |= _BDF_PROPS;
2088 *next = _bdf_parse_properties;
2089
2090 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002091 }
2092
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002093 /* Check for the FONTBOUNDINGBOX field. */
2094 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2095 {
2096 if ( !(p->flags & _BDF_SIZE ) )
2097 {
2098 /* Missing the SIZE field. */
2099 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2100 error = BDF_Err_Missing_Size_Field;
2101 goto Exit;
2102 }
2103
David Turner68df4f72005-03-15 18:18:57 +00002104 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002105 if ( error )
2106 goto Exit;
2107
2108 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2109 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2110
2111 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2112 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2113
David Turnerd490e372002-05-28 23:40:37 +00002114 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002115 p->font->bbx.y_offset );
2116
2117 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002118
2119 p->flags |= _BDF_FONT_BBX;
2120
2121 goto Exit;
2122 }
2123
2124 /* The next thing to check for is the FONT field. */
2125 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2126 {
David Turner68df4f72005-03-15 18:18:57 +00002127 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002128 if ( error )
2129 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002130 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002131
David Turner68df4f72005-03-15 18:18:57 +00002132 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002133
2134 if ( !s )
2135 {
2136 error = BDF_Err_Invalid_File_Format;
2137 goto Exit;
2138 }
2139
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002140 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2141 goto Exit;
2142 FT_MEM_COPY( p->font->name, s, slen + 1 );
2143
2144 /* If the font name is an XLFD name, set the spacing to the one in */
2145 /* the font name. If there is no spacing fall back on the default. */
2146 error = _bdf_set_default_spacing( p->font, p->opts );
2147 if ( error )
2148 goto Exit;
2149
2150 p->flags |= _BDF_FONT_NAME;
2151
2152 goto Exit;
2153 }
2154
2155 /* Check for the SIZE field. */
2156 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2157 {
2158 if ( !( p->flags & _BDF_FONT_NAME ) )
2159 {
2160 /* Missing the FONT field. */
2161 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2162 error = BDF_Err_Missing_Font_Field;
2163 goto Exit;
2164 }
2165
David Turner68df4f72005-03-15 18:18:57 +00002166 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002167 if ( error )
2168 goto Exit;
2169
2170 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2171 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2172 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2173
2174 /* Check for the bits per pixel field. */
2175 if ( p->list.used == 5 )
2176 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002177 unsigned short bitcount, i, shift;
2178
2179
2180 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2181
2182 /* Only values 1, 2, 4, 8 are allowed. */
2183 shift = p->font->bpp;
2184 bitcount = 0;
2185 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002186 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002187 if ( shift & 1 )
2188 bitcount = i;
2189 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002190 }
David Turner993a8d02002-05-18 12:03:43 +00002191
Werner Lembergbd8e3242002-06-12 08:43:58 +00002192 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002193
2194 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002195 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002196 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002197 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002198 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002199 }
2200 }
2201 else
2202 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002203
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002204 p->flags |= _BDF_SIZE;
2205
2206 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002207 }
2208
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002209 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 Exit:
2212 return error;
2213 }
David Turner993a8d02002-05-18 12:03:43 +00002214
2215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002216 /*************************************************************************/
2217 /* */
2218 /* API. */
2219 /* */
2220 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002221
David Turner993a8d02002-05-18 12:03:43 +00002222
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002223 FT_LOCAL_DEF( FT_Error )
2224 bdf_load_font( FT_Stream stream,
2225 FT_Memory extmemory,
2226 bdf_options_t* opts,
2227 bdf_font_t* *font )
2228 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002229 unsigned long lineno = 0; /* make compiler happy */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002230 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002231
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002232 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002233 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002234
2235
David Turner68df4f72005-03-15 18:18:57 +00002236 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002237 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002239 memory = NULL;
2240 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2241 p->minlb = 32767;
2242 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002243
David Turner68df4f72005-03-15 18:18:57 +00002244 _bdf_list_init( &p->list, extmemory );
2245
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002246 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002247 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002249 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002250
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002251 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002252 {
2253 /* If the font is not proportional, set the font's monowidth */
2254 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002255 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002256
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002257 if ( p->font->spacing != BDF_PROPORTIONAL )
2258 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002259
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002260 /* If the number of glyphs loaded is not that of the original count, */
2261 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002262 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002263 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002264 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2265 p->font->glyphs_used + p->font->unencoded_used ));
2266 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002267 }
2268
2269 /* Once the font has been loaded, adjust the overall font metrics if */
2270 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002271 if ( p->opts->correct_metrics != 0 &&
2272 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002273 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002274 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002275 {
2276 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002277 p->font->bbx.width, p->maxrb - p->minlb ));
2278 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2279 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002280 }
2281
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002282 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002283 {
2284 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002285 p->font->bbx.x_offset, p->minlb ));
2286 p->font->bbx.x_offset = p->minlb;
2287 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002288 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002289
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002290 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002291 {
2292 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002293 p->font->bbx.ascent, p->maxas ));
2294 p->font->bbx.ascent = p->maxas;
2295 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296 }
2297
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002298 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002299 {
2300 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002301 p->font->bbx.descent, p->maxds ));
2302 p->font->bbx.descent = p->maxds;
2303 p->font->bbx.y_offset = (short)( -p->maxds );
2304 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002305 }
2306
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002307 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002308 {
2309 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002310 p->font->bbx.height, p->maxas + p->maxds ));
2311 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002312 }
2313
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002314 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002315 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2316 }
David Turner993a8d02002-05-18 12:03:43 +00002317 }
2318
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002319 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002320 {
2321 {
2322 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002323 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg5b591e42007-06-01 22:16:43 +00002324 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002325 /* Error happened while parsing header. */
2326 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002327 error = BDF_Err_Corrupted_Font_Header;
2328 goto Exit;
2329 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002330 else
Werner Lemberg5b591e42007-06-01 22:16:43 +00002331 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002332 /* Error happened when parsing glyphs. */
2333 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002334 error = BDF_Err_Corrupted_Font_Glyphs;
2335 goto Exit;
2336 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002337 }
David Turner993a8d02002-05-18 12:03:43 +00002338 }
2339
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002340 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002341 {
2342 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002343 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002344
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002345 if ( p->font->comments_len > 0 ) {
2346 if ( FT_RENEW_ARRAY( p->font->comments,
2347 p->font->comments_len,
2348 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002349 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002350
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002351 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002352 }
David Turner993a8d02002-05-18 12:03:43 +00002353 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002354 else if ( error == BDF_Err_Ok )
2355 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002356
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002357 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002358
2359 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002360 if ( p )
2361 {
David Turner68df4f72005-03-15 18:18:57 +00002362 _bdf_list_done( &p->list );
2363
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002364 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002365
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002366 FT_FREE( p );
2367 }
2368
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002369 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002370
2371 Fail:
2372 bdf_free_font( p->font );
2373
2374 memory = extmemory;
2375
2376 FT_FREE( p->font );
2377
2378 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002379 }
David Turner993a8d02002-05-18 12:03:43 +00002380
2381
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002382 FT_LOCAL_DEF( void )
2383 bdf_free_font( bdf_font_t* font )
2384 {
2385 bdf_property_t* prop;
2386 unsigned long i;
2387 bdf_glyph_t* glyphs;
2388 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002389
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002390
2391 if ( font == 0 )
2392 return;
David Turner993a8d02002-05-18 12:03:43 +00002393
2394 memory = font->memory;
2395
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002396 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002397
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002398 /* Free up the internal hash table of property names. */
2399 if ( font->internal )
2400 {
2401 hash_free( (hashtable *)font->internal, memory );
2402 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002403 }
2404
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002405 /* Free up the comment info. */
2406 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002407
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002408 /* Free up the properties. */
2409 for ( i = 0; i < font->props_size; i++ )
2410 {
2411 if ( font->props[i].format == BDF_ATOM )
2412 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002413 }
2414
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002415 FT_FREE( font->props );
2416
2417 /* Free up the character info. */
2418 for ( i = 0, glyphs = font->glyphs;
2419 i < font->glyphs_used; i++, glyphs++ )
2420 {
2421 FT_FREE( glyphs->name );
2422 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002423 }
2424
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002425 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2426 i++, glyphs++ )
2427 {
2428 FT_FREE( glyphs->name );
2429 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002430 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002431
2432 FT_FREE( font->glyphs );
2433 FT_FREE( font->unencoded );
2434
2435 /* Free up the overflow storage if it was used. */
2436 for ( i = 0, glyphs = font->overflow.glyphs;
2437 i < font->overflow.glyphs_used; i++, glyphs++ )
2438 {
2439 FT_FREE( glyphs->name );
2440 FT_FREE( glyphs->bitmap );
2441 }
2442
2443 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002444
2445 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002446 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002447
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 /* Free up the user defined properties. */
2449 for (prop = font->user_props, i = 0;
2450 i < font->nuser_props; i++, prop++ )
2451 {
2452 FT_FREE( prop->name );
2453 if ( prop->format == BDF_ATOM )
2454 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002455 }
David Turner993a8d02002-05-18 12:03:43 +00002456
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002457 FT_FREE( font->user_props );
2458
2459 /* FREE( font ); */ /* XXX Fixme */
2460 }
David Turner993a8d02002-05-18 12:03:43 +00002461
2462
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002463 FT_LOCAL_DEF( bdf_property_t * )
2464 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002465 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002466 {
2467 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002468
David Turner993a8d02002-05-18 12:03:43 +00002469
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002470 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002471 return 0;
2472
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002473 hn = hash_lookup( name, (hashtable *)font->internal );
2474
2475 return hn ? ( font->props + (unsigned long)hn->data ) : 0;
2476 }
2477
2478
2479/* END */