blob: 21b8d9d40e1638d4876d3cf7c6b1ddf16a8796c5 [file] [log] [blame]
David Turner993a8d02002-05-18 12:03:43 +00001/*
2 * Copyright 2000 Computing Research Labs, New Mexico State University
Werner Lembergf4c94d42010-06-19 16:08:31 +02003 * Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010
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
Werner Lembergf4c94d42010-06-19 16:08:31 +0200473 /* An empty string for empty fields. */
474
475 static const char empty[1] = { 0 }; /* XXX eliminate this */
476
477
David Turner68df4f72005-03-15 18:18:57 +0000478 static char *
479 _bdf_list_join( _bdf_list_t* list,
480 int c,
481 unsigned long *alen )
482 {
483 unsigned long i, j;
484 char *fp, *dp;
485
486
487 *alen = 0;
488
489 if ( list == 0 || list->used == 0 )
490 return 0;
491
492 dp = list->field[0];
493 for ( i = j = 0; i < list->used; i++ )
494 {
495 fp = list->field[i];
496 while ( *fp )
497 dp[j++] = *fp++;
498
499 if ( i + 1 < list->used )
500 dp[j++] = (char)c;
501 }
Werner Lembergf4c94d42010-06-19 16:08:31 +0200502 if ( dp != empty )
503 dp[j] = 0;
David Turner68df4f72005-03-15 18:18:57 +0000504
505 *alen = j;
506 return dp;
507 }
508
509
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000510 static FT_Error
David Turner68df4f72005-03-15 18:18:57 +0000511 _bdf_list_split( _bdf_list_t* list,
512 char* separators,
513 char* line,
514 unsigned long linelen )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000515 {
516 int mult, final_empty;
517 char *sp, *ep, *end;
518 char seps[32];
519 FT_Error error = BDF_Err_Ok;
520
521
522 /* Initialize the list. */
523 list->used = 0;
524
525 /* If the line is empty, then simply return. */
526 if ( linelen == 0 || line[0] == 0 )
527 goto Exit;
528
529 /* In the original code, if the `separators' parameter is NULL or */
530 /* empty, the list is split into individual bytes. We don't need */
531 /* this, so an error is signaled. */
532 if ( separators == 0 || *separators == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000533 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000534 error = BDF_Err_Invalid_Argument;
535 goto Exit;
536 }
537
538 /* Prepare the separator bitmap. */
Werner Lembergb3d5e9c2002-07-28 05:05:24 +0000539 FT_MEM_ZERO( seps, 32 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000540
541 /* If the very last character of the separator string is a plus, then */
542 /* set the `mult' flag to indicate that multiple separators should be */
543 /* collapsed into one. */
544 for ( mult = 0, sp = separators; sp && *sp; sp++ )
545 {
546 if ( *sp == '+' && *( sp + 1 ) == 0 )
547 mult = 1;
David Turner993a8d02002-05-18 12:03:43 +0000548 else
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000549 setsbit( seps, *sp );
550 }
551
552 /* Break the line up into fields. */
553 for ( final_empty = 0, sp = ep = line, end = sp + linelen;
554 sp < end && *sp; )
555 {
556 /* Collect everything that is not a separator. */
557 for ( ; *ep && !sbitset( seps, *ep ); ep++ )
558 ;
559
560 /* Resize the list if necessary. */
561 if ( list->used == list->size )
David Turner993a8d02002-05-18 12:03:43 +0000562 {
Werner Lembergebf55852005-03-16 01:49:54 +0000563 error = _bdf_list_ensure( list, list->used + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000564 if ( error )
565 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000566 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000567
568 /* Assign the field appropriately. */
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000569 list->field[list->used++] = ( ep > sp ) ? sp : (char*)empty;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000570
571 sp = ep;
572
573 if ( mult )
574 {
575 /* If multiple separators should be collapsed, do it now by */
576 /* setting all the separator characters to 0. */
577 for ( ; *ep && sbitset( seps, *ep ); ep++ )
578 *ep = 0;
579 }
580 else if ( *ep != 0 )
581 /* Don't collapse multiple separators by making them 0, so just */
582 /* make the one encountered 0. */
583 *ep++ = 0;
584
585 final_empty = ( ep > sp && *ep == 0 );
586 sp = ep;
David Turner993a8d02002-05-18 12:03:43 +0000587 }
588
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000589 /* Finally, NULL-terminate the list. */
David Turner68df4f72005-03-15 18:18:57 +0000590 if ( list->used + final_empty >= list->size )
David Turner993a8d02002-05-18 12:03:43 +0000591 {
Werner Lembergebf55852005-03-16 01:49:54 +0000592 error = _bdf_list_ensure( list, list->used + final_empty + 1 );
David Turner68df4f72005-03-15 18:18:57 +0000593 if ( error )
594 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +0000595 }
596
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000597 if ( final_empty )
Werner Lemberg15ee9b52003-10-15 22:20:56 +0000598 list->field[list->used++] = (char*)empty;
David Turner993a8d02002-05-18 12:03:43 +0000599
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000600 list->field[list->used] = 0;
601
602 Exit:
603 return error;
David Turner993a8d02002-05-18 12:03:43 +0000604 }
605
David Turner993a8d02002-05-18 12:03:43 +0000606
David Turner68df4f72005-03-15 18:18:57 +0000607#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000608
Werner Lembergebf55852005-03-16 01:49:54 +0000609
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000610 static FT_Error
611 _bdf_readstream( FT_Stream stream,
612 _bdf_line_func_t callback,
613 void* client_data,
614 unsigned long *lno )
David Turner993a8d02002-05-18 12:03:43 +0000615 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000616 _bdf_line_func_t cb;
David Turner68df4f72005-03-15 18:18:57 +0000617 unsigned long lineno, buf_size;
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900618 int refill, hold, to_skip;
619 ptrdiff_t bytes, start, end, cursor, avail;
David Turner68df4f72005-03-15 18:18:57 +0000620 char* buf = 0;
Werner Lemberg7925edc2002-05-30 19:29:41 +0000621 FT_Memory memory = stream->memory;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000622 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +0000623
David Turner993a8d02002-05-18 12:03:43 +0000624
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000625 if ( callback == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000626 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000627 error = BDF_Err_Invalid_Argument;
628 goto Exit;
629 }
David Turner993a8d02002-05-18 12:03:43 +0000630
Werner Lembergebf55852005-03-16 01:49:54 +0000631 /* initial size and allocation of the input buffer */
David Turner68df4f72005-03-15 18:18:57 +0000632 buf_size = 1024;
633
634 if ( FT_NEW_ARRAY( buf, buf_size ) )
Werner Lemberg7925edc2002-05-30 19:29:41 +0000635 goto Exit;
636
Werner Lembergebf55852005-03-16 01:49:54 +0000637 cb = callback;
638 lineno = 1;
639 buf[0] = 0;
640 start = 0;
641 end = 0;
642 avail = 0;
643 cursor = 0;
644 refill = 1;
645 to_skip = NO_SKIP;
646 bytes = 0; /* make compiler happy */
David Turner993a8d02002-05-18 12:03:43 +0000647
David Turner68df4f72005-03-15 18:18:57 +0000648 for (;;)
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000649 {
David Turner68df4f72005-03-15 18:18:57 +0000650 if ( refill )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000651 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +0200652 bytes = (ptrdiff_t)FT_Stream_TryRead(
653 stream, (FT_Byte*)buf + cursor,
654 (FT_ULong)( buf_size - cursor ) );
David Turner68df4f72005-03-15 18:18:57 +0000655 avail = cursor + bytes;
656 cursor = 0;
657 refill = 0;
658 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000659
David Turner68df4f72005-03-15 18:18:57 +0000660 end = start;
661
Werner Lembergebf55852005-03-16 01:49:54 +0000662 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000663 if ( start < avail && buf[start] == to_skip )
664 {
665 start += 1;
666 to_skip = NO_SKIP;
667 continue;
668 }
669
670 /* try to find the end of the line */
671 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
672 end++;
673
Werner Lembergebf55852005-03-16 01:49:54 +0000674 /* if we hit the end of the buffer, try shifting its content */
675 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000676 if ( end >= avail )
677 {
678 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
679 break; /* ignore it then exit */
680
681 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000682 {
Werner Lembergebf55852005-03-16 01:49:54 +0000683 /* this line is definitely too long; try resizing the input */
684 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000685 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000686
Werner Lembergebf55852005-03-16 01:49:54 +0000687
688 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000689 {
690 error = BDF_Err_Invalid_Argument;
691 goto Exit;
692 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000693
Werner Lembergebf55852005-03-16 01:49:54 +0000694 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000695 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
696 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000697
David Turner68df4f72005-03-15 18:18:57 +0000698 cursor = buf_size;
699 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000700 }
701 else
702 {
David Turner68df4f72005-03-15 18:18:57 +0000703 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000704
Werner Lembergebf55852005-03-16 01:49:54 +0000705 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000706
David Turner68df4f72005-03-15 18:18:57 +0000707 cursor = bytes;
708 avail -= bytes;
709 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000710 }
David Turner68df4f72005-03-15 18:18:57 +0000711 refill = 1;
712 continue;
David Turner993a8d02002-05-18 12:03:43 +0000713 }
David Turner68df4f72005-03-15 18:18:57 +0000714
715 /* Temporarily NUL-terminate the line. */
716 hold = buf[end];
717 buf[end] = 0;
718
719 /* XXX: Use encoding independent value for 0x1a */
720 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
721 {
Werner Lembergebf55852005-03-16 01:49:54 +0000722 error = (*cb)( buf + start, end - start, lineno,
723 (void*)&cb, client_data );
Werner Lembergb21d7bc2010-06-24 07:40:49 +0200724 /* Redo if we have encountered CHARS without properties. */
725 if ( error == -1 )
726 error = (*cb)( buf + start, end - start, lineno,
727 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000728 if ( error )
729 break;
730 }
731
732 lineno += 1;
733 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000734 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000735
736 if ( hold == '\n' )
737 to_skip = '\r';
738 else if ( hold == '\r' )
739 to_skip = '\n';
740 else
741 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000742 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743
David Turner68df4f72005-03-15 18:18:57 +0000744 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000745
746 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000747 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000748 return error;
David Turner993a8d02002-05-18 12:03:43 +0000749 }
David Turner993a8d02002-05-18 12:03:43 +0000750
751
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000752 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000753
David Turnerb1b47622002-05-21 21:17:43 +0000754 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000755 {
David Turner993a8d02002-05-18 12:03:43 +0000756 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
759 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
762 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
763 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
765 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000767 };
David Turner993a8d02002-05-18 12:03:43 +0000768
David Turnerb1b47622002-05-21 21:17:43 +0000769 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000770 {
David Turner993a8d02002-05-18 12:03:43 +0000771 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
772 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000775 };
David Turner993a8d02002-05-18 12:03:43 +0000776
David Turnerb1b47622002-05-21 21:17:43 +0000777 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000778 {
David Turner993a8d02002-05-18 12:03:43 +0000779 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000783 };
David Turner993a8d02002-05-18 12:03:43 +0000784
David Turnerb1b47622002-05-21 21:17:43 +0000785 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000786 {
David Turner993a8d02002-05-18 12:03:43 +0000787 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
788 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
789 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000791 };
David Turner993a8d02002-05-18 12:03:43 +0000792
David Turner993a8d02002-05-18 12:03:43 +0000793
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000794#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000795
David Turner993a8d02002-05-18 12:03:43 +0000796
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000797 /* Routine to convert an ASCII string into an unsigned long integer. */
798 static unsigned long
799 _bdf_atoul( char* s,
800 char** end,
801 int base )
David Turner993a8d02002-05-18 12:03:43 +0000802 {
David Turnerb1b47622002-05-21 21:17:43 +0000803 unsigned long v;
804 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000805
806
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000807 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000808 return 0;
809
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000810 /* Make sure the radix is something recognizable. Default to 10. */
811 switch ( base )
812 {
813 case 8:
814 dmap = odigits;
815 break;
816 case 16:
817 dmap = hdigits;
818 break;
819 default:
820 base = 10;
821 dmap = ddigits;
822 break;
David Turner993a8d02002-05-18 12:03:43 +0000823 }
824
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000825 /* Check for the special hex prefix. */
826 if ( *s == '0' &&
827 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
828 {
829 base = 16;
830 dmap = hdigits;
831 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000832 }
833
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000834 for ( v = 0; isdigok( dmap, *s ); s++ )
835 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000836
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000837 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000838 *end = s;
839
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000840 return v;
841 }
David Turner993a8d02002-05-18 12:03:43 +0000842
David Turner993a8d02002-05-18 12:03:43 +0000843
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000844 /* Routine to convert an ASCII string into an signed long integer. */
845 static long
846 _bdf_atol( char* s,
847 char** end,
848 int base )
849 {
David Turnerb1b47622002-05-21 21:17:43 +0000850 long v, neg;
851 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000852
853
854 if ( s == 0 || *s == 0 )
855 return 0;
856
857 /* Make sure the radix is something recognizable. Default to 10. */
858 switch ( base )
859 {
860 case 8:
861 dmap = odigits;
862 break;
863 case 16:
864 dmap = hdigits;
865 break;
866 default:
867 base = 10;
868 dmap = ddigits;
869 break;
870 }
871
872 /* Check for a minus sign. */
873 neg = 0;
874 if ( *s == '-' )
875 {
876 s++;
877 neg = 1;
878 }
879
880 /* Check for the special hex prefix. */
881 if ( *s == '0' &&
882 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
883 {
884 base = 16;
885 dmap = hdigits;
886 s += 2;
887 }
888
889 for ( v = 0; isdigok( dmap, *s ); s++ )
890 v = v * base + a2i[(int)*s];
891
892 if ( end != 0 )
893 *end = s;
894
895 return ( !neg ) ? v : -v;
896 }
897
898
899 /* Routine to convert an ASCII string into an signed short integer. */
900 static short
901 _bdf_atos( char* s,
902 char** end,
903 int base )
904 {
David Turnerb1b47622002-05-21 21:17:43 +0000905 short v, neg;
906 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000907
908
909 if ( s == 0 || *s == 0 )
910 return 0;
911
912 /* Make sure the radix is something recognizable. Default to 10. */
913 switch ( base )
914 {
915 case 8:
916 dmap = odigits;
917 break;
918 case 16:
919 dmap = hdigits;
920 break;
921 default:
922 base = 10;
923 dmap = ddigits;
924 break;
925 }
926
927 /* Check for a minus. */
928 neg = 0;
929 if ( *s == '-' )
930 {
931 s++;
932 neg = 1;
933 }
934
935 /* Check for the special hex prefix. */
936 if ( *s == '0' &&
937 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
938 {
939 base = 16;
940 dmap = hdigits;
941 s += 2;
942 }
943
944 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000945 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000946
947 if ( end != 0 )
948 *end = s;
949
Werner Lemberg233302a2002-05-22 05:41:06 +0000950 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000951 }
952
953
954 /* Routine to compare two glyphs by encoding so they can be sorted. */
955 static int
956 by_encoding( const void* a,
957 const void* b )
958 {
959 bdf_glyph_t *c1, *c2;
960
961
962 c1 = (bdf_glyph_t *)a;
963 c2 = (bdf_glyph_t *)b;
964
965 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000966 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000967
968 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000969 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000970
David Turner993a8d02002-05-18 12:03:43 +0000971 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000972 }
973
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000974
975 static FT_Error
976 bdf_create_property( char* name,
977 int format,
978 bdf_font_t* font )
979 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900980 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000981 bdf_property_t* p;
982 FT_Memory memory = font->memory;
983 FT_Error error = BDF_Err_Ok;
984
985
986 /* First check to see if the property has */
987 /* already been added or not. If it has, then */
988 /* simply ignore it. */
989 if ( hash_lookup( name, &(font->proptbl) ) )
990 goto Exit;
991
David Turner68df4f72005-03-15 18:18:57 +0000992 if ( FT_RENEW_ARRAY( font->user_props,
993 font->nuser_props,
994 font->nuser_props + 1 ) )
995 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000996
997 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000998 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000999
suzuki toshiya704f4d72009-09-13 00:50:14 +09001000 n = ft_strlen( name ) + 1;
1001 if ( n > FT_ULONG_MAX )
1002 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +00001003
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001004 if ( FT_NEW_ARRAY( p->name, n ) )
1005 goto Exit;
1006
1007 FT_MEM_COPY( (char *)p->name, name, n );
1008
1009 p->format = format;
1010 p->builtin = 0;
1011
1012 n = _num_bdf_properties + font->nuser_props;
1013
suzuki toshiya704f4d72009-09-13 00:50:14 +09001014 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001015 if ( error )
1016 goto Exit;
1017
1018 font->nuser_props++;
1019
1020 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001021 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001022 }
David Turner993a8d02002-05-18 12:03:43 +00001023
1024
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001025 FT_LOCAL_DEF( bdf_property_t * )
1026 bdf_get_property( char* name,
1027 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001028 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001029 hashnode hn;
1030 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001031
1032
1033 if ( name == 0 || *name == 0 )
1034 return 0;
1035
1036 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1037 return 0;
1038
suzuki toshiya704f4d72009-09-13 00:50:14 +09001039 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001040 if ( propid >= _num_bdf_properties )
1041 return font->user_props + ( propid - _num_bdf_properties );
1042
Werner Lemberg233302a2002-05-22 05:41:06 +00001043 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001044 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001045
1046
1047 /*************************************************************************/
1048 /* */
1049 /* BDF font file parsing flags and functions. */
1050 /* */
1051 /*************************************************************************/
1052
1053
1054 /* Parse flags. */
1055
1056#define _BDF_START 0x0001
1057#define _BDF_FONT_NAME 0x0002
1058#define _BDF_SIZE 0x0004
1059#define _BDF_FONT_BBX 0x0008
1060#define _BDF_PROPS 0x0010
1061#define _BDF_GLYPHS 0x0020
1062#define _BDF_GLYPH 0x0040
1063#define _BDF_ENCODING 0x0080
1064#define _BDF_SWIDTH 0x0100
1065#define _BDF_DWIDTH 0x0200
1066#define _BDF_BBX 0x0400
1067#define _BDF_BITMAP 0x0800
1068
1069#define _BDF_SWIDTH_ADJ 0x1000
1070
1071#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1072 _BDF_ENCODING | \
1073 _BDF_SWIDTH | \
1074 _BDF_DWIDTH | \
1075 _BDF_BBX | \
1076 _BDF_BITMAP )
1077
Werner Lembergf1c2b912006-01-13 14:53:28 +00001078#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1079#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001080
1081
1082 /* Auto correction messages. */
1083#define ACMSG1 "FONT_ASCENT property missing. " \
1084 "Added \"FONT_ASCENT %hd\".\n"
1085#define ACMSG2 "FONT_DESCENT property missing. " \
1086 "Added \"FONT_DESCENT %hd\".\n"
1087#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1088#define ACMSG4 "Font left bearing != actual left bearing. " \
1089 "Old: %hd New: %hd.\n"
1090#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1091#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1092#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1093#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1094#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1095#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1096#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1097#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1098#define ACMSG13 "Glyph %ld extra rows removed.\n"
1099#define ACMSG14 "Glyph %ld extra columns removed.\n"
1100#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1101
1102 /* Error messages. */
1103#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1104#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1105#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
Werner Lemberg26170df2006-03-26 07:19:07 +00001106#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001107
1108
1109 static FT_Error
1110 _bdf_add_comment( bdf_font_t* font,
1111 char* comment,
1112 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001113 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001114 char* cp;
1115 FT_Memory memory = font->memory;
1116 FT_Error error = BDF_Err_Ok;
1117
1118
David Turner68df4f72005-03-15 18:18:57 +00001119 if ( FT_RENEW_ARRAY( font->comments,
1120 font->comments_len,
1121 font->comments_len + len + 1 ) )
1122 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001123
1124 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001125
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001126 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001127 cp[len] = '\n';
1128
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001129 font->comments_len += len + 1;
1130
1131 Exit:
1132 return error;
David Turner993a8d02002-05-18 12:03:43 +00001133 }
1134
David Turner993a8d02002-05-18 12:03:43 +00001135
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001136 /* Set the spacing from the font name if it exists, or set it to the */
1137 /* default specified in the options. */
1138 static FT_Error
1139 _bdf_set_default_spacing( bdf_font_t* font,
1140 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001141 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001142 size_t len;
1143 char name[256];
1144 _bdf_list_t list;
1145 FT_Memory memory;
1146 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001147
David Turner993a8d02002-05-18 12:03:43 +00001148
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001149 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1150 {
1151 error = BDF_Err_Invalid_Argument;
1152 goto Exit;
1153 }
David Turner993a8d02002-05-18 12:03:43 +00001154
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001155 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001156
David Turner68df4f72005-03-15 18:18:57 +00001157 _bdf_list_init( &list, memory );
1158
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001159 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001160
suzuki toshiya704f4d72009-09-13 00:50:14 +09001161 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001162 /* Limit ourselves to 256 characters in the font name. */
1163 if ( len >= 256 )
1164 {
1165 error = BDF_Err_Invalid_Argument;
1166 goto Exit;
1167 }
1168
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001169 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001170
David Turner68df4f72005-03-15 18:18:57 +00001171 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001172 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001173 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001174
1175 if ( list.used == 15 )
1176 {
1177 switch ( list.field[11][0] )
1178 {
1179 case 'C':
1180 case 'c':
1181 font->spacing = BDF_CHARCELL;
1182 break;
1183 case 'M':
1184 case 'm':
1185 font->spacing = BDF_MONOWIDTH;
1186 break;
1187 case 'P':
1188 case 'p':
1189 font->spacing = BDF_PROPORTIONAL;
1190 break;
David Turner993a8d02002-05-18 12:03:43 +00001191 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001192 }
1193
David Turner68df4f72005-03-15 18:18:57 +00001194 Fail:
1195 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001196
1197 Exit:
1198 return error;
David Turner993a8d02002-05-18 12:03:43 +00001199 }
David Turner993a8d02002-05-18 12:03:43 +00001200
1201
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001202 /* Determine whether the property is an atom or not. If it is, then */
1203 /* clean it up so the double quotes are removed if they exist. */
1204 static int
1205 _bdf_is_atom( char* line,
1206 unsigned long linelen,
1207 char** name,
1208 char** value,
1209 bdf_font_t* font )
1210 {
1211 int hold;
1212 char *sp, *ep;
1213 bdf_property_t* p;
1214
David Turner993a8d02002-05-18 12:03:43 +00001215
1216 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001217
1218 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001219 ep++;
1220
1221 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001222 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001223 {
1224 hold = *ep;
1225 *ep = 0;
1226 }
1227
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001228 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001230 /* Restore the character that was saved before any return can happen. */
1231 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001232 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001233
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001234 /* If the property exists and is not an atom, just return here. */
1235 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001236 return 0;
1237
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001238 /* The property is an atom. Trim all leading and trailing whitespace */
1239 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001240 sp = ep;
1241 ep = line + linelen;
1242
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001243 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001244 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001245 while ( *sp &&
1246 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001247 sp++;
1248
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001249 /* Trim the leading double quote if it exists. */
1250 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001251 sp++;
1252 *value = sp;
1253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001254 /* Trim the trailing whitespace if it exists. */
1255 while ( ep > sp &&
1256 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001257 *--ep = 0;
1258
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 /* Trim the trailing double quote if it exists. */
1260 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001261 *--ep = 0;
1262
1263 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001264 }
David Turner993a8d02002-05-18 12:03:43 +00001265
1266
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001267 static FT_Error
1268 _bdf_add_property( bdf_font_t* font,
1269 char* name,
1270 char* value )
1271 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001272 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001273 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 bdf_property_t *prop, *fp;
1275 FT_Memory memory = font->memory;
1276 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001277
David Turner993a8d02002-05-18 12:03:43 +00001278
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001279 /* First, check to see if the property already exists in the font. */
1280 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001281 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001282 /* The property already exists in the font, so simply replace */
1283 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001284 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001285
David Turnerb1b47622002-05-21 21:17:43 +00001286 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001287 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 case BDF_ATOM:
1289 /* Delete the current atom if it exists. */
1290 FT_FREE( fp->value.atom );
1291
David Turnerc0f9c4a2007-02-12 14:55:03 +00001292 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001293 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001294 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001295 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001297 break;
1298
1299 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001300 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001301 break;
1302
1303 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001304 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001305 break;
David Turnerd490e372002-05-28 23:40:37 +00001306
David Turnerb1b47622002-05-21 21:17:43 +00001307 default:
1308 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001309 }
David Turnerd490e372002-05-28 23:40:37 +00001310
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001311 goto Exit;
1312 }
1313
1314 /* See whether this property type exists yet or not. */
1315 /* If not, create it. */
1316 hn = hash_lookup( name, &(font->proptbl) );
1317 if ( hn == 0 )
1318 {
1319 error = bdf_create_property( name, BDF_ATOM, font );
1320 if ( error )
1321 goto Exit;
1322 hn = hash_lookup( name, &(font->proptbl) );
1323 }
1324
1325 /* Allocate another property if this is overflow. */
1326 if ( font->props_used == font->props_size )
1327 {
1328 if ( font->props_size == 0 )
1329 {
1330 if ( FT_NEW_ARRAY( font->props, 1 ) )
1331 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001332 }
1333 else
1334 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001335 if ( FT_RENEW_ARRAY( font->props,
1336 font->props_size,
1337 font->props_size + 1 ) )
1338 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001339 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001340
David Turner993a8d02002-05-18 12:03:43 +00001341 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001342 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001343 font->props_size++;
1344 }
1345
suzuki toshiya704f4d72009-09-13 00:50:14 +09001346 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001347 if ( propid >= _num_bdf_properties )
1348 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001349 else
David Turnerb1b47622002-05-21 21:17:43 +00001350 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001351
1352 fp = font->props + font->props_used;
1353
1354 fp->name = prop->name;
1355 fp->format = prop->format;
1356 fp->builtin = prop->builtin;
1357
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001358 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001359 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001361 fp->value.atom = 0;
1362 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001363 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001364 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001365 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001366 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001367 break;
David Turner993a8d02002-05-18 12:03:43 +00001368
1369 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001370 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001371 break;
1372
1373 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001374 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001375 break;
David Turner993a8d02002-05-18 12:03:43 +00001376 }
1377
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001378 /* If the property happens to be a comment, then it doesn't need */
1379 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001380 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1381 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001382 /* Add the property to the font property table. */
1383 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001384 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001385 (hashtable *)font->internal,
1386 memory );
1387 if ( error )
1388 goto Exit;
1389 }
David Turner993a8d02002-05-18 12:03:43 +00001390
1391 font->props_used++;
1392
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001393 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1394 /* property needs to be located if it exists in the property list, the */
1395 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1396 /* present, and the SPACING property should override the default */
1397 /* spacing. */
1398 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001399 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001400 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001401 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001402 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001403 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001404 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001405 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001406 if ( !fp->value.atom )
1407 {
1408 error = BDF_Err_Invalid_File_Format;
1409 goto Exit;
1410 }
1411
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001412 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001413 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001414 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001415 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001416 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001417 font->spacing = BDF_CHARCELL;
1418 }
1419
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001420 Exit:
1421 return error;
David Turner993a8d02002-05-18 12:03:43 +00001422 }
1423
David Turner993a8d02002-05-18 12:03:43 +00001424
David Turnerb1b47622002-05-21 21:17:43 +00001425 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001426 {
1427 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1428 };
1429
1430
1431 /* Actually parse the glyph info and bitmaps. */
1432 static FT_Error
1433 _bdf_parse_glyphs( char* line,
1434 unsigned long linelen,
1435 unsigned long lineno,
1436 void* call_data,
1437 void* client_data )
1438 {
1439 int c, mask_index;
1440 char* s;
1441 unsigned char* bp;
1442 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001443
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001444 _bdf_parse_t* p;
1445 bdf_glyph_t* glyph;
1446 bdf_font_t* font;
1447
1448 FT_Memory memory;
1449 FT_Error error = BDF_Err_Ok;
1450
Werner Lemberg319c00d2003-04-23 19:48:24 +00001451 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001452 FT_UNUSED( lineno ); /* only used in debug mode */
1453
1454
Werner Lemberg319c00d2003-04-23 19:48:24 +00001455 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001456
1457 font = p->font;
1458 memory = font->memory;
1459
1460 /* Check for a comment. */
1461 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1462 {
1463 linelen -= 7;
1464
1465 s = line + 7;
1466 if ( *s != 0 )
1467 {
1468 s++;
1469 linelen--;
1470 }
1471 error = _bdf_add_comment( p->font, s, linelen );
1472 goto Exit;
1473 }
1474
1475 /* The very first thing expected is the number of glyphs. */
1476 if ( !( p->flags & _BDF_GLYPHS ) )
1477 {
1478 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1479 {
1480 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1481 error = BDF_Err_Missing_Chars_Field;
1482 goto Exit;
1483 }
1484
David Turner68df4f72005-03-15 18:18:57 +00001485 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001486 if ( error )
1487 goto Exit;
1488 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1489
1490 /* Make sure the number of glyphs is non-zero. */
1491 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001492 font->glyphs_size = 64;
1493
Werner Lemberga08b2172007-03-28 07:17:17 +00001494 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1495 /* number of code points available in Unicode). */
1496 if ( p->cnt >= 1114112UL )
1497 {
1498 error = BDF_Err_Invalid_Argument;
1499 goto Exit;
1500 }
1501
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001502 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1503 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001504
David Turner993a8d02002-05-18 12:03:43 +00001505 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001506
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001507 goto Exit;
1508 }
1509
1510 /* Check for the ENDFONT field. */
1511 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1512 {
1513 /* Sort the glyphs by encoding. */
1514 ft_qsort( (char *)font->glyphs,
1515 font->glyphs_used,
1516 sizeof ( bdf_glyph_t ),
1517 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001518
1519 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001520
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001521 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001522 }
1523
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001524 /* Check for the ENDCHAR field. */
1525 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1526 {
1527 p->glyph_enc = 0;
1528 p->flags &= ~_BDF_GLYPH_BITS;
1529
1530 goto Exit;
1531 }
1532
1533 /* Check to see whether a glyph is being scanned but should be */
1534 /* ignored because it is an unencoded glyph. */
1535 if ( ( p->flags & _BDF_GLYPH ) &&
1536 p->glyph_enc == -1 &&
1537 p->opts->keep_unencoded == 0 )
1538 goto Exit;
1539
1540 /* Check for the STARTCHAR field. */
1541 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1542 {
1543 /* Set the character name in the parse info first until the */
1544 /* encoding can be checked for an unencoded character. */
1545 FT_FREE( p->glyph_name );
1546
David Turner68df4f72005-03-15 18:18:57 +00001547 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001548 if ( error )
1549 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001550
David Turner68df4f72005-03-15 18:18:57 +00001551 _bdf_list_shift( &p->list, 1 );
1552
1553 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001554
Werner Lembergba03af62007-05-30 13:57:02 +00001555 if ( !s )
1556 {
1557 error = BDF_Err_Invalid_File_Format;
1558 goto Exit;
1559 }
1560
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001561 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1562 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001563
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001564 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1565
1566 p->flags |= _BDF_GLYPH;
1567
1568 goto Exit;
1569 }
1570
1571 /* Check for the ENCODING field. */
1572 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1573 {
1574 if ( !( p->flags & _BDF_GLYPH ) )
1575 {
1576 /* Missing STARTCHAR field. */
1577 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1578 error = BDF_Err_Missing_Startchar_Field;
1579 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001580 }
1581
David Turner68df4f72005-03-15 18:18:57 +00001582 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001583 if ( error )
1584 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001585
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001586 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001587
David Turner481838e2006-02-23 12:40:14 +00001588 /* Check that the encoding is in the range [0,65536] because */
1589 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001590 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001591 {
1592 error = BDF_Err_Invalid_File_Format;
1593 goto Exit;
1594 }
1595
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001596 /* Check to see whether this encoding has already been encountered. */
1597 /* If it has then change it to unencoded so it gets added if */
1598 /* indicated. */
1599 if ( p->glyph_enc >= 0 )
1600 {
1601 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1602 {
1603 /* Emit a message saying a glyph has been moved to the */
1604 /* unencoded area. */
1605 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1606 p->glyph_enc, p->glyph_name ));
1607 p->glyph_enc = -1;
1608 font->modified = 1;
1609 }
1610 else
1611 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1612 }
1613
1614 if ( p->glyph_enc >= 0 )
1615 {
1616 /* Make sure there are enough glyphs allocated in case the */
1617 /* number of characters happen to be wrong. */
1618 if ( font->glyphs_used == font->glyphs_size )
1619 {
1620 if ( FT_RENEW_ARRAY( font->glyphs,
1621 font->glyphs_size,
1622 font->glyphs_size + 64 ) )
1623 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001624
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001625 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001626 }
1627
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001628 glyph = font->glyphs + font->glyphs_used++;
1629 glyph->name = p->glyph_name;
1630 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001631
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001632 /* Reset the initial glyph info. */
1633 p->glyph_name = 0;
1634 }
1635 else
1636 {
1637 /* Unencoded glyph. Check to see whether it should */
1638 /* be added or not. */
1639 if ( p->opts->keep_unencoded != 0 )
1640 {
1641 /* Allocate the next unencoded glyph. */
1642 if ( font->unencoded_used == font->unencoded_size )
1643 {
David Turner68df4f72005-03-15 18:18:57 +00001644 if ( FT_RENEW_ARRAY( font->unencoded ,
1645 font->unencoded_size,
1646 font->unencoded_size + 4 ) )
1647 goto Exit;
1648
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001649 font->unencoded_size += 4;
1650 }
1651
1652 glyph = font->unencoded + font->unencoded_used;
1653 glyph->name = p->glyph_name;
1654 glyph->encoding = font->unencoded_used++;
1655 }
1656 else
1657 /* Free up the glyph name if the unencoded shouldn't be */
1658 /* kept. */
1659 FT_FREE( p->glyph_name );
1660
1661 p->glyph_name = 0;
1662 }
1663
1664 /* Clear the flags that might be added when width and height are */
1665 /* checked for consistency. */
1666 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1667
1668 p->flags |= _BDF_ENCODING;
1669
1670 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001671 }
1672
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001673 /* Point at the glyph being constructed. */
1674 if ( p->glyph_enc == -1 )
1675 glyph = font->unencoded + ( font->unencoded_used - 1 );
1676 else
1677 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001678
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001679 /* Check to see whether a bitmap is being constructed. */
1680 if ( p->flags & _BDF_BITMAP )
1681 {
1682 /* If there are more rows than are specified in the glyph metrics, */
1683 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001684 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001685 {
1686 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1687 {
1688 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1689 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001690 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001691 }
1692
1693 goto Exit;
1694 }
1695
1696 /* Only collect the number of nibbles indicated by the glyph */
1697 /* metrics. If there are more columns, they are simply ignored. */
1698 nibbles = glyph->bpr << 1;
1699 bp = glyph->bitmap + p->row * glyph->bpr;
1700
David Turnerb698eed2006-02-23 14:50:13 +00001701 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001702 {
1703 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001704 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001705 if ( i + 1 < nibbles && ( i & 1 ) )
1706 *++bp = 0;
1707 }
1708
1709 /* Remove possible garbage at the right. */
1710 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001711 if ( glyph->bbx.width )
1712 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001713
1714 /* If any line has extra columns, indicate they have been removed. */
1715 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1716 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1717 {
1718 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1719 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1720 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001721 }
1722
1723 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001724 goto Exit;
1725 }
David Turner993a8d02002-05-18 12:03:43 +00001726
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001727 /* Expect the SWIDTH (scalable width) field next. */
1728 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1729 {
1730 if ( !( p->flags & _BDF_ENCODING ) )
1731 {
1732 /* Missing ENCODING field. */
1733 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1734 error = BDF_Err_Missing_Encoding_Field;
1735 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001736 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001737
David Turner68df4f72005-03-15 18:18:57 +00001738 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001739 if ( error )
1740 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001741
David Turnerb1b47622002-05-21 21:17:43 +00001742 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001743 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001744
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001745 goto Exit;
1746 }
David Turner993a8d02002-05-18 12:03:43 +00001747
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001748 /* Expect the DWIDTH (scalable width) field next. */
1749 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1750 {
David Turner68df4f72005-03-15 18:18:57 +00001751 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001752 if ( error )
1753 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001754
David Turnerb1b47622002-05-21 21:17:43 +00001755 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001756
1757 if ( !( p->flags & _BDF_SWIDTH ) )
1758 {
1759 /* Missing SWIDTH field. Emit an auto correction message and set */
1760 /* the scalable width from the device width. */
1761 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1762
Werner Lemberg02d4d592002-05-28 22:38:05 +00001763 glyph->swidth = (unsigned short)FT_MulDiv(
1764 glyph->dwidth, 72000L,
1765 (FT_Long)( font->point_size *
1766 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001767 }
1768
1769 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001770 goto Exit;
1771 }
David Turner993a8d02002-05-18 12:03:43 +00001772
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001773 /* Expect the BBX field next. */
1774 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1775 {
David Turner68df4f72005-03-15 18:18:57 +00001776 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001777 if ( error )
1778 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001779
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001780 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1781 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1782 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1783 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1784
1785 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001786 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1787 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001788
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001789 /* Determine the overall font bounding box as the characters are */
1790 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001791 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1792 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001793
David Turnerb1b47622002-05-21 21:17:43 +00001794 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001795
Werner Lembergdfa46192004-03-05 09:26:24 +00001796 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1797 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1798 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001799
1800 if ( !( p->flags & _BDF_DWIDTH ) )
1801 {
1802 /* Missing DWIDTH field. Emit an auto correction message and set */
1803 /* the device width to the glyph width. */
1804 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1805 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001806 }
1807
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001808 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1809 /* value if necessary. */
1810 if ( p->opts->correct_metrics != 0 )
1811 {
1812 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001813 unsigned short sw = (unsigned short)FT_MulDiv(
1814 glyph->dwidth, 72000L,
1815 (FT_Long)( font->point_size *
1816 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001817
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001818
1819 if ( sw != glyph->swidth )
1820 {
1821 glyph->swidth = sw;
1822
1823 if ( p->glyph_enc == -1 )
1824 _bdf_set_glyph_modified( font->umod,
1825 font->unencoded_used - 1 );
1826 else
1827 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1828
1829 p->flags |= _BDF_SWIDTH_ADJ;
1830 font->modified = 1;
1831 }
David Turner993a8d02002-05-18 12:03:43 +00001832 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001833
David Turner993a8d02002-05-18 12:03:43 +00001834 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001835 goto Exit;
1836 }
David Turner993a8d02002-05-18 12:03:43 +00001837
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001838 /* And finally, gather up the bitmap. */
1839 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1840 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001841 unsigned long bitmap_size;
1842
1843
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001844 if ( !( p->flags & _BDF_BBX ) )
1845 {
1846 /* Missing BBX field. */
1847 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1848 error = BDF_Err_Missing_Bbx_Field;
1849 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001850 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001851
1852 /* Allocate enough space for the bitmap. */
1853 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001854
1855 bitmap_size = glyph->bpr * glyph->bbx.height;
1856 if ( bitmap_size > 0xFFFFU )
1857 {
1858 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1859 error = BDF_Err_Bbx_Too_Big;
1860 goto Exit;
1861 }
1862 else
1863 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001864
1865 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1866 goto Exit;
1867
1868 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001869 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001870
1871 goto Exit;
1872 }
1873
1874 error = BDF_Err_Invalid_File_Format;
1875
1876 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001877 if ( error && ( p->flags & _BDF_GLYPH ) )
1878 FT_FREE( p->glyph_name );
1879
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001880 return error;
David Turner993a8d02002-05-18 12:03:43 +00001881 }
1882
David Turner993a8d02002-05-18 12:03:43 +00001883
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001884 /* Load the font properties. */
1885 static FT_Error
1886 _bdf_parse_properties( char* line,
1887 unsigned long linelen,
1888 unsigned long lineno,
1889 void* call_data,
1890 void* client_data )
1891 {
1892 unsigned long vlen;
1893 _bdf_line_func_t* next;
1894 _bdf_parse_t* p;
1895 char* name;
1896 char* value;
1897 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001898 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001899
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001900 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001901
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001902
1903 next = (_bdf_line_func_t *)call_data;
1904 p = (_bdf_parse_t *) client_data;
1905
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001906 /* Check for the end of the properties. */
1907 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1908 {
1909 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1910 /* encountered yet, then make sure they are added as properties and */
1911 /* make sure they are set from the font bounding box info. */
1912 /* */
1913 /* This is *always* done regardless of the options, because X11 */
1914 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001915 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001916 {
1917 p->font->font_ascent = p->font->bbx.ascent;
1918 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1919 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1920 if ( error )
1921 goto Exit;
1922
1923 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1924 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001925 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001926
Werner Lemberg428c2e42003-04-25 05:35:04 +00001927 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001928 {
1929 p->font->font_descent = p->font->bbx.descent;
1930 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1931 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1932 if ( error )
1933 goto Exit;
1934
1935 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1936 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001937 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001938
David Turner993a8d02002-05-18 12:03:43 +00001939 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001940 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001941
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001942 goto Exit;
1943 }
David Turner993a8d02002-05-18 12:03:43 +00001944
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001945 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1946 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1947 goto Exit;
1948
1949 /* Handle COMMENT fields and properties in a special way to preserve */
1950 /* the spacing. */
1951 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1952 {
David Turner993a8d02002-05-18 12:03:43 +00001953 name = value = line;
1954 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001955 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001956 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001957 error = _bdf_add_property( p->font, name, value );
1958 if ( error )
1959 goto Exit;
1960 }
1961 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1962 {
1963 error = _bdf_add_property( p->font, name, value );
1964 if ( error )
1965 goto Exit;
1966 }
1967 else
1968 {
David Turner68df4f72005-03-15 18:18:57 +00001969 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001970 if ( error )
1971 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001972 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001973
David Turner68df4f72005-03-15 18:18:57 +00001974 _bdf_list_shift( &p->list, 1 );
1975 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001976
1977 error = _bdf_add_property( p->font, name, value );
1978 if ( error )
1979 goto Exit;
1980 }
1981
1982 Exit:
1983 return error;
David Turner993a8d02002-05-18 12:03:43 +00001984 }
1985
David Turner993a8d02002-05-18 12:03:43 +00001986
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001987 /* Load the font header. */
1988 static FT_Error
1989 _bdf_parse_start( char* line,
1990 unsigned long linelen,
1991 unsigned long lineno,
1992 void* call_data,
1993 void* client_data )
1994 {
1995 unsigned long slen;
1996 _bdf_line_func_t* next;
1997 _bdf_parse_t* p;
1998 bdf_font_t* font;
1999 char *s;
David Turner993a8d02002-05-18 12:03:43 +00002000
David Turnerd490e372002-05-28 23:40:37 +00002001 FT_Memory memory = NULL;
2002 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002003
2004 FT_UNUSED( lineno ); /* only used in debug mode */
2005
2006
2007 next = (_bdf_line_func_t *)call_data;
2008 p = (_bdf_parse_t *) client_data;
2009
2010 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002011 memory = p->font->memory;
2012
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002013 /* Check for a comment. This is done to handle those fonts that have */
2014 /* comments before the STARTFONT line for some reason. */
2015 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2016 {
2017 if ( p->opts->keep_comments != 0 && p->font != 0 )
2018 {
2019 linelen -= 7;
2020
2021 s = line + 7;
2022 if ( *s != 0 )
2023 {
2024 s++;
2025 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002026 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002027
2028 error = _bdf_add_comment( p->font, s, linelen );
2029 if ( error )
2030 goto Exit;
2031 /* here font is not defined! */
2032 }
2033
2034 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002035 }
2036
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002037 if ( !( p->flags & _BDF_START ) )
2038 {
2039 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002040
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002041 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2042 {
2043 /* No STARTFONT field is a good indication of a problem. */
2044 error = BDF_Err_Missing_Startfont_Field;
2045 goto Exit;
2046 }
David Turner993a8d02002-05-18 12:03:43 +00002047
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002048 p->flags = _BDF_START;
2049 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002050
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002051 if ( FT_NEW( font ) )
2052 goto Exit;
2053 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002054
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 font->memory = p->memory;
2056 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002057
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002058 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002059 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002060 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002061
David Turner993a8d02002-05-18 12:03:43 +00002062
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002063 error = hash_init( &(font->proptbl), memory );
2064 if ( error )
2065 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002066 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002067 i < _num_bdf_properties; i++, prop++ )
2068 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002069 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002070 &(font->proptbl), memory );
2071 if ( error )
2072 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002073 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002074 }
2075
2076 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2077 goto Exit;
2078 error = hash_init( (hashtable *)p->font->internal,memory );
2079 if ( error )
2080 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002081 p->font->spacing = p->opts->font_spacing;
2082 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002083
2084 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002085 }
2086
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002087 /* Check for the start of the properties. */
2088 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2089 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002090 if ( !( p->flags & _BDF_FONT_BBX ) )
Werner Lembergfb690292010-06-23 10:00:52 +02002091 {
2092 /* Missing the FONTBOUNDINGBOX field. */
2093 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2094 error = BDF_Err_Missing_Fontboundingbox_Field;
2095 goto Exit;
2096 }
2097
David Turner68df4f72005-03-15 18:18:57 +00002098 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002099 if ( error )
2100 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002101 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002102 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2103
2104 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2105 goto Exit;
2106
2107 p->flags |= _BDF_PROPS;
2108 *next = _bdf_parse_properties;
2109
2110 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002111 }
2112
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002113 /* Check for the FONTBOUNDINGBOX field. */
2114 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2115 {
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002116 if ( !( p->flags & _BDF_SIZE ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002117 {
2118 /* Missing the SIZE field. */
2119 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2120 error = BDF_Err_Missing_Size_Field;
2121 goto Exit;
2122 }
2123
David Turner68df4f72005-03-15 18:18:57 +00002124 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002125 if ( error )
2126 goto Exit;
2127
2128 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2129 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2130
2131 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2132 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2133
David Turnerd490e372002-05-28 23:40:37 +00002134 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002135 p->font->bbx.y_offset );
2136
2137 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002138
2139 p->flags |= _BDF_FONT_BBX;
2140
2141 goto Exit;
2142 }
2143
2144 /* The next thing to check for is the FONT field. */
2145 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2146 {
David Turner68df4f72005-03-15 18:18:57 +00002147 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002148 if ( error )
2149 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002150 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002151
David Turner68df4f72005-03-15 18:18:57 +00002152 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002153
2154 if ( !s )
2155 {
2156 error = BDF_Err_Invalid_File_Format;
2157 goto Exit;
2158 }
2159
Werner Lembergfb690292010-06-23 10:00:52 +02002160 /* Allowing multiple `FONT' lines (which is invalid) doesn't hurt... */
2161 FT_FREE( p->font->name );
2162
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002163 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2164 goto Exit;
2165 FT_MEM_COPY( p->font->name, s, slen + 1 );
2166
2167 /* If the font name is an XLFD name, set the spacing to the one in */
2168 /* the font name. If there is no spacing fall back on the default. */
2169 error = _bdf_set_default_spacing( p->font, p->opts );
2170 if ( error )
2171 goto Exit;
2172
2173 p->flags |= _BDF_FONT_NAME;
2174
2175 goto Exit;
2176 }
2177
2178 /* Check for the SIZE field. */
2179 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2180 {
2181 if ( !( p->flags & _BDF_FONT_NAME ) )
2182 {
2183 /* Missing the FONT field. */
2184 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2185 error = BDF_Err_Missing_Font_Field;
2186 goto Exit;
2187 }
2188
David Turner68df4f72005-03-15 18:18:57 +00002189 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002190 if ( error )
2191 goto Exit;
2192
2193 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2194 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2195 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2196
2197 /* Check for the bits per pixel field. */
2198 if ( p->list.used == 5 )
2199 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002200 unsigned short bitcount, i, shift;
2201
2202
2203 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2204
2205 /* Only values 1, 2, 4, 8 are allowed. */
2206 shift = p->font->bpp;
2207 bitcount = 0;
2208 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002209 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002210 if ( shift & 1 )
2211 bitcount = i;
2212 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002213 }
David Turner993a8d02002-05-18 12:03:43 +00002214
Werner Lembergbd8e3242002-06-12 08:43:58 +00002215 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002216
2217 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002219 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002220 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002221 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002222 }
2223 }
2224 else
2225 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002226
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002227 p->flags |= _BDF_SIZE;
2228
2229 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002230 }
2231
Werner Lembergb21d7bc2010-06-24 07:40:49 +02002232 /* Check for the CHARS field -- font properties are optional */
2233 if ( ft_memcmp( line, "CHARS", 5 ) == 0 )
2234 {
2235 char nbuf[128];
2236
2237
2238 if ( !( p->flags & _BDF_FONT_BBX ) )
2239 {
2240 /* Missing the FONTBOUNDINGBOX field. */
2241 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONTBOUNDINGBOX" ));
2242 error = BDF_Err_Missing_Fontboundingbox_Field;
2243 goto Exit;
2244 }
2245
2246 /* Add the two standard X11 properties which are required */
2247 /* for compiling fonts. */
2248 p->font->font_ascent = p->font->bbx.ascent;
2249 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
2250 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
2251 if ( error )
2252 goto Exit;
2253 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
2254
2255 p->font->font_descent = p->font->bbx.descent;
2256 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
2257 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
2258 if ( error )
2259 goto Exit;
2260 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
2261
2262 p->font->modified = 1;
2263
2264 *next = _bdf_parse_glyphs;
2265
2266 /* A special return value. */
2267 error = -1;
2268 goto Exit;
2269 }
2270
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002271 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002272
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002273 Exit:
2274 return error;
2275 }
David Turner993a8d02002-05-18 12:03:43 +00002276
2277
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002278 /*************************************************************************/
2279 /* */
2280 /* API. */
2281 /* */
2282 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002283
David Turner993a8d02002-05-18 12:03:43 +00002284
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002285 FT_LOCAL_DEF( FT_Error )
2286 bdf_load_font( FT_Stream stream,
2287 FT_Memory extmemory,
2288 bdf_options_t* opts,
2289 bdf_font_t* *font )
2290 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002291 unsigned long lineno = 0; /* make compiler happy */
Werner Lembergc8f5b982010-07-12 21:13:22 +02002292 _bdf_parse_t *p = NULL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002293
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002294 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002295 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296
2297
David Turner68df4f72005-03-15 18:18:57 +00002298 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002299 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002300
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002301 memory = NULL;
2302 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2303 p->minlb = 32767;
2304 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002305
David Turner68df4f72005-03-15 18:18:57 +00002306 _bdf_list_init( &p->list, extmemory );
2307
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002308 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002309 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002310 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002311 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002312
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002313 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002314 {
2315 /* If the font is not proportional, set the font's monowidth */
2316 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002317 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002318
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002319 if ( p->font->spacing != BDF_PROPORTIONAL )
2320 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002321
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 /* If the number of glyphs loaded is not that of the original count, */
2323 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002324 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002325 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002326 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2327 p->font->glyphs_used + p->font->unencoded_used ));
2328 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002329 }
2330
2331 /* Once the font has been loaded, adjust the overall font metrics if */
2332 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002333 if ( p->opts->correct_metrics != 0 &&
2334 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002335 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002336 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002337 {
2338 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002339 p->font->bbx.width, p->maxrb - p->minlb ));
2340 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2341 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002342 }
2343
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002344 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002345 {
2346 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002347 p->font->bbx.x_offset, p->minlb ));
2348 p->font->bbx.x_offset = p->minlb;
2349 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002350 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002351
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002352 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002353 {
2354 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002355 p->font->bbx.ascent, p->maxas ));
2356 p->font->bbx.ascent = p->maxas;
2357 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002358 }
2359
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002360 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002361 {
2362 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002363 p->font->bbx.descent, p->maxds ));
2364 p->font->bbx.descent = p->maxds;
2365 p->font->bbx.y_offset = (short)( -p->maxds );
2366 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002367 }
2368
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002369 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002370 {
2371 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002372 p->font->bbx.height, p->maxas + p->maxds ));
2373 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002374 }
2375
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002376 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002377 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2378 }
David Turner993a8d02002-05-18 12:03:43 +00002379 }
2380
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002381 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002382 {
2383 {
2384 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002385 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg5b591e42007-06-01 22:16:43 +00002386 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387 /* Error happened while parsing header. */
2388 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002389 error = BDF_Err_Corrupted_Font_Header;
2390 goto Exit;
2391 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002392 else
Werner Lemberg5b591e42007-06-01 22:16:43 +00002393 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002394 /* Error happened when parsing glyphs. */
2395 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002396 error = BDF_Err_Corrupted_Font_Glyphs;
2397 goto Exit;
2398 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002399 }
David Turner993a8d02002-05-18 12:03:43 +00002400 }
2401
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002402 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002403 {
2404 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002405 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002406
Werner Lemberg370aea82010-06-08 08:37:11 +02002407 if ( p->font->comments_len > 0 )
2408 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002409 if ( FT_RENEW_ARRAY( p->font->comments,
2410 p->font->comments_len,
2411 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002412 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002413
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002414 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002415 }
David Turner993a8d02002-05-18 12:03:43 +00002416 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002417 else if ( error == BDF_Err_Ok )
2418 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002419
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002420 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002421
2422 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002423 if ( p )
2424 {
David Turner68df4f72005-03-15 18:18:57 +00002425 _bdf_list_done( &p->list );
2426
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002427 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002428
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002429 FT_FREE( p );
2430 }
2431
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002432 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002433
2434 Fail:
2435 bdf_free_font( p->font );
2436
2437 memory = extmemory;
2438
2439 FT_FREE( p->font );
2440
2441 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002442 }
David Turner993a8d02002-05-18 12:03:43 +00002443
2444
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002445 FT_LOCAL_DEF( void )
2446 bdf_free_font( bdf_font_t* font )
2447 {
2448 bdf_property_t* prop;
2449 unsigned long i;
2450 bdf_glyph_t* glyphs;
2451 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002452
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002453
2454 if ( font == 0 )
2455 return;
David Turner993a8d02002-05-18 12:03:43 +00002456
2457 memory = font->memory;
2458
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002459 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002460
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002461 /* Free up the internal hash table of property names. */
2462 if ( font->internal )
2463 {
2464 hash_free( (hashtable *)font->internal, memory );
2465 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002466 }
2467
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002468 /* Free up the comment info. */
2469 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002470
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002471 /* Free up the properties. */
2472 for ( i = 0; i < font->props_size; i++ )
2473 {
2474 if ( font->props[i].format == BDF_ATOM )
2475 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002476 }
2477
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002478 FT_FREE( font->props );
2479
2480 /* Free up the character info. */
2481 for ( i = 0, glyphs = font->glyphs;
2482 i < font->glyphs_used; i++, glyphs++ )
2483 {
2484 FT_FREE( glyphs->name );
2485 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002486 }
2487
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002488 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2489 i++, glyphs++ )
2490 {
2491 FT_FREE( glyphs->name );
2492 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002493 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002494
2495 FT_FREE( font->glyphs );
2496 FT_FREE( font->unencoded );
2497
2498 /* Free up the overflow storage if it was used. */
2499 for ( i = 0, glyphs = font->overflow.glyphs;
2500 i < font->overflow.glyphs_used; i++, glyphs++ )
2501 {
2502 FT_FREE( glyphs->name );
2503 FT_FREE( glyphs->bitmap );
2504 }
2505
2506 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002507
2508 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002509 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002510
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002511 /* Free up the user defined properties. */
Werner Lemberg8c2c2552010-06-24 07:36:21 +02002512 for ( prop = font->user_props, i = 0;
2513 i < font->nuser_props; i++, prop++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002514 {
2515 FT_FREE( prop->name );
2516 if ( prop->format == BDF_ATOM )
2517 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002518 }
David Turner993a8d02002-05-18 12:03:43 +00002519
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002520 FT_FREE( font->user_props );
2521
2522 /* FREE( font ); */ /* XXX Fixme */
2523 }
David Turner993a8d02002-05-18 12:03:43 +00002524
2525
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002526 FT_LOCAL_DEF( bdf_property_t * )
2527 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002528 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002529 {
2530 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002531
David Turner993a8d02002-05-18 12:03:43 +00002532
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002533 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002534 return 0;
2535
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002536 hn = hash_lookup( name, (hashtable *)font->internal );
2537
suzuki toshiya704f4d72009-09-13 00:50:14 +09002538 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002539 }
2540
2541
2542/* END */