blob: 5fa5868c7158a4dbb71e08339759d6e37369aa48 [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,
suzuki toshiya704f4d72009-09-13 00:50:14 +0900284 size_t data,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000285 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 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900974 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000975 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
suzuki toshiya704f4d72009-09-13 00:50:14 +0900994 n = ft_strlen( name ) + 1;
995 if ( n > FT_ULONG_MAX )
996 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +0000997
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000998 if ( FT_NEW_ARRAY( p->name, n ) )
999 goto Exit;
1000
1001 FT_MEM_COPY( (char *)p->name, name, n );
1002
1003 p->format = format;
1004 p->builtin = 0;
1005
1006 n = _num_bdf_properties + font->nuser_props;
1007
suzuki toshiya704f4d72009-09-13 00:50:14 +09001008 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001009 if ( error )
1010 goto Exit;
1011
1012 font->nuser_props++;
1013
1014 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001015 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001016 }
David Turner993a8d02002-05-18 12:03:43 +00001017
1018
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001019 FT_LOCAL_DEF( bdf_property_t * )
1020 bdf_get_property( char* name,
1021 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001022 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001023 hashnode hn;
1024 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025
1026
1027 if ( name == 0 || *name == 0 )
1028 return 0;
1029
1030 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1031 return 0;
1032
suzuki toshiya704f4d72009-09-13 00:50:14 +09001033 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001034 if ( propid >= _num_bdf_properties )
1035 return font->user_props + ( propid - _num_bdf_properties );
1036
Werner Lemberg233302a2002-05-22 05:41:06 +00001037 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001038 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001039
1040
1041 /*************************************************************************/
1042 /* */
1043 /* BDF font file parsing flags and functions. */
1044 /* */
1045 /*************************************************************************/
1046
1047
1048 /* Parse flags. */
1049
1050#define _BDF_START 0x0001
1051#define _BDF_FONT_NAME 0x0002
1052#define _BDF_SIZE 0x0004
1053#define _BDF_FONT_BBX 0x0008
1054#define _BDF_PROPS 0x0010
1055#define _BDF_GLYPHS 0x0020
1056#define _BDF_GLYPH 0x0040
1057#define _BDF_ENCODING 0x0080
1058#define _BDF_SWIDTH 0x0100
1059#define _BDF_DWIDTH 0x0200
1060#define _BDF_BBX 0x0400
1061#define _BDF_BITMAP 0x0800
1062
1063#define _BDF_SWIDTH_ADJ 0x1000
1064
1065#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1066 _BDF_ENCODING | \
1067 _BDF_SWIDTH | \
1068 _BDF_DWIDTH | \
1069 _BDF_BBX | \
1070 _BDF_BITMAP )
1071
Werner Lembergf1c2b912006-01-13 14:53:28 +00001072#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1073#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001074
1075
1076 /* Auto correction messages. */
1077#define ACMSG1 "FONT_ASCENT property missing. " \
1078 "Added \"FONT_ASCENT %hd\".\n"
1079#define ACMSG2 "FONT_DESCENT property missing. " \
1080 "Added \"FONT_DESCENT %hd\".\n"
1081#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1082#define ACMSG4 "Font left bearing != actual left bearing. " \
1083 "Old: %hd New: %hd.\n"
1084#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1085#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1086#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1087#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1088#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1089#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1090#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1091#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1092#define ACMSG13 "Glyph %ld extra rows removed.\n"
1093#define ACMSG14 "Glyph %ld extra columns removed.\n"
1094#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1095
1096 /* Error messages. */
1097#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1098#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1099#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
Werner Lemberg26170df2006-03-26 07:19:07 +00001100#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001101
1102
1103 static FT_Error
1104 _bdf_add_comment( bdf_font_t* font,
1105 char* comment,
1106 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001107 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001108 char* cp;
1109 FT_Memory memory = font->memory;
1110 FT_Error error = BDF_Err_Ok;
1111
1112
David Turner68df4f72005-03-15 18:18:57 +00001113 if ( FT_RENEW_ARRAY( font->comments,
1114 font->comments_len,
1115 font->comments_len + len + 1 ) )
1116 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001117
1118 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001119
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001120 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001121 cp[len] = '\n';
1122
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001123 font->comments_len += len + 1;
1124
1125 Exit:
1126 return error;
David Turner993a8d02002-05-18 12:03:43 +00001127 }
1128
David Turner993a8d02002-05-18 12:03:43 +00001129
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001130 /* Set the spacing from the font name if it exists, or set it to the */
1131 /* default specified in the options. */
1132 static FT_Error
1133 _bdf_set_default_spacing( bdf_font_t* font,
1134 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001135 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001136 size_t len;
1137 char name[256];
1138 _bdf_list_t list;
1139 FT_Memory memory;
1140 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001141
David Turner993a8d02002-05-18 12:03:43 +00001142
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001143 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1144 {
1145 error = BDF_Err_Invalid_Argument;
1146 goto Exit;
1147 }
David Turner993a8d02002-05-18 12:03:43 +00001148
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001149 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001150
David Turner68df4f72005-03-15 18:18:57 +00001151 _bdf_list_init( &list, memory );
1152
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001153 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001154
suzuki toshiya704f4d72009-09-13 00:50:14 +09001155 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001156 /* Limit ourselves to 256 characters in the font name. */
1157 if ( len >= 256 )
1158 {
1159 error = BDF_Err_Invalid_Argument;
1160 goto Exit;
1161 }
1162
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001163 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001164
David Turner68df4f72005-03-15 18:18:57 +00001165 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001166 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001167 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001168
1169 if ( list.used == 15 )
1170 {
1171 switch ( list.field[11][0] )
1172 {
1173 case 'C':
1174 case 'c':
1175 font->spacing = BDF_CHARCELL;
1176 break;
1177 case 'M':
1178 case 'm':
1179 font->spacing = BDF_MONOWIDTH;
1180 break;
1181 case 'P':
1182 case 'p':
1183 font->spacing = BDF_PROPORTIONAL;
1184 break;
David Turner993a8d02002-05-18 12:03:43 +00001185 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001186 }
1187
David Turner68df4f72005-03-15 18:18:57 +00001188 Fail:
1189 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001190
1191 Exit:
1192 return error;
David Turner993a8d02002-05-18 12:03:43 +00001193 }
David Turner993a8d02002-05-18 12:03:43 +00001194
1195
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001196 /* Determine whether the property is an atom or not. If it is, then */
1197 /* clean it up so the double quotes are removed if they exist. */
1198 static int
1199 _bdf_is_atom( char* line,
1200 unsigned long linelen,
1201 char** name,
1202 char** value,
1203 bdf_font_t* font )
1204 {
1205 int hold;
1206 char *sp, *ep;
1207 bdf_property_t* p;
1208
David Turner993a8d02002-05-18 12:03:43 +00001209
1210 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001211
1212 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001213 ep++;
1214
1215 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001216 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001217 {
1218 hold = *ep;
1219 *ep = 0;
1220 }
1221
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001223
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001224 /* Restore the character that was saved before any return can happen. */
1225 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001226 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001227
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001228 /* If the property exists and is not an atom, just return here. */
1229 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001230 return 0;
1231
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001232 /* The property is an atom. Trim all leading and trailing whitespace */
1233 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001234 sp = ep;
1235 ep = line + linelen;
1236
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001237 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001238 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001239 while ( *sp &&
1240 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001241 sp++;
1242
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001243 /* Trim the leading double quote if it exists. */
1244 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001245 sp++;
1246 *value = sp;
1247
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001248 /* Trim the trailing whitespace if it exists. */
1249 while ( ep > sp &&
1250 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001251 *--ep = 0;
1252
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001253 /* Trim the trailing double quote if it exists. */
1254 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001255 *--ep = 0;
1256
1257 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001258 }
David Turner993a8d02002-05-18 12:03:43 +00001259
1260
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001261 static FT_Error
1262 _bdf_add_property( bdf_font_t* font,
1263 char* name,
1264 char* value )
1265 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001266 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001267 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001268 bdf_property_t *prop, *fp;
1269 FT_Memory memory = font->memory;
1270 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001271
David Turner993a8d02002-05-18 12:03:43 +00001272
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001273 /* First, check to see if the property already exists in the font. */
1274 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001275 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001276 /* The property already exists in the font, so simply replace */
1277 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001278 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279
David Turnerb1b47622002-05-21 21:17:43 +00001280 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001281 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001282 case BDF_ATOM:
1283 /* Delete the current atom if it exists. */
1284 FT_FREE( fp->value.atom );
1285
David Turnerc0f9c4a2007-02-12 14:55:03 +00001286 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001287 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001288 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001289 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001290 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 break;
1292
1293 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001294 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001295 break;
1296
1297 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001298 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001299 break;
David Turnerd490e372002-05-28 23:40:37 +00001300
David Turnerb1b47622002-05-21 21:17:43 +00001301 default:
1302 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001303 }
David Turnerd490e372002-05-28 23:40:37 +00001304
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001305 goto Exit;
1306 }
1307
1308 /* See whether this property type exists yet or not. */
1309 /* If not, create it. */
1310 hn = hash_lookup( name, &(font->proptbl) );
1311 if ( hn == 0 )
1312 {
1313 error = bdf_create_property( name, BDF_ATOM, font );
1314 if ( error )
1315 goto Exit;
1316 hn = hash_lookup( name, &(font->proptbl) );
1317 }
1318
1319 /* Allocate another property if this is overflow. */
1320 if ( font->props_used == font->props_size )
1321 {
1322 if ( font->props_size == 0 )
1323 {
1324 if ( FT_NEW_ARRAY( font->props, 1 ) )
1325 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001326 }
1327 else
1328 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001329 if ( FT_RENEW_ARRAY( font->props,
1330 font->props_size,
1331 font->props_size + 1 ) )
1332 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001333 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001334
David Turner993a8d02002-05-18 12:03:43 +00001335 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001336 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001337 font->props_size++;
1338 }
1339
suzuki toshiya704f4d72009-09-13 00:50:14 +09001340 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001341 if ( propid >= _num_bdf_properties )
1342 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001343 else
David Turnerb1b47622002-05-21 21:17:43 +00001344 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001345
1346 fp = font->props + font->props_used;
1347
1348 fp->name = prop->name;
1349 fp->format = prop->format;
1350 fp->builtin = prop->builtin;
1351
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001352 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001353 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001354 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001355 fp->value.atom = 0;
1356 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001357 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001358 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001359 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001361 break;
David Turner993a8d02002-05-18 12:03:43 +00001362
1363 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001364 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001365 break;
1366
1367 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001368 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001369 break;
David Turner993a8d02002-05-18 12:03:43 +00001370 }
1371
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001372 /* If the property happens to be a comment, then it doesn't need */
1373 /* to be added to the internal hash table. */
1374 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 ) {
1375 /* Add the property to the font property table. */
1376 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001377 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378 (hashtable *)font->internal,
1379 memory );
1380 if ( error )
1381 goto Exit;
1382 }
David Turner993a8d02002-05-18 12:03:43 +00001383
1384 font->props_used++;
1385
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001386 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1387 /* property needs to be located if it exists in the property list, the */
1388 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1389 /* present, and the SPACING property should override the default */
1390 /* spacing. */
1391 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001392 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001394 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001396 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001398 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001399 if ( !fp->value.atom )
1400 {
1401 error = BDF_Err_Invalid_File_Format;
1402 goto Exit;
1403 }
1404
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001405 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001406 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001408 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001409 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001410 font->spacing = BDF_CHARCELL;
1411 }
1412
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001413 Exit:
1414 return error;
David Turner993a8d02002-05-18 12:03:43 +00001415 }
1416
David Turner993a8d02002-05-18 12:03:43 +00001417
David Turnerb1b47622002-05-21 21:17:43 +00001418 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001419 {
1420 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1421 };
1422
1423
1424 /* Actually parse the glyph info and bitmaps. */
1425 static FT_Error
1426 _bdf_parse_glyphs( char* line,
1427 unsigned long linelen,
1428 unsigned long lineno,
1429 void* call_data,
1430 void* client_data )
1431 {
1432 int c, mask_index;
1433 char* s;
1434 unsigned char* bp;
1435 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001436
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001437 _bdf_parse_t* p;
1438 bdf_glyph_t* glyph;
1439 bdf_font_t* font;
1440
1441 FT_Memory memory;
1442 FT_Error error = BDF_Err_Ok;
1443
Werner Lemberg319c00d2003-04-23 19:48:24 +00001444 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001445 FT_UNUSED( lineno ); /* only used in debug mode */
1446
1447
Werner Lemberg319c00d2003-04-23 19:48:24 +00001448 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001449
1450 font = p->font;
1451 memory = font->memory;
1452
1453 /* Check for a comment. */
1454 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1455 {
1456 linelen -= 7;
1457
1458 s = line + 7;
1459 if ( *s != 0 )
1460 {
1461 s++;
1462 linelen--;
1463 }
1464 error = _bdf_add_comment( p->font, s, linelen );
1465 goto Exit;
1466 }
1467
1468 /* The very first thing expected is the number of glyphs. */
1469 if ( !( p->flags & _BDF_GLYPHS ) )
1470 {
1471 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1472 {
1473 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1474 error = BDF_Err_Missing_Chars_Field;
1475 goto Exit;
1476 }
1477
David Turner68df4f72005-03-15 18:18:57 +00001478 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001479 if ( error )
1480 goto Exit;
1481 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1482
1483 /* Make sure the number of glyphs is non-zero. */
1484 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001485 font->glyphs_size = 64;
1486
Werner Lemberga08b2172007-03-28 07:17:17 +00001487 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1488 /* number of code points available in Unicode). */
1489 if ( p->cnt >= 1114112UL )
1490 {
1491 error = BDF_Err_Invalid_Argument;
1492 goto Exit;
1493 }
1494
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001495 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1496 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001497
David Turner993a8d02002-05-18 12:03:43 +00001498 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001499
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001500 goto Exit;
1501 }
1502
1503 /* Check for the ENDFONT field. */
1504 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1505 {
1506 /* Sort the glyphs by encoding. */
1507 ft_qsort( (char *)font->glyphs,
1508 font->glyphs_used,
1509 sizeof ( bdf_glyph_t ),
1510 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001511
1512 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001513
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001514 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001515 }
1516
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001517 /* Check for the ENDCHAR field. */
1518 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1519 {
1520 p->glyph_enc = 0;
1521 p->flags &= ~_BDF_GLYPH_BITS;
1522
1523 goto Exit;
1524 }
1525
1526 /* Check to see whether a glyph is being scanned but should be */
1527 /* ignored because it is an unencoded glyph. */
1528 if ( ( p->flags & _BDF_GLYPH ) &&
1529 p->glyph_enc == -1 &&
1530 p->opts->keep_unencoded == 0 )
1531 goto Exit;
1532
1533 /* Check for the STARTCHAR field. */
1534 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1535 {
1536 /* Set the character name in the parse info first until the */
1537 /* encoding can be checked for an unencoded character. */
1538 FT_FREE( p->glyph_name );
1539
David Turner68df4f72005-03-15 18:18:57 +00001540 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001541 if ( error )
1542 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001543
David Turner68df4f72005-03-15 18:18:57 +00001544 _bdf_list_shift( &p->list, 1 );
1545
1546 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001547
Werner Lembergba03af62007-05-30 13:57:02 +00001548 if ( !s )
1549 {
1550 error = BDF_Err_Invalid_File_Format;
1551 goto Exit;
1552 }
1553
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001554 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1555 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001556
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001557 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1558
1559 p->flags |= _BDF_GLYPH;
1560
1561 goto Exit;
1562 }
1563
1564 /* Check for the ENCODING field. */
1565 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1566 {
1567 if ( !( p->flags & _BDF_GLYPH ) )
1568 {
1569 /* Missing STARTCHAR field. */
1570 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1571 error = BDF_Err_Missing_Startchar_Field;
1572 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001573 }
1574
David Turner68df4f72005-03-15 18:18:57 +00001575 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001576 if ( error )
1577 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001578
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001579 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001580
David Turner481838e2006-02-23 12:40:14 +00001581 /* Check that the encoding is in the range [0,65536] because */
1582 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001583 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001584 {
1585 error = BDF_Err_Invalid_File_Format;
1586 goto Exit;
1587 }
1588
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001589 /* Check to see whether this encoding has already been encountered. */
1590 /* If it has then change it to unencoded so it gets added if */
1591 /* indicated. */
1592 if ( p->glyph_enc >= 0 )
1593 {
1594 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1595 {
1596 /* Emit a message saying a glyph has been moved to the */
1597 /* unencoded area. */
1598 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1599 p->glyph_enc, p->glyph_name ));
1600 p->glyph_enc = -1;
1601 font->modified = 1;
1602 }
1603 else
1604 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1605 }
1606
1607 if ( p->glyph_enc >= 0 )
1608 {
1609 /* Make sure there are enough glyphs allocated in case the */
1610 /* number of characters happen to be wrong. */
1611 if ( font->glyphs_used == font->glyphs_size )
1612 {
1613 if ( FT_RENEW_ARRAY( font->glyphs,
1614 font->glyphs_size,
1615 font->glyphs_size + 64 ) )
1616 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001617
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001618 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001619 }
1620
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001621 glyph = font->glyphs + font->glyphs_used++;
1622 glyph->name = p->glyph_name;
1623 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001624
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001625 /* Reset the initial glyph info. */
1626 p->glyph_name = 0;
1627 }
1628 else
1629 {
1630 /* Unencoded glyph. Check to see whether it should */
1631 /* be added or not. */
1632 if ( p->opts->keep_unencoded != 0 )
1633 {
1634 /* Allocate the next unencoded glyph. */
1635 if ( font->unencoded_used == font->unencoded_size )
1636 {
David Turner68df4f72005-03-15 18:18:57 +00001637 if ( FT_RENEW_ARRAY( font->unencoded ,
1638 font->unencoded_size,
1639 font->unencoded_size + 4 ) )
1640 goto Exit;
1641
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001642 font->unencoded_size += 4;
1643 }
1644
1645 glyph = font->unencoded + font->unencoded_used;
1646 glyph->name = p->glyph_name;
1647 glyph->encoding = font->unencoded_used++;
1648 }
1649 else
1650 /* Free up the glyph name if the unencoded shouldn't be */
1651 /* kept. */
1652 FT_FREE( p->glyph_name );
1653
1654 p->glyph_name = 0;
1655 }
1656
1657 /* Clear the flags that might be added when width and height are */
1658 /* checked for consistency. */
1659 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1660
1661 p->flags |= _BDF_ENCODING;
1662
1663 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001664 }
1665
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001666 /* Point at the glyph being constructed. */
1667 if ( p->glyph_enc == -1 )
1668 glyph = font->unencoded + ( font->unencoded_used - 1 );
1669 else
1670 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001671
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001672 /* Check to see whether a bitmap is being constructed. */
1673 if ( p->flags & _BDF_BITMAP )
1674 {
1675 /* If there are more rows than are specified in the glyph metrics, */
1676 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001677 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001678 {
1679 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1680 {
1681 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1682 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001683 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001684 }
1685
1686 goto Exit;
1687 }
1688
1689 /* Only collect the number of nibbles indicated by the glyph */
1690 /* metrics. If there are more columns, they are simply ignored. */
1691 nibbles = glyph->bpr << 1;
1692 bp = glyph->bitmap + p->row * glyph->bpr;
1693
David Turnerb698eed2006-02-23 14:50:13 +00001694 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001695 {
1696 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001697 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001698 if ( i + 1 < nibbles && ( i & 1 ) )
1699 *++bp = 0;
1700 }
1701
1702 /* Remove possible garbage at the right. */
1703 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001704 if ( glyph->bbx.width )
1705 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001706
1707 /* If any line has extra columns, indicate they have been removed. */
1708 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1709 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1710 {
1711 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1712 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1713 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001714 }
1715
1716 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001717 goto Exit;
1718 }
David Turner993a8d02002-05-18 12:03:43 +00001719
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001720 /* Expect the SWIDTH (scalable width) field next. */
1721 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1722 {
1723 if ( !( p->flags & _BDF_ENCODING ) )
1724 {
1725 /* Missing ENCODING field. */
1726 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1727 error = BDF_Err_Missing_Encoding_Field;
1728 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001729 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001730
David Turner68df4f72005-03-15 18:18:57 +00001731 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732 if ( error )
1733 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001734
David Turnerb1b47622002-05-21 21:17:43 +00001735 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001736 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001737
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001738 goto Exit;
1739 }
David Turner993a8d02002-05-18 12:03:43 +00001740
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001741 /* Expect the DWIDTH (scalable width) field next. */
1742 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1743 {
David Turner68df4f72005-03-15 18:18:57 +00001744 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001745 if ( error )
1746 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001747
David Turnerb1b47622002-05-21 21:17:43 +00001748 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001749
1750 if ( !( p->flags & _BDF_SWIDTH ) )
1751 {
1752 /* Missing SWIDTH field. Emit an auto correction message and set */
1753 /* the scalable width from the device width. */
1754 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1755
Werner Lemberg02d4d592002-05-28 22:38:05 +00001756 glyph->swidth = (unsigned short)FT_MulDiv(
1757 glyph->dwidth, 72000L,
1758 (FT_Long)( font->point_size *
1759 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001760 }
1761
1762 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001763 goto Exit;
1764 }
David Turner993a8d02002-05-18 12:03:43 +00001765
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001766 /* Expect the BBX field next. */
1767 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1768 {
David Turner68df4f72005-03-15 18:18:57 +00001769 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 if ( error )
1771 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001772
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001773 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1774 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1775 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1776 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1777
1778 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001779 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1780 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001781
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001782 /* Determine the overall font bounding box as the characters are */
1783 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001784 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1785 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001786
David Turnerb1b47622002-05-21 21:17:43 +00001787 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001788
Werner Lembergdfa46192004-03-05 09:26:24 +00001789 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1790 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1791 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001792
1793 if ( !( p->flags & _BDF_DWIDTH ) )
1794 {
1795 /* Missing DWIDTH field. Emit an auto correction message and set */
1796 /* the device width to the glyph width. */
1797 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1798 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001799 }
1800
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001801 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1802 /* value if necessary. */
1803 if ( p->opts->correct_metrics != 0 )
1804 {
1805 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001806 unsigned short sw = (unsigned short)FT_MulDiv(
1807 glyph->dwidth, 72000L,
1808 (FT_Long)( font->point_size *
1809 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001810
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001811
1812 if ( sw != glyph->swidth )
1813 {
1814 glyph->swidth = sw;
1815
1816 if ( p->glyph_enc == -1 )
1817 _bdf_set_glyph_modified( font->umod,
1818 font->unencoded_used - 1 );
1819 else
1820 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1821
1822 p->flags |= _BDF_SWIDTH_ADJ;
1823 font->modified = 1;
1824 }
David Turner993a8d02002-05-18 12:03:43 +00001825 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001826
David Turner993a8d02002-05-18 12:03:43 +00001827 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828 goto Exit;
1829 }
David Turner993a8d02002-05-18 12:03:43 +00001830
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001831 /* And finally, gather up the bitmap. */
1832 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1833 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001834 unsigned long bitmap_size;
1835
1836
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001837 if ( !( p->flags & _BDF_BBX ) )
1838 {
1839 /* Missing BBX field. */
1840 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1841 error = BDF_Err_Missing_Bbx_Field;
1842 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001843 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001844
1845 /* Allocate enough space for the bitmap. */
1846 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001847
1848 bitmap_size = glyph->bpr * glyph->bbx.height;
1849 if ( bitmap_size > 0xFFFFU )
1850 {
1851 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1852 error = BDF_Err_Bbx_Too_Big;
1853 goto Exit;
1854 }
1855 else
1856 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001857
1858 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1859 goto Exit;
1860
1861 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001862 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001863
1864 goto Exit;
1865 }
1866
1867 error = BDF_Err_Invalid_File_Format;
1868
1869 Exit:
1870 return error;
David Turner993a8d02002-05-18 12:03:43 +00001871 }
1872
David Turner993a8d02002-05-18 12:03:43 +00001873
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001874 /* Load the font properties. */
1875 static FT_Error
1876 _bdf_parse_properties( char* line,
1877 unsigned long linelen,
1878 unsigned long lineno,
1879 void* call_data,
1880 void* client_data )
1881 {
1882 unsigned long vlen;
1883 _bdf_line_func_t* next;
1884 _bdf_parse_t* p;
1885 char* name;
1886 char* value;
1887 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001888 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001889
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001890 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001891
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001892
1893 next = (_bdf_line_func_t *)call_data;
1894 p = (_bdf_parse_t *) client_data;
1895
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001896 /* Check for the end of the properties. */
1897 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1898 {
1899 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1900 /* encountered yet, then make sure they are added as properties and */
1901 /* make sure they are set from the font bounding box info. */
1902 /* */
1903 /* This is *always* done regardless of the options, because X11 */
1904 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001905 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001906 {
1907 p->font->font_ascent = p->font->bbx.ascent;
1908 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1909 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1910 if ( error )
1911 goto Exit;
1912
1913 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1914 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001915 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916
Werner Lemberg428c2e42003-04-25 05:35:04 +00001917 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001918 {
1919 p->font->font_descent = p->font->bbx.descent;
1920 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1921 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1922 if ( error )
1923 goto Exit;
1924
1925 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1926 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001927 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928
David Turner993a8d02002-05-18 12:03:43 +00001929 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001930 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001931
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001932 goto Exit;
1933 }
David Turner993a8d02002-05-18 12:03:43 +00001934
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001935 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1936 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1937 goto Exit;
1938
1939 /* Handle COMMENT fields and properties in a special way to preserve */
1940 /* the spacing. */
1941 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1942 {
David Turner993a8d02002-05-18 12:03:43 +00001943 name = value = line;
1944 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001946 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001947 error = _bdf_add_property( p->font, name, value );
1948 if ( error )
1949 goto Exit;
1950 }
1951 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1952 {
1953 error = _bdf_add_property( p->font, name, value );
1954 if ( error )
1955 goto Exit;
1956 }
1957 else
1958 {
David Turner68df4f72005-03-15 18:18:57 +00001959 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001960 if ( error )
1961 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001962 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001963
David Turner68df4f72005-03-15 18:18:57 +00001964 _bdf_list_shift( &p->list, 1 );
1965 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001966
1967 error = _bdf_add_property( p->font, name, value );
1968 if ( error )
1969 goto Exit;
1970 }
1971
1972 Exit:
1973 return error;
David Turner993a8d02002-05-18 12:03:43 +00001974 }
1975
David Turner993a8d02002-05-18 12:03:43 +00001976
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001977 /* Load the font header. */
1978 static FT_Error
1979 _bdf_parse_start( char* line,
1980 unsigned long linelen,
1981 unsigned long lineno,
1982 void* call_data,
1983 void* client_data )
1984 {
1985 unsigned long slen;
1986 _bdf_line_func_t* next;
1987 _bdf_parse_t* p;
1988 bdf_font_t* font;
1989 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001990
David Turnerd490e372002-05-28 23:40:37 +00001991 FT_Memory memory = NULL;
1992 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001993
1994 FT_UNUSED( lineno ); /* only used in debug mode */
1995
1996
1997 next = (_bdf_line_func_t *)call_data;
1998 p = (_bdf_parse_t *) client_data;
1999
2000 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002001 memory = p->font->memory;
2002
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003 /* Check for a comment. This is done to handle those fonts that have */
2004 /* comments before the STARTFONT line for some reason. */
2005 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2006 {
2007 if ( p->opts->keep_comments != 0 && p->font != 0 )
2008 {
2009 linelen -= 7;
2010
2011 s = line + 7;
2012 if ( *s != 0 )
2013 {
2014 s++;
2015 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002016 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002017
2018 error = _bdf_add_comment( p->font, s, linelen );
2019 if ( error )
2020 goto Exit;
2021 /* here font is not defined! */
2022 }
2023
2024 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002025 }
2026
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027 if ( !( p->flags & _BDF_START ) )
2028 {
2029 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002030
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002031 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2032 {
2033 /* No STARTFONT field is a good indication of a problem. */
2034 error = BDF_Err_Missing_Startfont_Field;
2035 goto Exit;
2036 }
David Turner993a8d02002-05-18 12:03:43 +00002037
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002038 p->flags = _BDF_START;
2039 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002040
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 if ( FT_NEW( font ) )
2042 goto Exit;
2043 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002044
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002045 font->memory = p->memory;
2046 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002047
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002049 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002050 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002051
David Turner993a8d02002-05-18 12:03:43 +00002052
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002053 error = hash_init( &(font->proptbl), memory );
2054 if ( error )
2055 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002056 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002057 i < _num_bdf_properties; i++, prop++ )
2058 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002059 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002060 &(font->proptbl), memory );
2061 if ( error )
2062 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002063 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002064 }
2065
2066 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2067 goto Exit;
2068 error = hash_init( (hashtable *)p->font->internal,memory );
2069 if ( error )
2070 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002071 p->font->spacing = p->opts->font_spacing;
2072 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002073
2074 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002075 }
2076
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002077 /* Check for the start of the properties. */
2078 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2079 {
David Turner68df4f72005-03-15 18:18:57 +00002080 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002081 if ( error )
2082 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002083 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002084 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2085
2086 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2087 goto Exit;
2088
2089 p->flags |= _BDF_PROPS;
2090 *next = _bdf_parse_properties;
2091
2092 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002093 }
2094
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002095 /* Check for the FONTBOUNDINGBOX field. */
2096 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2097 {
2098 if ( !(p->flags & _BDF_SIZE ) )
2099 {
2100 /* Missing the SIZE field. */
2101 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2102 error = BDF_Err_Missing_Size_Field;
2103 goto Exit;
2104 }
2105
David Turner68df4f72005-03-15 18:18:57 +00002106 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002107 if ( error )
2108 goto Exit;
2109
2110 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2111 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2112
2113 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2114 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2115
David Turnerd490e372002-05-28 23:40:37 +00002116 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002117 p->font->bbx.y_offset );
2118
2119 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002120
2121 p->flags |= _BDF_FONT_BBX;
2122
2123 goto Exit;
2124 }
2125
2126 /* The next thing to check for is the FONT field. */
2127 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2128 {
David Turner68df4f72005-03-15 18:18:57 +00002129 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002130 if ( error )
2131 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002132 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002133
David Turner68df4f72005-03-15 18:18:57 +00002134 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002135
2136 if ( !s )
2137 {
2138 error = BDF_Err_Invalid_File_Format;
2139 goto Exit;
2140 }
2141
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002142 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2143 goto Exit;
2144 FT_MEM_COPY( p->font->name, s, slen + 1 );
2145
2146 /* If the font name is an XLFD name, set the spacing to the one in */
2147 /* the font name. If there is no spacing fall back on the default. */
2148 error = _bdf_set_default_spacing( p->font, p->opts );
2149 if ( error )
2150 goto Exit;
2151
2152 p->flags |= _BDF_FONT_NAME;
2153
2154 goto Exit;
2155 }
2156
2157 /* Check for the SIZE field. */
2158 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2159 {
2160 if ( !( p->flags & _BDF_FONT_NAME ) )
2161 {
2162 /* Missing the FONT field. */
2163 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2164 error = BDF_Err_Missing_Font_Field;
2165 goto Exit;
2166 }
2167
David Turner68df4f72005-03-15 18:18:57 +00002168 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002169 if ( error )
2170 goto Exit;
2171
2172 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2173 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2174 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2175
2176 /* Check for the bits per pixel field. */
2177 if ( p->list.used == 5 )
2178 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002179 unsigned short bitcount, i, shift;
2180
2181
2182 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2183
2184 /* Only values 1, 2, 4, 8 are allowed. */
2185 shift = p->font->bpp;
2186 bitcount = 0;
2187 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002188 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002189 if ( shift & 1 )
2190 bitcount = i;
2191 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002192 }
David Turner993a8d02002-05-18 12:03:43 +00002193
Werner Lembergbd8e3242002-06-12 08:43:58 +00002194 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002195
2196 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002197 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002198 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002199 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002200 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002201 }
2202 }
2203 else
2204 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002205
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002206 p->flags |= _BDF_SIZE;
2207
2208 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002209 }
2210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002212
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002213 Exit:
2214 return error;
2215 }
David Turner993a8d02002-05-18 12:03:43 +00002216
2217
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 /*************************************************************************/
2219 /* */
2220 /* API. */
2221 /* */
2222 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002223
David Turner993a8d02002-05-18 12:03:43 +00002224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002225 FT_LOCAL_DEF( FT_Error )
2226 bdf_load_font( FT_Stream stream,
2227 FT_Memory extmemory,
2228 bdf_options_t* opts,
2229 bdf_font_t* *font )
2230 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002231 unsigned long lineno = 0; /* make compiler happy */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002232 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002233
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002234 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002235 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002236
2237
David Turner68df4f72005-03-15 18:18:57 +00002238 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002239 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002240
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002241 memory = NULL;
2242 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2243 p->minlb = 32767;
2244 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002245
David Turner68df4f72005-03-15 18:18:57 +00002246 _bdf_list_init( &p->list, extmemory );
2247
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002248 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002249 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002250 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002251 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002252
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002253 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002254 {
2255 /* If the font is not proportional, set the font's monowidth */
2256 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002257 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002258
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002259 if ( p->font->spacing != BDF_PROPORTIONAL )
2260 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002261
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002262 /* If the number of glyphs loaded is not that of the original count, */
2263 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002264 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002265 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002266 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2267 p->font->glyphs_used + p->font->unencoded_used ));
2268 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002269 }
2270
2271 /* Once the font has been loaded, adjust the overall font metrics if */
2272 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002273 if ( p->opts->correct_metrics != 0 &&
2274 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002275 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002276 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002277 {
2278 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002279 p->font->bbx.width, p->maxrb - p->minlb ));
2280 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2281 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002282 }
2283
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002284 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002285 {
2286 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002287 p->font->bbx.x_offset, p->minlb ));
2288 p->font->bbx.x_offset = p->minlb;
2289 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002290 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002291
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002292 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002293 {
2294 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002295 p->font->bbx.ascent, p->maxas ));
2296 p->font->bbx.ascent = p->maxas;
2297 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 }
2299
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002300 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002301 {
2302 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002303 p->font->bbx.descent, p->maxds ));
2304 p->font->bbx.descent = p->maxds;
2305 p->font->bbx.y_offset = (short)( -p->maxds );
2306 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002307 }
2308
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002309 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002310 {
2311 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002312 p->font->bbx.height, p->maxas + p->maxds ));
2313 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002314 }
2315
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002316 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002317 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2318 }
David Turner993a8d02002-05-18 12:03:43 +00002319 }
2320
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002321 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 {
2323 {
2324 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002325 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg5b591e42007-06-01 22:16:43 +00002326 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002327 /* Error happened while parsing header. */
2328 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002329 error = BDF_Err_Corrupted_Font_Header;
2330 goto Exit;
2331 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002332 else
Werner Lemberg5b591e42007-06-01 22:16:43 +00002333 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002334 /* Error happened when parsing glyphs. */
2335 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002336 error = BDF_Err_Corrupted_Font_Glyphs;
2337 goto Exit;
2338 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002339 }
David Turner993a8d02002-05-18 12:03:43 +00002340 }
2341
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002342 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002343 {
2344 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002345 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002346
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002347 if ( p->font->comments_len > 0 ) {
2348 if ( FT_RENEW_ARRAY( p->font->comments,
2349 p->font->comments_len,
2350 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002351 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002352
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002353 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002354 }
David Turner993a8d02002-05-18 12:03:43 +00002355 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002356 else if ( error == BDF_Err_Ok )
2357 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002358
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002359 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002360
2361 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002362 if ( p )
2363 {
David Turner68df4f72005-03-15 18:18:57 +00002364 _bdf_list_done( &p->list );
2365
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002366 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002367
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002368 FT_FREE( p );
2369 }
2370
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002371 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002372
2373 Fail:
2374 bdf_free_font( p->font );
2375
2376 memory = extmemory;
2377
2378 FT_FREE( p->font );
2379
2380 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002381 }
David Turner993a8d02002-05-18 12:03:43 +00002382
2383
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002384 FT_LOCAL_DEF( void )
2385 bdf_free_font( bdf_font_t* font )
2386 {
2387 bdf_property_t* prop;
2388 unsigned long i;
2389 bdf_glyph_t* glyphs;
2390 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002391
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392
2393 if ( font == 0 )
2394 return;
David Turner993a8d02002-05-18 12:03:43 +00002395
2396 memory = font->memory;
2397
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002398 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002399
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002400 /* Free up the internal hash table of property names. */
2401 if ( font->internal )
2402 {
2403 hash_free( (hashtable *)font->internal, memory );
2404 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002405 }
2406
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002407 /* Free up the comment info. */
2408 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002409
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002410 /* Free up the properties. */
2411 for ( i = 0; i < font->props_size; i++ )
2412 {
2413 if ( font->props[i].format == BDF_ATOM )
2414 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002415 }
2416
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002417 FT_FREE( font->props );
2418
2419 /* Free up the character info. */
2420 for ( i = 0, glyphs = font->glyphs;
2421 i < font->glyphs_used; i++, glyphs++ )
2422 {
2423 FT_FREE( glyphs->name );
2424 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002425 }
2426
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002427 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2428 i++, glyphs++ )
2429 {
2430 FT_FREE( glyphs->name );
2431 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002432 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002433
2434 FT_FREE( font->glyphs );
2435 FT_FREE( font->unencoded );
2436
2437 /* Free up the overflow storage if it was used. */
2438 for ( i = 0, glyphs = font->overflow.glyphs;
2439 i < font->overflow.glyphs_used; i++, glyphs++ )
2440 {
2441 FT_FREE( glyphs->name );
2442 FT_FREE( glyphs->bitmap );
2443 }
2444
2445 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002446
2447 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002448 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002449
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002450 /* Free up the user defined properties. */
2451 for (prop = font->user_props, i = 0;
2452 i < font->nuser_props; i++, prop++ )
2453 {
2454 FT_FREE( prop->name );
2455 if ( prop->format == BDF_ATOM )
2456 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002457 }
David Turner993a8d02002-05-18 12:03:43 +00002458
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002459 FT_FREE( font->user_props );
2460
2461 /* FREE( font ); */ /* XXX Fixme */
2462 }
David Turner993a8d02002-05-18 12:03:43 +00002463
2464
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002465 FT_LOCAL_DEF( bdf_property_t * )
2466 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002467 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002468 {
2469 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002470
David Turner993a8d02002-05-18 12:03:43 +00002471
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002472 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002473 return 0;
2474
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002475 hn = hash_lookup( name, (hashtable *)font->internal );
2476
suzuki toshiya704f4d72009-09-13 00:50:14 +09002477 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002478 }
2479
2480
2481/* END */