blob: 6ce5c26c210cf0ec6d029815cc72ee0c6c86b6d5 [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 {
suzuki toshiya2bbcb7e2009-08-01 00:30:15 +0900652 bytes = (ptrdiff_t)FT_Stream_TryRead( stream, (FT_Byte*)buf + cursor,
653 (FT_ULong)(buf_size - cursor) );
David Turner68df4f72005-03-15 18:18:57 +0000654 avail = cursor + bytes;
655 cursor = 0;
656 refill = 0;
657 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000658
David Turner68df4f72005-03-15 18:18:57 +0000659 end = start;
660
Werner Lembergebf55852005-03-16 01:49:54 +0000661 /* should we skip an optional character like \n or \r? */
David Turner68df4f72005-03-15 18:18:57 +0000662 if ( start < avail && buf[start] == to_skip )
663 {
664 start += 1;
665 to_skip = NO_SKIP;
666 continue;
667 }
668
669 /* try to find the end of the line */
670 while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
671 end++;
672
Werner Lembergebf55852005-03-16 01:49:54 +0000673 /* if we hit the end of the buffer, try shifting its content */
674 /* or even resizing it */
David Turner68df4f72005-03-15 18:18:57 +0000675 if ( end >= avail )
676 {
677 if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
678 break; /* ignore it then exit */
679
680 if ( start == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000681 {
Werner Lembergebf55852005-03-16 01:49:54 +0000682 /* this line is definitely too long; try resizing the input */
683 /* buffer a bit to handle it. */
David Turner68df4f72005-03-15 18:18:57 +0000684 FT_ULong new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000685
Werner Lembergebf55852005-03-16 01:49:54 +0000686
687 if ( buf_size >= 65536UL ) /* limit ourselves to 64KByte */
David Turner68df4f72005-03-15 18:18:57 +0000688 {
689 error = BDF_Err_Invalid_Argument;
690 goto Exit;
691 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000692
Werner Lembergebf55852005-03-16 01:49:54 +0000693 new_size = buf_size * 2;
David Turner68df4f72005-03-15 18:18:57 +0000694 if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
695 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000696
David Turner68df4f72005-03-15 18:18:57 +0000697 cursor = buf_size;
698 buf_size = new_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000699 }
700 else
701 {
David Turner68df4f72005-03-15 18:18:57 +0000702 bytes = avail - start;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000703
Werner Lembergebf55852005-03-16 01:49:54 +0000704 FT_MEM_COPY( buf, buf + start, bytes );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000705
David Turner68df4f72005-03-15 18:18:57 +0000706 cursor = bytes;
707 avail -= bytes;
708 start = 0;
David Turnerd490e372002-05-28 23:40:37 +0000709 }
David Turner68df4f72005-03-15 18:18:57 +0000710 refill = 1;
711 continue;
David Turner993a8d02002-05-18 12:03:43 +0000712 }
David Turner68df4f72005-03-15 18:18:57 +0000713
714 /* Temporarily NUL-terminate the line. */
715 hold = buf[end];
716 buf[end] = 0;
717
718 /* XXX: Use encoding independent value for 0x1a */
719 if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
720 {
Werner Lembergebf55852005-03-16 01:49:54 +0000721 error = (*cb)( buf + start, end - start, lineno,
722 (void*)&cb, client_data );
David Turner68df4f72005-03-15 18:18:57 +0000723 if ( error )
724 break;
725 }
726
727 lineno += 1;
728 buf[end] = (char)hold;
Werner Lembergebf55852005-03-16 01:49:54 +0000729 start = end + 1;
David Turner68df4f72005-03-15 18:18:57 +0000730
731 if ( hold == '\n' )
732 to_skip = '\r';
733 else if ( hold == '\r' )
734 to_skip = '\n';
735 else
736 to_skip = NO_SKIP;
David Turner993a8d02002-05-18 12:03:43 +0000737 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000738
David Turner68df4f72005-03-15 18:18:57 +0000739 *lno = lineno;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000740
741 Exit:
Werner Lemberg7925edc2002-05-30 19:29:41 +0000742 FT_FREE( buf );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000743 return error;
David Turner993a8d02002-05-18 12:03:43 +0000744 }
David Turner993a8d02002-05-18 12:03:43 +0000745
746
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000747 /* XXX: make this work with EBCDIC also */
David Turner993a8d02002-05-18 12:03:43 +0000748
David Turnerb1b47622002-05-21 21:17:43 +0000749 static const unsigned char a2i[128] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000750 {
David Turner993a8d02002-05-18 12:03:43 +0000751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
753 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
754 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
755 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
756 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 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, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
760 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
761 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000762 };
David Turner993a8d02002-05-18 12:03:43 +0000763
David Turnerb1b47622002-05-21 21:17:43 +0000764 static const unsigned char odigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000765 {
David Turner993a8d02002-05-18 12:03:43 +0000766 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
767 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
768 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
769 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000770 };
David Turner993a8d02002-05-18 12:03:43 +0000771
David Turnerb1b47622002-05-21 21:17:43 +0000772 static const unsigned char ddigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000773 {
David Turner993a8d02002-05-18 12:03:43 +0000774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
775 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000778 };
David Turner993a8d02002-05-18 12:03:43 +0000779
David Turnerb1b47622002-05-21 21:17:43 +0000780 static const unsigned char hdigits[32] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000781 {
David Turner993a8d02002-05-18 12:03:43 +0000782 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
783 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
784 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
785 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000786 };
David Turner993a8d02002-05-18 12:03:43 +0000787
David Turner993a8d02002-05-18 12:03:43 +0000788
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000789#define isdigok( m, d ) (m[(d) >> 3] & ( 1 << ( (d) & 7 ) ) )
David Turner993a8d02002-05-18 12:03:43 +0000790
David Turner993a8d02002-05-18 12:03:43 +0000791
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000792 /* Routine to convert an ASCII string into an unsigned long integer. */
793 static unsigned long
794 _bdf_atoul( char* s,
795 char** end,
796 int base )
David Turner993a8d02002-05-18 12:03:43 +0000797 {
David Turnerb1b47622002-05-21 21:17:43 +0000798 unsigned long v;
799 const unsigned char* dmap;
David Turner993a8d02002-05-18 12:03:43 +0000800
801
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000802 if ( s == 0 || *s == 0 )
David Turner993a8d02002-05-18 12:03:43 +0000803 return 0;
804
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000805 /* Make sure the radix is something recognizable. Default to 10. */
806 switch ( base )
807 {
808 case 8:
809 dmap = odigits;
810 break;
811 case 16:
812 dmap = hdigits;
813 break;
814 default:
815 base = 10;
816 dmap = ddigits;
817 break;
David Turner993a8d02002-05-18 12:03:43 +0000818 }
819
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000820 /* Check for the special hex prefix. */
821 if ( *s == '0' &&
822 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
823 {
824 base = 16;
825 dmap = hdigits;
826 s += 2;
David Turner993a8d02002-05-18 12:03:43 +0000827 }
828
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000829 for ( v = 0; isdigok( dmap, *s ); s++ )
830 v = v * base + a2i[(int)*s];
David Turner993a8d02002-05-18 12:03:43 +0000831
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000832 if ( end != 0 )
David Turner993a8d02002-05-18 12:03:43 +0000833 *end = s;
834
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000835 return v;
836 }
David Turner993a8d02002-05-18 12:03:43 +0000837
David Turner993a8d02002-05-18 12:03:43 +0000838
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000839 /* Routine to convert an ASCII string into an signed long integer. */
840 static long
841 _bdf_atol( char* s,
842 char** end,
843 int base )
844 {
David Turnerb1b47622002-05-21 21:17:43 +0000845 long v, neg;
846 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000847
848
849 if ( s == 0 || *s == 0 )
850 return 0;
851
852 /* Make sure the radix is something recognizable. Default to 10. */
853 switch ( base )
854 {
855 case 8:
856 dmap = odigits;
857 break;
858 case 16:
859 dmap = hdigits;
860 break;
861 default:
862 base = 10;
863 dmap = ddigits;
864 break;
865 }
866
867 /* Check for a minus sign. */
868 neg = 0;
869 if ( *s == '-' )
870 {
871 s++;
872 neg = 1;
873 }
874
875 /* Check for the special hex prefix. */
876 if ( *s == '0' &&
877 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
878 {
879 base = 16;
880 dmap = hdigits;
881 s += 2;
882 }
883
884 for ( v = 0; isdigok( dmap, *s ); s++ )
885 v = v * base + a2i[(int)*s];
886
887 if ( end != 0 )
888 *end = s;
889
890 return ( !neg ) ? v : -v;
891 }
892
893
894 /* Routine to convert an ASCII string into an signed short integer. */
895 static short
896 _bdf_atos( char* s,
897 char** end,
898 int base )
899 {
David Turnerb1b47622002-05-21 21:17:43 +0000900 short v, neg;
901 const unsigned char* dmap;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000902
903
904 if ( s == 0 || *s == 0 )
905 return 0;
906
907 /* Make sure the radix is something recognizable. Default to 10. */
908 switch ( base )
909 {
910 case 8:
911 dmap = odigits;
912 break;
913 case 16:
914 dmap = hdigits;
915 break;
916 default:
917 base = 10;
918 dmap = ddigits;
919 break;
920 }
921
922 /* Check for a minus. */
923 neg = 0;
924 if ( *s == '-' )
925 {
926 s++;
927 neg = 1;
928 }
929
930 /* Check for the special hex prefix. */
931 if ( *s == '0' &&
932 ( *( s + 1 ) == 'x' || *( s + 1 ) == 'X' ) )
933 {
934 base = 16;
935 dmap = hdigits;
936 s += 2;
937 }
938
939 for ( v = 0; isdigok( dmap, *s ); s++ )
Werner Lemberg233302a2002-05-22 05:41:06 +0000940 v = (short)( v * base + a2i[(int)*s] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000941
942 if ( end != 0 )
943 *end = s;
944
Werner Lemberg233302a2002-05-22 05:41:06 +0000945 return (short)( ( !neg ) ? v : -v );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000946 }
947
948
949 /* Routine to compare two glyphs by encoding so they can be sorted. */
950 static int
951 by_encoding( const void* a,
952 const void* b )
953 {
954 bdf_glyph_t *c1, *c2;
955
956
957 c1 = (bdf_glyph_t *)a;
958 c2 = (bdf_glyph_t *)b;
959
960 if ( c1->encoding < c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000961 return -1;
David Turner68df4f72005-03-15 18:18:57 +0000962
963 if ( c1->encoding > c2->encoding )
David Turner993a8d02002-05-18 12:03:43 +0000964 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000965
David Turner993a8d02002-05-18 12:03:43 +0000966 return 0;
David Turner993a8d02002-05-18 12:03:43 +0000967 }
968
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000969
970 static FT_Error
971 bdf_create_property( char* name,
972 int format,
973 bdf_font_t* font )
974 {
suzuki toshiya704f4d72009-09-13 00:50:14 +0900975 size_t n;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000976 bdf_property_t* p;
977 FT_Memory memory = font->memory;
978 FT_Error error = BDF_Err_Ok;
979
980
981 /* First check to see if the property has */
982 /* already been added or not. If it has, then */
983 /* simply ignore it. */
984 if ( hash_lookup( name, &(font->proptbl) ) )
985 goto Exit;
986
David Turner68df4f72005-03-15 18:18:57 +0000987 if ( FT_RENEW_ARRAY( font->user_props,
988 font->nuser_props,
989 font->nuser_props + 1 ) )
990 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000991
992 p = font->user_props + font->nuser_props;
David Turner68df4f72005-03-15 18:18:57 +0000993 FT_ZERO( p );
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000994
suzuki toshiya704f4d72009-09-13 00:50:14 +0900995 n = ft_strlen( name ) + 1;
996 if ( n > FT_ULONG_MAX )
997 return BDF_Err_Invalid_Argument;
David Turner68df4f72005-03-15 18:18:57 +0000998
Werner Lemberg7cf4d372002-05-21 14:13:01 +0000999 if ( FT_NEW_ARRAY( p->name, n ) )
1000 goto Exit;
1001
1002 FT_MEM_COPY( (char *)p->name, name, n );
1003
1004 p->format = format;
1005 p->builtin = 0;
1006
1007 n = _num_bdf_properties + font->nuser_props;
1008
suzuki toshiya704f4d72009-09-13 00:50:14 +09001009 error = hash_insert( p->name, n, &(font->proptbl), memory );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001010 if ( error )
1011 goto Exit;
1012
1013 font->nuser_props++;
1014
1015 Exit:
David Turner993a8d02002-05-18 12:03:43 +00001016 return error;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001017 }
David Turner993a8d02002-05-18 12:03:43 +00001018
1019
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001020 FT_LOCAL_DEF( bdf_property_t * )
1021 bdf_get_property( char* name,
1022 bdf_font_t* font )
David Turner993a8d02002-05-18 12:03:43 +00001023 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001024 hashnode hn;
1025 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001026
1027
1028 if ( name == 0 || *name == 0 )
1029 return 0;
1030
1031 if ( ( hn = hash_lookup( name, &(font->proptbl) ) ) == 0 )
1032 return 0;
1033
suzuki toshiya704f4d72009-09-13 00:50:14 +09001034 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001035 if ( propid >= _num_bdf_properties )
1036 return font->user_props + ( propid - _num_bdf_properties );
1037
Werner Lemberg233302a2002-05-22 05:41:06 +00001038 return (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001039 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001040
1041
1042 /*************************************************************************/
1043 /* */
1044 /* BDF font file parsing flags and functions. */
1045 /* */
1046 /*************************************************************************/
1047
1048
1049 /* Parse flags. */
1050
1051#define _BDF_START 0x0001
1052#define _BDF_FONT_NAME 0x0002
1053#define _BDF_SIZE 0x0004
1054#define _BDF_FONT_BBX 0x0008
1055#define _BDF_PROPS 0x0010
1056#define _BDF_GLYPHS 0x0020
1057#define _BDF_GLYPH 0x0040
1058#define _BDF_ENCODING 0x0080
1059#define _BDF_SWIDTH 0x0100
1060#define _BDF_DWIDTH 0x0200
1061#define _BDF_BBX 0x0400
1062#define _BDF_BITMAP 0x0800
1063
1064#define _BDF_SWIDTH_ADJ 0x1000
1065
1066#define _BDF_GLYPH_BITS ( _BDF_GLYPH | \
1067 _BDF_ENCODING | \
1068 _BDF_SWIDTH | \
1069 _BDF_DWIDTH | \
1070 _BDF_BBX | \
1071 _BDF_BITMAP )
1072
Werner Lembergf1c2b912006-01-13 14:53:28 +00001073#define _BDF_GLYPH_WIDTH_CHECK 0x40000000UL
1074#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000UL
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001075
1076
1077 /* Auto correction messages. */
1078#define ACMSG1 "FONT_ASCENT property missing. " \
1079 "Added \"FONT_ASCENT %hd\".\n"
1080#define ACMSG2 "FONT_DESCENT property missing. " \
1081 "Added \"FONT_DESCENT %hd\".\n"
1082#define ACMSG3 "Font width != actual width. Old: %hd New: %hd.\n"
1083#define ACMSG4 "Font left bearing != actual left bearing. " \
1084 "Old: %hd New: %hd.\n"
1085#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd.\n"
1086#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd.\n"
1087#define ACMSG7 "Font height != actual height. Old: %hd New: %hd.\n"
1088#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made.\n"
1089#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically.\n"
1090#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width.\n"
1091#define ACMSG11 "SIZE bits per pixel field adjusted to %hd.\n"
1092#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded.\n"
1093#define ACMSG13 "Glyph %ld extra rows removed.\n"
1094#define ACMSG14 "Glyph %ld extra columns removed.\n"
1095#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found.\n"
1096
1097 /* Error messages. */
1098#define ERRMSG1 "[line %ld] Missing \"%s\" line.\n"
1099#define ERRMSG2 "[line %ld] Font header corrupted or missing fields.\n"
1100#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields.\n"
Werner Lemberg26170df2006-03-26 07:19:07 +00001101#define ERRMSG4 "[line %ld] BBX too big.\n"
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001102
1103
1104 static FT_Error
1105 _bdf_add_comment( bdf_font_t* font,
1106 char* comment,
1107 unsigned long len )
David Turner993a8d02002-05-18 12:03:43 +00001108 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001109 char* cp;
1110 FT_Memory memory = font->memory;
1111 FT_Error error = BDF_Err_Ok;
1112
1113
David Turner68df4f72005-03-15 18:18:57 +00001114 if ( FT_RENEW_ARRAY( font->comments,
1115 font->comments_len,
1116 font->comments_len + len + 1 ) )
1117 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001118
1119 cp = font->comments + font->comments_len;
David Turner68df4f72005-03-15 18:18:57 +00001120
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001121 FT_MEM_COPY( cp, comment, len );
David Turner68df4f72005-03-15 18:18:57 +00001122 cp[len] = '\n';
1123
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001124 font->comments_len += len + 1;
1125
1126 Exit:
1127 return error;
David Turner993a8d02002-05-18 12:03:43 +00001128 }
1129
David Turner993a8d02002-05-18 12:03:43 +00001130
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001131 /* Set the spacing from the font name if it exists, or set it to the */
1132 /* default specified in the options. */
1133 static FT_Error
1134 _bdf_set_default_spacing( bdf_font_t* font,
1135 bdf_options_t* opts )
David Turner993a8d02002-05-18 12:03:43 +00001136 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001137 size_t len;
1138 char name[256];
1139 _bdf_list_t list;
1140 FT_Memory memory;
1141 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001142
David Turner993a8d02002-05-18 12:03:43 +00001143
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001144 if ( font == 0 || font->name == 0 || font->name[0] == 0 )
1145 {
1146 error = BDF_Err_Invalid_Argument;
1147 goto Exit;
1148 }
David Turner993a8d02002-05-18 12:03:43 +00001149
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001150 memory = font->memory;
David Turner993a8d02002-05-18 12:03:43 +00001151
David Turner68df4f72005-03-15 18:18:57 +00001152 _bdf_list_init( &list, memory );
1153
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001154 font->spacing = opts->font_spacing;
David Turner993a8d02002-05-18 12:03:43 +00001155
suzuki toshiya704f4d72009-09-13 00:50:14 +09001156 len = ft_strlen( font->name ) + 1;
Werner Lemberga08b2172007-03-28 07:17:17 +00001157 /* Limit ourselves to 256 characters in the font name. */
1158 if ( len >= 256 )
1159 {
1160 error = BDF_Err_Invalid_Argument;
1161 goto Exit;
1162 }
1163
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001164 FT_MEM_COPY( name, font->name, len );
David Turner993a8d02002-05-18 12:03:43 +00001165
David Turner68df4f72005-03-15 18:18:57 +00001166 error = _bdf_list_split( &list, (char *)"-", name, len );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001167 if ( error )
David Turner68df4f72005-03-15 18:18:57 +00001168 goto Fail;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001169
1170 if ( list.used == 15 )
1171 {
1172 switch ( list.field[11][0] )
1173 {
1174 case 'C':
1175 case 'c':
1176 font->spacing = BDF_CHARCELL;
1177 break;
1178 case 'M':
1179 case 'm':
1180 font->spacing = BDF_MONOWIDTH;
1181 break;
1182 case 'P':
1183 case 'p':
1184 font->spacing = BDF_PROPORTIONAL;
1185 break;
David Turner993a8d02002-05-18 12:03:43 +00001186 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001187 }
1188
David Turner68df4f72005-03-15 18:18:57 +00001189 Fail:
1190 _bdf_list_done( &list );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001191
1192 Exit:
1193 return error;
David Turner993a8d02002-05-18 12:03:43 +00001194 }
David Turner993a8d02002-05-18 12:03:43 +00001195
1196
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001197 /* Determine whether the property is an atom or not. If it is, then */
1198 /* clean it up so the double quotes are removed if they exist. */
1199 static int
1200 _bdf_is_atom( char* line,
1201 unsigned long linelen,
1202 char** name,
1203 char** value,
1204 bdf_font_t* font )
1205 {
1206 int hold;
1207 char *sp, *ep;
1208 bdf_property_t* p;
1209
David Turner993a8d02002-05-18 12:03:43 +00001210
1211 *name = sp = ep = line;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001212
1213 while ( *ep && *ep != ' ' && *ep != '\t' )
David Turner993a8d02002-05-18 12:03:43 +00001214 ep++;
1215
1216 hold = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001217 if ( *ep )
David Turner993a8d02002-05-18 12:03:43 +00001218 {
1219 hold = *ep;
1220 *ep = 0;
1221 }
1222
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001223 p = bdf_get_property( sp, font );
David Turner993a8d02002-05-18 12:03:43 +00001224
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001225 /* Restore the character that was saved before any return can happen. */
1226 if ( hold != -1 )
Werner Lemberg233302a2002-05-22 05:41:06 +00001227 *ep = (char)hold;
David Turner993a8d02002-05-18 12:03:43 +00001228
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001229 /* If the property exists and is not an atom, just return here. */
1230 if ( p && p->format != BDF_ATOM )
David Turner993a8d02002-05-18 12:03:43 +00001231 return 0;
1232
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001233 /* The property is an atom. Trim all leading and trailing whitespace */
1234 /* and double quotes for the atom value. */
David Turner993a8d02002-05-18 12:03:43 +00001235 sp = ep;
1236 ep = line + linelen;
1237
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001238 /* Trim the leading whitespace if it exists. */
David Turner993a8d02002-05-18 12:03:43 +00001239 *sp++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001240 while ( *sp &&
1241 ( *sp == ' ' || *sp == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001242 sp++;
1243
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001244 /* Trim the leading double quote if it exists. */
1245 if ( *sp == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001246 sp++;
1247 *value = sp;
1248
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001249 /* Trim the trailing whitespace if it exists. */
1250 while ( ep > sp &&
1251 ( *( ep - 1 ) == ' ' || *( ep - 1 ) == '\t' ) )
David Turner993a8d02002-05-18 12:03:43 +00001252 *--ep = 0;
1253
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001254 /* Trim the trailing double quote if it exists. */
1255 if ( ep > sp && *( ep - 1 ) == '"' )
David Turner993a8d02002-05-18 12:03:43 +00001256 *--ep = 0;
1257
1258 return 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001259 }
David Turner993a8d02002-05-18 12:03:43 +00001260
1261
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001262 static FT_Error
1263 _bdf_add_property( bdf_font_t* font,
1264 char* name,
1265 char* value )
1266 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09001267 size_t propid;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001268 hashnode hn;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001269 bdf_property_t *prop, *fp;
1270 FT_Memory memory = font->memory;
1271 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001272
David Turner993a8d02002-05-18 12:03:43 +00001273
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001274 /* First, check to see if the property already exists in the font. */
1275 if ( ( hn = hash_lookup( name, (hashtable *)font->internal ) ) != 0 )
David Turner993a8d02002-05-18 12:03:43 +00001276 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001277 /* The property already exists in the font, so simply replace */
1278 /* the value of the property with the current value. */
suzuki toshiya704f4d72009-09-13 00:50:14 +09001279 fp = font->props + hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001280
David Turnerb1b47622002-05-21 21:17:43 +00001281 switch ( fp->format )
David Turner993a8d02002-05-18 12:03:43 +00001282 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001283 case BDF_ATOM:
1284 /* Delete the current atom if it exists. */
1285 FT_FREE( fp->value.atom );
1286
David Turnerc0f9c4a2007-02-12 14:55:03 +00001287 if ( value && value[0] != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001288 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001289 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001290 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001291 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001292 break;
1293
1294 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001295 fp->value.l = _bdf_atol( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001296 break;
1297
1298 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001299 fp->value.ul = _bdf_atoul( value, 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001300 break;
David Turnerd490e372002-05-28 23:40:37 +00001301
David Turnerb1b47622002-05-21 21:17:43 +00001302 default:
1303 ;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001304 }
David Turnerd490e372002-05-28 23:40:37 +00001305
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001306 goto Exit;
1307 }
1308
1309 /* See whether this property type exists yet or not. */
1310 /* If not, create it. */
1311 hn = hash_lookup( name, &(font->proptbl) );
1312 if ( hn == 0 )
1313 {
1314 error = bdf_create_property( name, BDF_ATOM, font );
1315 if ( error )
1316 goto Exit;
1317 hn = hash_lookup( name, &(font->proptbl) );
1318 }
1319
1320 /* Allocate another property if this is overflow. */
1321 if ( font->props_used == font->props_size )
1322 {
1323 if ( font->props_size == 0 )
1324 {
1325 if ( FT_NEW_ARRAY( font->props, 1 ) )
1326 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001327 }
1328 else
1329 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001330 if ( FT_RENEW_ARRAY( font->props,
1331 font->props_size,
1332 font->props_size + 1 ) )
1333 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001334 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001335
David Turner993a8d02002-05-18 12:03:43 +00001336 fp = font->props + font->props_size;
Werner Lembergb3d5e9c2002-07-28 05:05:24 +00001337 FT_MEM_ZERO( fp, sizeof ( bdf_property_t ) );
David Turner993a8d02002-05-18 12:03:43 +00001338 font->props_size++;
1339 }
1340
suzuki toshiya704f4d72009-09-13 00:50:14 +09001341 propid = hn->data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001342 if ( propid >= _num_bdf_properties )
1343 prop = font->user_props + ( propid - _num_bdf_properties );
David Turner993a8d02002-05-18 12:03:43 +00001344 else
David Turnerb1b47622002-05-21 21:17:43 +00001345 prop = (bdf_property_t*)_bdf_properties + propid;
David Turner993a8d02002-05-18 12:03:43 +00001346
1347 fp = font->props + font->props_used;
1348
1349 fp->name = prop->name;
1350 fp->format = prop->format;
1351 fp->builtin = prop->builtin;
1352
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001353 switch ( prop->format )
David Turner993a8d02002-05-18 12:03:43 +00001354 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001355 case BDF_ATOM:
David Turnerc0f9c4a2007-02-12 14:55:03 +00001356 fp->value.atom = 0;
1357 if ( value != 0 && value[0] )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001358 {
David Turnerc0f9c4a2007-02-12 14:55:03 +00001359 if ( FT_STRDUP( fp->value.atom, value ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001360 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001361 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001362 break;
David Turner993a8d02002-05-18 12:03:43 +00001363
1364 case BDF_INTEGER:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001365 fp->value.l = _bdf_atol( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001366 break;
1367
1368 case BDF_CARDINAL:
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001369 fp->value.ul = _bdf_atoul( value, 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001370 break;
David Turner993a8d02002-05-18 12:03:43 +00001371 }
1372
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001373 /* If the property happens to be a comment, then it doesn't need */
1374 /* to be added to the internal hash table. */
Werner Lemberg370aea82010-06-08 08:37:11 +02001375 if ( ft_memcmp( name, "COMMENT", 7 ) != 0 )
1376 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001377 /* Add the property to the font property table. */
1378 error = hash_insert( fp->name,
suzuki toshiya704f4d72009-09-13 00:50:14 +09001379 font->props_used,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001380 (hashtable *)font->internal,
1381 memory );
1382 if ( error )
1383 goto Exit;
1384 }
David Turner993a8d02002-05-18 12:03:43 +00001385
1386 font->props_used++;
1387
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001388 /* Some special cases need to be handled here. The DEFAULT_CHAR */
1389 /* property needs to be located if it exists in the property list, the */
1390 /* FONT_ASCENT and FONT_DESCENT need to be assigned if they are */
1391 /* present, and the SPACING property should override the default */
1392 /* spacing. */
1393 if ( ft_memcmp( name, "DEFAULT_CHAR", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001394 font->default_char = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001395 else if ( ft_memcmp( name, "FONT_ASCENT", 11 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001396 font->font_ascent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001397 else if ( ft_memcmp( name, "FONT_DESCENT", 12 ) == 0 )
suzuki toshiyabe41d3e2009-08-01 00:30:22 +09001398 font->font_descent = fp->value.l;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001399 else if ( ft_memcmp( name, "SPACING", 7 ) == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001400 {
Werner Lembergb66efef2009-03-12 08:07:49 +00001401 if ( !fp->value.atom )
1402 {
1403 error = BDF_Err_Invalid_File_Format;
1404 goto Exit;
1405 }
1406
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001407 if ( fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P' )
David Turner993a8d02002-05-18 12:03:43 +00001408 font->spacing = BDF_PROPORTIONAL;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001409 else if ( fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M' )
David Turner993a8d02002-05-18 12:03:43 +00001410 font->spacing = BDF_MONOWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001411 else if ( fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C' )
David Turner993a8d02002-05-18 12:03:43 +00001412 font->spacing = BDF_CHARCELL;
1413 }
1414
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001415 Exit:
1416 return error;
David Turner993a8d02002-05-18 12:03:43 +00001417 }
1418
David Turner993a8d02002-05-18 12:03:43 +00001419
David Turnerb1b47622002-05-21 21:17:43 +00001420 static const unsigned char nibble_mask[8] =
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001421 {
1422 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE
1423 };
1424
1425
1426 /* Actually parse the glyph info and bitmaps. */
1427 static FT_Error
1428 _bdf_parse_glyphs( char* line,
1429 unsigned long linelen,
1430 unsigned long lineno,
1431 void* call_data,
1432 void* client_data )
1433 {
1434 int c, mask_index;
1435 char* s;
1436 unsigned char* bp;
1437 unsigned long i, slen, nibbles;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001438
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001439 _bdf_parse_t* p;
1440 bdf_glyph_t* glyph;
1441 bdf_font_t* font;
1442
1443 FT_Memory memory;
1444 FT_Error error = BDF_Err_Ok;
1445
Werner Lemberg319c00d2003-04-23 19:48:24 +00001446 FT_UNUSED( call_data );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001447 FT_UNUSED( lineno ); /* only used in debug mode */
1448
1449
Werner Lemberg319c00d2003-04-23 19:48:24 +00001450 p = (_bdf_parse_t *)client_data;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001451
1452 font = p->font;
1453 memory = font->memory;
1454
1455 /* Check for a comment. */
1456 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1457 {
1458 linelen -= 7;
1459
1460 s = line + 7;
1461 if ( *s != 0 )
1462 {
1463 s++;
1464 linelen--;
1465 }
1466 error = _bdf_add_comment( p->font, s, linelen );
1467 goto Exit;
1468 }
1469
1470 /* The very first thing expected is the number of glyphs. */
1471 if ( !( p->flags & _BDF_GLYPHS ) )
1472 {
1473 if ( ft_memcmp( line, "CHARS", 5 ) != 0 )
1474 {
1475 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "CHARS" ));
1476 error = BDF_Err_Missing_Chars_Field;
1477 goto Exit;
1478 }
1479
David Turner68df4f72005-03-15 18:18:57 +00001480 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001481 if ( error )
1482 goto Exit;
1483 p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
1484
1485 /* Make sure the number of glyphs is non-zero. */
1486 if ( p->cnt == 0 )
David Turner993a8d02002-05-18 12:03:43 +00001487 font->glyphs_size = 64;
1488
Werner Lemberga08b2172007-03-28 07:17:17 +00001489 /* Limit ourselves to 1,114,112 glyphs in the font (this is the */
1490 /* number of code points available in Unicode). */
1491 if ( p->cnt >= 1114112UL )
1492 {
1493 error = BDF_Err_Invalid_Argument;
1494 goto Exit;
1495 }
1496
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001497 if ( FT_NEW_ARRAY( font->glyphs, font->glyphs_size ) )
1498 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001499
David Turner993a8d02002-05-18 12:03:43 +00001500 p->flags |= _BDF_GLYPHS;
David Turner993a8d02002-05-18 12:03:43 +00001501
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001502 goto Exit;
1503 }
1504
1505 /* Check for the ENDFONT field. */
1506 if ( ft_memcmp( line, "ENDFONT", 7 ) == 0 )
1507 {
1508 /* Sort the glyphs by encoding. */
1509 ft_qsort( (char *)font->glyphs,
1510 font->glyphs_used,
1511 sizeof ( bdf_glyph_t ),
1512 by_encoding );
David Turner993a8d02002-05-18 12:03:43 +00001513
1514 p->flags &= ~_BDF_START;
David Turner993a8d02002-05-18 12:03:43 +00001515
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001516 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001517 }
1518
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001519 /* Check for the ENDCHAR field. */
1520 if ( ft_memcmp( line, "ENDCHAR", 7 ) == 0 )
1521 {
1522 p->glyph_enc = 0;
1523 p->flags &= ~_BDF_GLYPH_BITS;
1524
1525 goto Exit;
1526 }
1527
1528 /* Check to see whether a glyph is being scanned but should be */
1529 /* ignored because it is an unencoded glyph. */
1530 if ( ( p->flags & _BDF_GLYPH ) &&
1531 p->glyph_enc == -1 &&
1532 p->opts->keep_unencoded == 0 )
1533 goto Exit;
1534
1535 /* Check for the STARTCHAR field. */
1536 if ( ft_memcmp( line, "STARTCHAR", 9 ) == 0 )
1537 {
1538 /* Set the character name in the parse info first until the */
1539 /* encoding can be checked for an unencoded character. */
1540 FT_FREE( p->glyph_name );
1541
David Turner68df4f72005-03-15 18:18:57 +00001542 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001543 if ( error )
1544 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001545
David Turner68df4f72005-03-15 18:18:57 +00001546 _bdf_list_shift( &p->list, 1 );
1547
1548 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001549
Werner Lembergba03af62007-05-30 13:57:02 +00001550 if ( !s )
1551 {
1552 error = BDF_Err_Invalid_File_Format;
1553 goto Exit;
1554 }
1555
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001556 if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
1557 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001558
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001559 FT_MEM_COPY( p->glyph_name, s, slen + 1 );
1560
1561 p->flags |= _BDF_GLYPH;
1562
1563 goto Exit;
1564 }
1565
1566 /* Check for the ENCODING field. */
1567 if ( ft_memcmp( line, "ENCODING", 8 ) == 0 )
1568 {
1569 if ( !( p->flags & _BDF_GLYPH ) )
1570 {
1571 /* Missing STARTCHAR field. */
1572 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "STARTCHAR" ));
1573 error = BDF_Err_Missing_Startchar_Field;
1574 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001575 }
1576
David Turner68df4f72005-03-15 18:18:57 +00001577 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001578 if ( error )
1579 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001580
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001581 p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001582
David Turner481838e2006-02-23 12:40:14 +00001583 /* Check that the encoding is in the range [0,65536] because */
1584 /* otherwise p->have (a bitmap with static size) overflows. */
Werner Lembergd4303da2006-02-23 21:01:34 +00001585 if ( (size_t)p->glyph_enc >= sizeof ( p->have ) * 8 )
David Turner481838e2006-02-23 12:40:14 +00001586 {
1587 error = BDF_Err_Invalid_File_Format;
1588 goto Exit;
1589 }
1590
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001591 /* Check to see whether this encoding has already been encountered. */
1592 /* If it has then change it to unencoded so it gets added if */
1593 /* indicated. */
1594 if ( p->glyph_enc >= 0 )
1595 {
1596 if ( _bdf_glyph_modified( p->have, p->glyph_enc ) )
1597 {
1598 /* Emit a message saying a glyph has been moved to the */
1599 /* unencoded area. */
1600 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG12,
1601 p->glyph_enc, p->glyph_name ));
1602 p->glyph_enc = -1;
1603 font->modified = 1;
1604 }
1605 else
1606 _bdf_set_glyph_modified( p->have, p->glyph_enc );
1607 }
1608
1609 if ( p->glyph_enc >= 0 )
1610 {
1611 /* Make sure there are enough glyphs allocated in case the */
1612 /* number of characters happen to be wrong. */
1613 if ( font->glyphs_used == font->glyphs_size )
1614 {
1615 if ( FT_RENEW_ARRAY( font->glyphs,
1616 font->glyphs_size,
1617 font->glyphs_size + 64 ) )
1618 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001619
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001620 font->glyphs_size += 64;
David Turner993a8d02002-05-18 12:03:43 +00001621 }
1622
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001623 glyph = font->glyphs + font->glyphs_used++;
1624 glyph->name = p->glyph_name;
1625 glyph->encoding = p->glyph_enc;
David Turner993a8d02002-05-18 12:03:43 +00001626
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001627 /* Reset the initial glyph info. */
1628 p->glyph_name = 0;
1629 }
1630 else
1631 {
1632 /* Unencoded glyph. Check to see whether it should */
1633 /* be added or not. */
1634 if ( p->opts->keep_unencoded != 0 )
1635 {
1636 /* Allocate the next unencoded glyph. */
1637 if ( font->unencoded_used == font->unencoded_size )
1638 {
David Turner68df4f72005-03-15 18:18:57 +00001639 if ( FT_RENEW_ARRAY( font->unencoded ,
1640 font->unencoded_size,
1641 font->unencoded_size + 4 ) )
1642 goto Exit;
1643
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001644 font->unencoded_size += 4;
1645 }
1646
1647 glyph = font->unencoded + font->unencoded_used;
1648 glyph->name = p->glyph_name;
1649 glyph->encoding = font->unencoded_used++;
1650 }
1651 else
1652 /* Free up the glyph name if the unencoded shouldn't be */
1653 /* kept. */
1654 FT_FREE( p->glyph_name );
1655
1656 p->glyph_name = 0;
1657 }
1658
1659 /* Clear the flags that might be added when width and height are */
1660 /* checked for consistency. */
1661 p->flags &= ~( _BDF_GLYPH_WIDTH_CHECK | _BDF_GLYPH_HEIGHT_CHECK );
1662
1663 p->flags |= _BDF_ENCODING;
1664
1665 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001666 }
1667
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001668 /* Point at the glyph being constructed. */
1669 if ( p->glyph_enc == -1 )
1670 glyph = font->unencoded + ( font->unencoded_used - 1 );
1671 else
1672 glyph = font->glyphs + ( font->glyphs_used - 1 );
David Turner993a8d02002-05-18 12:03:43 +00001673
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001674 /* Check to see whether a bitmap is being constructed. */
1675 if ( p->flags & _BDF_BITMAP )
1676 {
1677 /* If there are more rows than are specified in the glyph metrics, */
1678 /* ignore the remaining lines. */
David Turnerb1b47622002-05-21 21:17:43 +00001679 if ( p->row >= (unsigned long)glyph->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001680 {
1681 if ( !( p->flags & _BDF_GLYPH_HEIGHT_CHECK ) )
1682 {
1683 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG13, glyph->encoding ));
1684 p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
David Turner993a8d02002-05-18 12:03:43 +00001685 font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001686 }
1687
1688 goto Exit;
1689 }
1690
1691 /* Only collect the number of nibbles indicated by the glyph */
1692 /* metrics. If there are more columns, they are simply ignored. */
1693 nibbles = glyph->bpr << 1;
1694 bp = glyph->bitmap + p->row * glyph->bpr;
1695
David Turnerb698eed2006-02-23 14:50:13 +00001696 for ( i = 0; i < nibbles; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001697 {
1698 c = line[i];
Werner Lemberg233302a2002-05-22 05:41:06 +00001699 *bp = (FT_Byte)( ( *bp << 4 ) + a2i[c] );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001700 if ( i + 1 < nibbles && ( i & 1 ) )
1701 *++bp = 0;
1702 }
1703
1704 /* Remove possible garbage at the right. */
1705 mask_index = ( glyph->bbx.width * p->font->bpp ) & 7;
David Turner6cda6c02006-02-23 12:37:18 +00001706 if ( glyph->bbx.width )
1707 *bp &= nibble_mask[mask_index];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001708
1709 /* If any line has extra columns, indicate they have been removed. */
1710 if ( ( line[nibbles] == '0' || a2i[(int)line[nibbles]] != 0 ) &&
1711 !( p->flags & _BDF_GLYPH_WIDTH_CHECK ) )
1712 {
1713 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG14, glyph->encoding ));
1714 p->flags |= _BDF_GLYPH_WIDTH_CHECK;
1715 font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001716 }
1717
1718 p->row++;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001719 goto Exit;
1720 }
David Turner993a8d02002-05-18 12:03:43 +00001721
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001722 /* Expect the SWIDTH (scalable width) field next. */
1723 if ( ft_memcmp( line, "SWIDTH", 6 ) == 0 )
1724 {
1725 if ( !( p->flags & _BDF_ENCODING ) )
1726 {
1727 /* Missing ENCODING field. */
1728 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "ENCODING" ));
1729 error = BDF_Err_Missing_Encoding_Field;
1730 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001731 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001732
David Turner68df4f72005-03-15 18:18:57 +00001733 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001734 if ( error )
1735 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001736
David Turnerb1b47622002-05-21 21:17:43 +00001737 glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
David Turner993a8d02002-05-18 12:03:43 +00001738 p->flags |= _BDF_SWIDTH;
David Turner993a8d02002-05-18 12:03:43 +00001739
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001740 goto Exit;
1741 }
David Turner993a8d02002-05-18 12:03:43 +00001742
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001743 /* Expect the DWIDTH (scalable width) field next. */
1744 if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
1745 {
David Turner68df4f72005-03-15 18:18:57 +00001746 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001747 if ( error )
1748 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00001749
David Turnerb1b47622002-05-21 21:17:43 +00001750 glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001751
1752 if ( !( p->flags & _BDF_SWIDTH ) )
1753 {
1754 /* Missing SWIDTH field. Emit an auto correction message and set */
1755 /* the scalable width from the device width. */
1756 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG9, lineno ));
1757
Werner Lemberg02d4d592002-05-28 22:38:05 +00001758 glyph->swidth = (unsigned short)FT_MulDiv(
1759 glyph->dwidth, 72000L,
1760 (FT_Long)( font->point_size *
1761 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001762 }
1763
1764 p->flags |= _BDF_DWIDTH;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001765 goto Exit;
1766 }
David Turner993a8d02002-05-18 12:03:43 +00001767
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001768 /* Expect the BBX field next. */
1769 if ( ft_memcmp( line, "BBX", 3 ) == 0 )
1770 {
David Turner68df4f72005-03-15 18:18:57 +00001771 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001772 if ( error )
1773 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001774
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001775 glyph->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
1776 glyph->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
1777 glyph->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
1778 glyph->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
1779
1780 /* Generate the ascent and descent of the character. */
Werner Lemberg233302a2002-05-22 05:41:06 +00001781 glyph->bbx.ascent = (short)( glyph->bbx.height + glyph->bbx.y_offset );
1782 glyph->bbx.descent = (short)( -glyph->bbx.y_offset );
David Turner993a8d02002-05-18 12:03:43 +00001783
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001784 /* Determine the overall font bounding box as the characters are */
1785 /* loaded so corrections can be done later if indicated. */
Werner Lembergdfa46192004-03-05 09:26:24 +00001786 p->maxas = (short)FT_MAX( glyph->bbx.ascent, p->maxas );
1787 p->maxds = (short)FT_MAX( glyph->bbx.descent, p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001788
David Turnerb1b47622002-05-21 21:17:43 +00001789 p->rbearing = (short)( glyph->bbx.width + glyph->bbx.x_offset );
David Turner993a8d02002-05-18 12:03:43 +00001790
Werner Lembergdfa46192004-03-05 09:26:24 +00001791 p->maxrb = (short)FT_MAX( p->rbearing, p->maxrb );
1792 p->minlb = (short)FT_MIN( glyph->bbx.x_offset, p->minlb );
1793 p->maxlb = (short)FT_MAX( glyph->bbx.x_offset, p->maxlb );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001794
1795 if ( !( p->flags & _BDF_DWIDTH ) )
1796 {
1797 /* Missing DWIDTH field. Emit an auto correction message and set */
1798 /* the device width to the glyph width. */
1799 FT_TRACE2(( "_bdf_parse_glyphs: " ACMSG10, lineno ));
1800 glyph->dwidth = glyph->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00001801 }
1802
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001803 /* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH */
1804 /* value if necessary. */
1805 if ( p->opts->correct_metrics != 0 )
1806 {
1807 /* Determine the point size of the glyph. */
Werner Lemberg02d4d592002-05-28 22:38:05 +00001808 unsigned short sw = (unsigned short)FT_MulDiv(
1809 glyph->dwidth, 72000L,
1810 (FT_Long)( font->point_size *
1811 font->resolution_x ) );
David Turner993a8d02002-05-18 12:03:43 +00001812
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001813
1814 if ( sw != glyph->swidth )
1815 {
1816 glyph->swidth = sw;
1817
1818 if ( p->glyph_enc == -1 )
1819 _bdf_set_glyph_modified( font->umod,
1820 font->unencoded_used - 1 );
1821 else
1822 _bdf_set_glyph_modified( font->nmod, glyph->encoding );
1823
1824 p->flags |= _BDF_SWIDTH_ADJ;
1825 font->modified = 1;
1826 }
David Turner993a8d02002-05-18 12:03:43 +00001827 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001828
David Turner993a8d02002-05-18 12:03:43 +00001829 p->flags |= _BDF_BBX;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001830 goto Exit;
1831 }
David Turner993a8d02002-05-18 12:03:43 +00001832
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001833 /* And finally, gather up the bitmap. */
1834 if ( ft_memcmp( line, "BITMAP", 6 ) == 0 )
1835 {
Werner Lemberg26170df2006-03-26 07:19:07 +00001836 unsigned long bitmap_size;
1837
1838
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001839 if ( !( p->flags & _BDF_BBX ) )
1840 {
1841 /* Missing BBX field. */
1842 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG1, lineno, "BBX" ));
1843 error = BDF_Err_Missing_Bbx_Field;
1844 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001845 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001846
1847 /* Allocate enough space for the bitmap. */
1848 glyph->bpr = ( glyph->bbx.width * p->font->bpp + 7 ) >> 3;
Werner Lemberg26170df2006-03-26 07:19:07 +00001849
1850 bitmap_size = glyph->bpr * glyph->bbx.height;
1851 if ( bitmap_size > 0xFFFFU )
1852 {
1853 FT_ERROR(( "_bdf_parse_glyphs: " ERRMSG4, lineno ));
1854 error = BDF_Err_Bbx_Too_Big;
1855 goto Exit;
1856 }
1857 else
1858 glyph->bytes = (unsigned short)bitmap_size;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001859
1860 if ( FT_NEW_ARRAY( glyph->bitmap, glyph->bytes ) )
1861 goto Exit;
1862
1863 p->row = 0;
David Turner993a8d02002-05-18 12:03:43 +00001864 p->flags |= _BDF_BITMAP;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001865
1866 goto Exit;
1867 }
1868
1869 error = BDF_Err_Invalid_File_Format;
1870
1871 Exit:
Werner Lembergf4c94d42010-06-19 16:08:31 +02001872 if ( error && ( p->flags & _BDF_GLYPH ) )
1873 FT_FREE( p->glyph_name );
1874
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001875 return error;
David Turner993a8d02002-05-18 12:03:43 +00001876 }
1877
David Turner993a8d02002-05-18 12:03:43 +00001878
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001879 /* Load the font properties. */
1880 static FT_Error
1881 _bdf_parse_properties( char* line,
1882 unsigned long linelen,
1883 unsigned long lineno,
1884 void* call_data,
1885 void* client_data )
1886 {
1887 unsigned long vlen;
1888 _bdf_line_func_t* next;
1889 _bdf_parse_t* p;
1890 char* name;
1891 char* value;
1892 char nbuf[128];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001893 FT_Error error = BDF_Err_Ok;
David Turner993a8d02002-05-18 12:03:43 +00001894
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001895 FT_UNUSED( lineno );
David Turner993a8d02002-05-18 12:03:43 +00001896
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001897
1898 next = (_bdf_line_func_t *)call_data;
1899 p = (_bdf_parse_t *) client_data;
1900
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001901 /* Check for the end of the properties. */
1902 if ( ft_memcmp( line, "ENDPROPERTIES", 13 ) == 0 )
1903 {
1904 /* If the FONT_ASCENT or FONT_DESCENT properties have not been */
1905 /* encountered yet, then make sure they are added as properties and */
1906 /* make sure they are set from the font bounding box info. */
1907 /* */
1908 /* This is *always* done regardless of the options, because X11 */
1909 /* requires these two fields to compile fonts. */
Werner Lemberg428c2e42003-04-25 05:35:04 +00001910 if ( bdf_get_font_property( p->font, "FONT_ASCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001911 {
1912 p->font->font_ascent = p->font->bbx.ascent;
1913 ft_sprintf( nbuf, "%hd", p->font->bbx.ascent );
1914 error = _bdf_add_property( p->font, (char *)"FONT_ASCENT", nbuf );
1915 if ( error )
1916 goto Exit;
1917
1918 FT_TRACE2(( "_bdf_parse_properties: " ACMSG1, p->font->bbx.ascent ));
1919 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001920 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001921
Werner Lemberg428c2e42003-04-25 05:35:04 +00001922 if ( bdf_get_font_property( p->font, "FONT_DESCENT" ) == 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001923 {
1924 p->font->font_descent = p->font->bbx.descent;
1925 ft_sprintf( nbuf, "%hd", p->font->bbx.descent );
1926 error = _bdf_add_property( p->font, (char *)"FONT_DESCENT", nbuf );
1927 if ( error )
1928 goto Exit;
1929
1930 FT_TRACE2(( "_bdf_parse_properties: " ACMSG2, p->font->bbx.descent ));
1931 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00001932 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001933
David Turner993a8d02002-05-18 12:03:43 +00001934 p->flags &= ~_BDF_PROPS;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001935 *next = _bdf_parse_glyphs;
David Turner993a8d02002-05-18 12:03:43 +00001936
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001937 goto Exit;
1938 }
David Turner993a8d02002-05-18 12:03:43 +00001939
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001940 /* Ignore the _XFREE86_GLYPH_RANGES properties. */
1941 if ( ft_memcmp( line, "_XFREE86_GLYPH_RANGES", 21 ) == 0 )
1942 goto Exit;
1943
1944 /* Handle COMMENT fields and properties in a special way to preserve */
1945 /* the spacing. */
1946 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
1947 {
David Turner993a8d02002-05-18 12:03:43 +00001948 name = value = line;
1949 value += 7;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001950 if ( *value )
David Turner993a8d02002-05-18 12:03:43 +00001951 *value++ = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001952 error = _bdf_add_property( p->font, name, value );
1953 if ( error )
1954 goto Exit;
1955 }
1956 else if ( _bdf_is_atom( line, linelen, &name, &value, p->font ) )
1957 {
1958 error = _bdf_add_property( p->font, name, value );
1959 if ( error )
1960 goto Exit;
1961 }
1962 else
1963 {
David Turner68df4f72005-03-15 18:18:57 +00001964 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001965 if ( error )
1966 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00001967 name = p->list.field[0];
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001968
David Turner68df4f72005-03-15 18:18:57 +00001969 _bdf_list_shift( &p->list, 1 );
1970 value = _bdf_list_join( &p->list, ' ', &vlen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001971
1972 error = _bdf_add_property( p->font, name, value );
1973 if ( error )
1974 goto Exit;
1975 }
1976
1977 Exit:
1978 return error;
David Turner993a8d02002-05-18 12:03:43 +00001979 }
1980
David Turner993a8d02002-05-18 12:03:43 +00001981
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001982 /* Load the font header. */
1983 static FT_Error
1984 _bdf_parse_start( char* line,
1985 unsigned long linelen,
1986 unsigned long lineno,
1987 void* call_data,
1988 void* client_data )
1989 {
1990 unsigned long slen;
1991 _bdf_line_func_t* next;
1992 _bdf_parse_t* p;
1993 bdf_font_t* font;
1994 char *s;
David Turner993a8d02002-05-18 12:03:43 +00001995
David Turnerd490e372002-05-28 23:40:37 +00001996 FT_Memory memory = NULL;
1997 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00001998
1999 FT_UNUSED( lineno ); /* only used in debug mode */
2000
2001
2002 next = (_bdf_line_func_t *)call_data;
2003 p = (_bdf_parse_t *) client_data;
2004
2005 if ( p->font )
David Turner993a8d02002-05-18 12:03:43 +00002006 memory = p->font->memory;
2007
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002008 /* Check for a comment. This is done to handle those fonts that have */
2009 /* comments before the STARTFONT line for some reason. */
2010 if ( ft_memcmp( line, "COMMENT", 7 ) == 0 )
2011 {
2012 if ( p->opts->keep_comments != 0 && p->font != 0 )
2013 {
2014 linelen -= 7;
2015
2016 s = line + 7;
2017 if ( *s != 0 )
2018 {
2019 s++;
2020 linelen--;
David Turner993a8d02002-05-18 12:03:43 +00002021 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002022
2023 error = _bdf_add_comment( p->font, s, linelen );
2024 if ( error )
2025 goto Exit;
2026 /* here font is not defined! */
2027 }
2028
2029 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002030 }
2031
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002032 if ( !( p->flags & _BDF_START ) )
2033 {
2034 memory = p->memory;
David Turner993a8d02002-05-18 12:03:43 +00002035
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002036 if ( ft_memcmp( line, "STARTFONT", 9 ) != 0 )
2037 {
2038 /* No STARTFONT field is a good indication of a problem. */
2039 error = BDF_Err_Missing_Startfont_Field;
2040 goto Exit;
2041 }
David Turner993a8d02002-05-18 12:03:43 +00002042
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002043 p->flags = _BDF_START;
2044 font = p->font = 0;
David Turner993a8d02002-05-18 12:03:43 +00002045
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002046 if ( FT_NEW( font ) )
2047 goto Exit;
2048 p->font = font;
David Turner993a8d02002-05-18 12:03:43 +00002049
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002050 font->memory = p->memory;
2051 p->memory = 0;
David Turner993a8d02002-05-18 12:03:43 +00002052
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002053 { /* setup */
suzuki toshiya704f4d72009-09-13 00:50:14 +09002054 size_t i;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002055 bdf_property_t* prop;
David Turner993a8d02002-05-18 12:03:43 +00002056
David Turner993a8d02002-05-18 12:03:43 +00002057
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002058 error = hash_init( &(font->proptbl), memory );
2059 if ( error )
2060 goto Exit;
Werner Lemberg233302a2002-05-22 05:41:06 +00002061 for ( i = 0, prop = (bdf_property_t*)_bdf_properties;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002062 i < _num_bdf_properties; i++, prop++ )
2063 {
suzuki toshiya704f4d72009-09-13 00:50:14 +09002064 error = hash_insert( prop->name, i,
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002065 &(font->proptbl), memory );
2066 if ( error )
2067 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002068 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002069 }
2070
2071 if ( FT_ALLOC( p->font->internal, sizeof ( hashtable ) ) )
2072 goto Exit;
2073 error = hash_init( (hashtable *)p->font->internal,memory );
2074 if ( error )
2075 goto Exit;
Werner Lemberg8ef41832004-06-22 12:28:17 +00002076 p->font->spacing = p->opts->font_spacing;
2077 p->font->default_char = -1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002078
2079 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002080 }
2081
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002082 /* Check for the start of the properties. */
2083 if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
2084 {
David Turner68df4f72005-03-15 18:18:57 +00002085 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002086 if ( error )
2087 goto Exit;
Werner Lembergb66efef2009-03-12 08:07:49 +00002088 /* at this point, `p->font' can't be NULL */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002089 p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
2090
2091 if ( FT_NEW_ARRAY( p->font->props, p->cnt ) )
2092 goto Exit;
2093
2094 p->flags |= _BDF_PROPS;
2095 *next = _bdf_parse_properties;
2096
2097 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002098 }
2099
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002100 /* Check for the FONTBOUNDINGBOX field. */
2101 if ( ft_memcmp( line, "FONTBOUNDINGBOX", 15 ) == 0 )
2102 {
2103 if ( !(p->flags & _BDF_SIZE ) )
2104 {
2105 /* Missing the SIZE field. */
2106 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "SIZE" ));
2107 error = BDF_Err_Missing_Size_Field;
2108 goto Exit;
2109 }
2110
David Turner68df4f72005-03-15 18:18:57 +00002111 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002112 if ( error )
2113 goto Exit;
2114
2115 p->font->bbx.width = _bdf_atos( p->list.field[1], 0, 10 );
2116 p->font->bbx.height = _bdf_atos( p->list.field[2], 0, 10 );
2117
2118 p->font->bbx.x_offset = _bdf_atos( p->list.field[3], 0, 10 );
2119 p->font->bbx.y_offset = _bdf_atos( p->list.field[4], 0, 10 );
2120
David Turnerd490e372002-05-28 23:40:37 +00002121 p->font->bbx.ascent = (short)( p->font->bbx.height +
David Turnerb1b47622002-05-21 21:17:43 +00002122 p->font->bbx.y_offset );
2123
2124 p->font->bbx.descent = (short)( -p->font->bbx.y_offset );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002125
2126 p->flags |= _BDF_FONT_BBX;
2127
2128 goto Exit;
2129 }
2130
2131 /* The next thing to check for is the FONT field. */
2132 if ( ft_memcmp( line, "FONT", 4 ) == 0 )
2133 {
David Turner68df4f72005-03-15 18:18:57 +00002134 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002135 if ( error )
2136 goto Exit;
David Turner68df4f72005-03-15 18:18:57 +00002137 _bdf_list_shift( &p->list, 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002138
David Turner68df4f72005-03-15 18:18:57 +00002139 s = _bdf_list_join( &p->list, ' ', &slen );
Werner Lemberg5b591e42007-06-01 22:16:43 +00002140
2141 if ( !s )
2142 {
2143 error = BDF_Err_Invalid_File_Format;
2144 goto Exit;
2145 }
2146
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002147 if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
2148 goto Exit;
2149 FT_MEM_COPY( p->font->name, s, slen + 1 );
2150
2151 /* If the font name is an XLFD name, set the spacing to the one in */
2152 /* the font name. If there is no spacing fall back on the default. */
2153 error = _bdf_set_default_spacing( p->font, p->opts );
2154 if ( error )
2155 goto Exit;
2156
2157 p->flags |= _BDF_FONT_NAME;
2158
2159 goto Exit;
2160 }
2161
2162 /* Check for the SIZE field. */
2163 if ( ft_memcmp( line, "SIZE", 4 ) == 0 )
2164 {
2165 if ( !( p->flags & _BDF_FONT_NAME ) )
2166 {
2167 /* Missing the FONT field. */
2168 FT_ERROR(( "_bdf_parse_start: " ERRMSG1, lineno, "FONT" ));
2169 error = BDF_Err_Missing_Font_Field;
2170 goto Exit;
2171 }
2172
David Turner68df4f72005-03-15 18:18:57 +00002173 error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002174 if ( error )
2175 goto Exit;
2176
2177 p->font->point_size = _bdf_atoul( p->list.field[1], 0, 10 );
2178 p->font->resolution_x = _bdf_atoul( p->list.field[2], 0, 10 );
2179 p->font->resolution_y = _bdf_atoul( p->list.field[3], 0, 10 );
2180
2181 /* Check for the bits per pixel field. */
2182 if ( p->list.used == 5 )
2183 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002184 unsigned short bitcount, i, shift;
2185
2186
2187 p->font->bpp = (unsigned short)_bdf_atos( p->list.field[4], 0, 10 );
2188
2189 /* Only values 1, 2, 4, 8 are allowed. */
2190 shift = p->font->bpp;
2191 bitcount = 0;
2192 for ( i = 0; shift > 0; i++ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002193 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002194 if ( shift & 1 )
2195 bitcount = i;
2196 shift >>= 1;
David Turner993a8d02002-05-18 12:03:43 +00002197 }
David Turner993a8d02002-05-18 12:03:43 +00002198
Werner Lembergbd8e3242002-06-12 08:43:58 +00002199 shift = (short)( ( bitcount > 3 ) ? 8 : ( 1 << bitcount ) );
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002200
2201 if ( p->font->bpp > shift || p->font->bpp != shift )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002202 {
Werner Lemberg5a1fae12002-06-03 20:01:23 +00002203 /* select next higher value */
Werner Lembergbd8e3242002-06-12 08:43:58 +00002204 p->font->bpp = (unsigned short)( shift << 1 );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002205 FT_TRACE2(( "_bdf_parse_start: " ACMSG11, p->font->bpp ));
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002206 }
2207 }
2208 else
2209 p->font->bpp = 1;
David Turner993a8d02002-05-18 12:03:43 +00002210
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002211 p->flags |= _BDF_SIZE;
2212
2213 goto Exit;
David Turner993a8d02002-05-18 12:03:43 +00002214 }
2215
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002216 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002217
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002218 Exit:
2219 return error;
2220 }
David Turner993a8d02002-05-18 12:03:43 +00002221
2222
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002223 /*************************************************************************/
2224 /* */
2225 /* API. */
2226 /* */
2227 /*************************************************************************/
David Turner993a8d02002-05-18 12:03:43 +00002228
David Turner993a8d02002-05-18 12:03:43 +00002229
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002230 FT_LOCAL_DEF( FT_Error )
2231 bdf_load_font( FT_Stream stream,
2232 FT_Memory extmemory,
2233 bdf_options_t* opts,
2234 bdf_font_t* *font )
2235 {
Jens Claudiusa787f452006-08-27 11:26:18 +00002236 unsigned long lineno = 0; /* make compiler happy */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002237 _bdf_parse_t *p;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002238
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002239 FT_Memory memory = extmemory;
David Turnerd490e372002-05-28 23:40:37 +00002240 FT_Error error = BDF_Err_Ok;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002241
2242
David Turner68df4f72005-03-15 18:18:57 +00002243 if ( FT_NEW( p ) )
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002244 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002245
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002246 memory = NULL;
2247 p->opts = (bdf_options_t*)( ( opts != 0 ) ? opts : &_bdf_opts );
2248 p->minlb = 32767;
2249 p->memory = extmemory; /* only during font creation */
David Turner993a8d02002-05-18 12:03:43 +00002250
David Turner68df4f72005-03-15 18:18:57 +00002251 _bdf_list_init( &p->list, extmemory );
2252
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002253 error = _bdf_readstream( stream, _bdf_parse_start,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002254 (void *)p, &lineno );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002255 if ( error )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002256 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002257
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002258 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002259 {
2260 /* If the font is not proportional, set the font's monowidth */
2261 /* field to the width of the font bounding box. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002262 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002263
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002264 if ( p->font->spacing != BDF_PROPORTIONAL )
2265 p->font->monowidth = p->font->bbx.width;
David Turner993a8d02002-05-18 12:03:43 +00002266
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002267 /* If the number of glyphs loaded is not that of the original count, */
2268 /* indicate the difference. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002269 if ( p->cnt != p->font->glyphs_used + p->font->unencoded_used )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002270 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002271 FT_TRACE2(( "bdf_load_font: " ACMSG15, p->cnt,
2272 p->font->glyphs_used + p->font->unencoded_used ));
2273 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002274 }
2275
2276 /* Once the font has been loaded, adjust the overall font metrics if */
2277 /* necessary. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002278 if ( p->opts->correct_metrics != 0 &&
2279 ( p->font->glyphs_used > 0 || p->font->unencoded_used > 0 ) )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002280 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002281 if ( p->maxrb - p->minlb != p->font->bbx.width )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002282 {
2283 FT_TRACE2(( "bdf_load_font: " ACMSG3,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002284 p->font->bbx.width, p->maxrb - p->minlb ));
2285 p->font->bbx.width = (unsigned short)( p->maxrb - p->minlb );
2286 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002287 }
2288
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002289 if ( p->font->bbx.x_offset != p->minlb )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002290 {
2291 FT_TRACE2(( "bdf_load_font: " ACMSG4,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002292 p->font->bbx.x_offset, p->minlb ));
2293 p->font->bbx.x_offset = p->minlb;
2294 p->font->modified = 1;
David Turner993a8d02002-05-18 12:03:43 +00002295 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002296
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002297 if ( p->font->bbx.ascent != p->maxas )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002298 {
2299 FT_TRACE2(( "bdf_load_font: " ACMSG5,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002300 p->font->bbx.ascent, p->maxas ));
2301 p->font->bbx.ascent = p->maxas;
2302 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002303 }
2304
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002305 if ( p->font->bbx.descent != p->maxds )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002306 {
2307 FT_TRACE2(( "bdf_load_font: " ACMSG6,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002308 p->font->bbx.descent, p->maxds ));
2309 p->font->bbx.descent = p->maxds;
2310 p->font->bbx.y_offset = (short)( -p->maxds );
2311 p->font->modified = 1;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002312 }
2313
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002314 if ( p->maxas + p->maxds != p->font->bbx.height )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002315 {
2316 FT_TRACE2(( "bdf_load_font: " ACMSG7,
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002317 p->font->bbx.height, p->maxas + p->maxds ));
2318 p->font->bbx.height = (unsigned short)( p->maxas + p->maxds );
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002319 }
2320
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002321 if ( p->flags & _BDF_SWIDTH_ADJ )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002322 FT_TRACE2(( "bdf_load_font: " ACMSG8 ));
2323 }
David Turner993a8d02002-05-18 12:03:43 +00002324 }
2325
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002326 if ( p->flags & _BDF_START )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002327 {
2328 {
2329 /* The ENDFONT field was never reached or did not exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002330 if ( !( p->flags & _BDF_GLYPHS ) )
Werner Lemberg5b591e42007-06-01 22:16:43 +00002331 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002332 /* Error happened while parsing header. */
2333 FT_ERROR(( "bdf_load_font: " ERRMSG2, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002334 error = BDF_Err_Corrupted_Font_Header;
2335 goto Exit;
2336 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002337 else
Werner Lemberg5b591e42007-06-01 22:16:43 +00002338 {
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002339 /* Error happened when parsing glyphs. */
2340 FT_ERROR(( "bdf_load_font: " ERRMSG3, lineno ));
Werner Lemberg5b591e42007-06-01 22:16:43 +00002341 error = BDF_Err_Corrupted_Font_Glyphs;
2342 goto Exit;
2343 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002344 }
David Turner993a8d02002-05-18 12:03:43 +00002345 }
2346
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002347 if ( p->font != 0 )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002348 {
2349 /* Make sure the comments are NULL terminated if they exist. */
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002350 memory = p->font->memory;
David Turner993a8d02002-05-18 12:03:43 +00002351
Werner Lemberg370aea82010-06-08 08:37:11 +02002352 if ( p->font->comments_len > 0 )
2353 {
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002354 if ( FT_RENEW_ARRAY( p->font->comments,
2355 p->font->comments_len,
2356 p->font->comments_len + 1 ) )
Werner Lembergb10e45a2006-06-08 07:32:56 +00002357 goto Fail;
David Turner993a8d02002-05-18 12:03:43 +00002358
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002359 p->font->comments[p->font->comments_len] = 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002360 }
David Turner993a8d02002-05-18 12:03:43 +00002361 }
Werner Lemberg7925edc2002-05-30 19:29:41 +00002362 else if ( error == BDF_Err_Ok )
2363 error = BDF_Err_Invalid_File_Format;
David Turner993a8d02002-05-18 12:03:43 +00002364
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002365 *font = p->font;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002366
2367 Exit:
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002368 if ( p )
2369 {
David Turner68df4f72005-03-15 18:18:57 +00002370 _bdf_list_done( &p->list );
2371
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002372 memory = extmemory;
David Turner68df4f72005-03-15 18:18:57 +00002373
Werner Lemberg90e3dd62002-10-02 17:04:58 +00002374 FT_FREE( p );
2375 }
2376
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002377 return error;
Werner Lembergb10e45a2006-06-08 07:32:56 +00002378
2379 Fail:
2380 bdf_free_font( p->font );
2381
2382 memory = extmemory;
2383
2384 FT_FREE( p->font );
2385
2386 goto Exit;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002387 }
David Turner993a8d02002-05-18 12:03:43 +00002388
2389
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002390 FT_LOCAL_DEF( void )
2391 bdf_free_font( bdf_font_t* font )
2392 {
2393 bdf_property_t* prop;
2394 unsigned long i;
2395 bdf_glyph_t* glyphs;
2396 FT_Memory memory;
David Turner993a8d02002-05-18 12:03:43 +00002397
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002398
2399 if ( font == 0 )
2400 return;
David Turner993a8d02002-05-18 12:03:43 +00002401
2402 memory = font->memory;
2403
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002404 FT_FREE( font->name );
David Turner993a8d02002-05-18 12:03:43 +00002405
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002406 /* Free up the internal hash table of property names. */
2407 if ( font->internal )
2408 {
2409 hash_free( (hashtable *)font->internal, memory );
2410 FT_FREE( font->internal );
David Turner993a8d02002-05-18 12:03:43 +00002411 }
2412
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002413 /* Free up the comment info. */
2414 FT_FREE( font->comments );
David Turner993a8d02002-05-18 12:03:43 +00002415
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002416 /* Free up the properties. */
2417 for ( i = 0; i < font->props_size; i++ )
2418 {
2419 if ( font->props[i].format == BDF_ATOM )
2420 FT_FREE( font->props[i].value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002421 }
2422
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002423 FT_FREE( font->props );
2424
2425 /* Free up the character info. */
2426 for ( i = 0, glyphs = font->glyphs;
2427 i < font->glyphs_used; i++, glyphs++ )
2428 {
2429 FT_FREE( glyphs->name );
2430 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002431 }
2432
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002433 for ( i = 0, glyphs = font->unencoded; i < font->unencoded_used;
2434 i++, glyphs++ )
2435 {
2436 FT_FREE( glyphs->name );
2437 FT_FREE( glyphs->bitmap );
David Turner993a8d02002-05-18 12:03:43 +00002438 }
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002439
2440 FT_FREE( font->glyphs );
2441 FT_FREE( font->unencoded );
2442
2443 /* Free up the overflow storage if it was used. */
2444 for ( i = 0, glyphs = font->overflow.glyphs;
2445 i < font->overflow.glyphs_used; i++, glyphs++ )
2446 {
2447 FT_FREE( glyphs->name );
2448 FT_FREE( glyphs->bitmap );
2449 }
2450
2451 FT_FREE( font->overflow.glyphs );
David Turner993a8d02002-05-18 12:03:43 +00002452
2453 /* bdf_cleanup */
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002454 hash_free( &(font->proptbl), memory );
David Turner993a8d02002-05-18 12:03:43 +00002455
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002456 /* Free up the user defined properties. */
2457 for (prop = font->user_props, i = 0;
2458 i < font->nuser_props; i++, prop++ )
2459 {
2460 FT_FREE( prop->name );
2461 if ( prop->format == BDF_ATOM )
2462 FT_FREE( prop->value.atom );
David Turner993a8d02002-05-18 12:03:43 +00002463 }
David Turner993a8d02002-05-18 12:03:43 +00002464
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002465 FT_FREE( font->user_props );
2466
2467 /* FREE( font ); */ /* XXX Fixme */
2468 }
David Turner993a8d02002-05-18 12:03:43 +00002469
2470
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002471 FT_LOCAL_DEF( bdf_property_t * )
2472 bdf_get_font_property( bdf_font_t* font,
Werner Lemberg428c2e42003-04-25 05:35:04 +00002473 const char* name )
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002474 {
2475 hashnode hn;
David Turner993a8d02002-05-18 12:03:43 +00002476
David Turner993a8d02002-05-18 12:03:43 +00002477
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002478 if ( font == 0 || font->props_size == 0 || name == 0 || *name == 0 )
David Turner993a8d02002-05-18 12:03:43 +00002479 return 0;
2480
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002481 hn = hash_lookup( name, (hashtable *)font->internal );
2482
suzuki toshiya704f4d72009-09-13 00:50:14 +09002483 return hn ? ( font->props + hn->data ) : 0;
Werner Lemberg7cf4d372002-05-21 14:13:01 +00002484 }
2485
2486
2487/* END */