Al-Qurtas-Islamic-bank-The-.../src/bdf/bdflib.c

2466 lines
65 KiB
C
Raw Normal View History

2002-05-18 14:03:43 +02:00
/*
* Copyright 2000 Computing Research Labs, New Mexico State University
* Copyright 2001 Francesco Zappa Nardelli
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
static char rcsid[] = "$Id$";
*/
#include <ft2build.h>
#include FT_INTERNAL_DEBUG_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_OBJECTS_H
#include "bdf.h"
#include "bdferror.h"
#undef MAX
#define MAX(h, i) ((h) > (i) ? (h) : (i))
#undef MIN
#define MIN(l, o) ((l) < (o) ? (l) : (o))
/**************************************************************************
*
* Masks used for checking different bits per pixel cases.
*
**************************************************************************/
static const unsigned char onebpp[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
static const unsigned char twobpp[] = { 0xc0, 0x30, 0x0c, 0x03 };
static const unsigned char fourbpp[] = { 0xf0, 0x0f };
static const unsigned char eightbpp[] = { 0xff };
/**************************************************************************
*
* Default BDF font options.
*
**************************************************************************/
static const bdf_options_t _bdf_opts =
{
1, /* Hint TTF glyphs. */
1, /* Correct metrics. */
1, /* Preserve unencoded glyphs. */
1, /* Preserve comments. */
1, /* Pad character-cells. */
BDF_PROPORTIONAL, /* Default spacing. */
12, /* Default point size. */
0, /* Default horizontal resolution. */
0, /* Default vertical resolution. */
1, /* Bits per pixel. */
BDF_UNIX_EOL, /* Line separator. */
};
/**************************************************************************
*
* Builtin BDF font properties.
*
**************************************************************************/
/*
* List of most properties that might appear in a font. Doesn't include the
* RAW_* and AXIS_* properties in X11R6 polymorphic fonts.
*/
static const bdf_property_t _bdf_properties[] =
{
{"ADD_STYLE_NAME", BDF_ATOM, 1},
{"AVERAGE_WIDTH", BDF_INTEGER, 1},
{"AVG_CAPITAL_WIDTH", BDF_INTEGER, 1},
{"AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1},
{"CAP_HEIGHT", BDF_INTEGER, 1},
{"CHARSET_COLLECTIONS", BDF_ATOM, 1},
{"CHARSET_ENCODING", BDF_ATOM, 1},
{"CHARSET_REGISTRY", BDF_ATOM, 1},
{"COMMENT", BDF_ATOM, 1},
{"COPYRIGHT", BDF_ATOM, 1},
{"DEFAULT_CHAR", BDF_CARDINAL, 1},
{"DESTINATION", BDF_CARDINAL, 1},
{"DEVICE_FONT_NAME", BDF_ATOM, 1},
{"END_SPACE", BDF_INTEGER, 1},
{"FACE_NAME", BDF_ATOM, 1},
{"FAMILY_NAME", BDF_ATOM, 1},
{"FIGURE_WIDTH", BDF_INTEGER, 1},
{"FONT", BDF_ATOM, 1},
{"FONTNAME_REGISTRY", BDF_ATOM, 1},
{"FONT_ASCENT", BDF_INTEGER, 1},
{"FONT_DESCENT", BDF_INTEGER, 1},
{"FOUNDRY", BDF_ATOM, 1},
{"FULL_NAME", BDF_ATOM, 1},
{"ITALIC_ANGLE", BDF_INTEGER, 1},
{"MAX_SPACE", BDF_INTEGER, 1},
{"MIN_SPACE", BDF_INTEGER, 1},
{"NORM_SPACE", BDF_INTEGER, 1},
{"NOTICE", BDF_ATOM, 1},
{"PIXEL_SIZE", BDF_INTEGER, 1},
{"POINT_SIZE", BDF_INTEGER, 1},
{"QUAD_WIDTH", BDF_INTEGER, 1},
{"RAW_ASCENT", BDF_INTEGER, 1},
{"RAW_AVERAGE_WIDTH", BDF_INTEGER, 1},
{"RAW_AVG_CAPITAL_WIDTH", BDF_INTEGER, 1},
{"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER, 1},
{"RAW_CAP_HEIGHT", BDF_INTEGER, 1},
{"RAW_DESCENT", BDF_INTEGER, 1},
{"RAW_END_SPACE", BDF_INTEGER, 1},
{"RAW_FIGURE_WIDTH", BDF_INTEGER, 1},
{"RAW_MAX_SPACE", BDF_INTEGER, 1},
{"RAW_MIN_SPACE", BDF_INTEGER, 1},
{"RAW_NORM_SPACE", BDF_INTEGER, 1},
{"RAW_PIXEL_SIZE", BDF_INTEGER, 1},
{"RAW_POINT_SIZE", BDF_INTEGER, 1},
{"RAW_PIXELSIZE", BDF_INTEGER, 1},
{"RAW_POINTSIZE", BDF_INTEGER, 1},
{"RAW_QUAD_WIDTH", BDF_INTEGER, 1},
{"RAW_SMALL_CAP_SIZE", BDF_INTEGER, 1},
{"RAW_STRIKEOUT_ASCENT", BDF_INTEGER, 1},
{"RAW_STRIKEOUT_DESCENT", BDF_INTEGER, 1},
{"RAW_SUBSCRIPT_SIZE", BDF_INTEGER, 1},
{"RAW_SUBSCRIPT_X", BDF_INTEGER, 1},
{"RAW_SUBSCRIPT_Y", BDF_INTEGER, 1},
{"RAW_SUPERSCRIPT_SIZE", BDF_INTEGER, 1},
{"RAW_SUPERSCRIPT_X", BDF_INTEGER, 1},
{"RAW_SUPERSCRIPT_Y", BDF_INTEGER, 1},
{"RAW_UNDERLINE_POSITION", BDF_INTEGER, 1},
{"RAW_UNDERLINE_THICKNESS", BDF_INTEGER, 1},
{"RAW_X_HEIGHT", BDF_INTEGER, 1},
{"RELATIVE_SETWIDTH", BDF_CARDINAL, 1},
{"RELATIVE_WEIGHT", BDF_CARDINAL, 1},
{"RESOLUTION", BDF_INTEGER, 1},
{"RESOLUTION_X", BDF_CARDINAL, 1},
{"RESOLUTION_Y", BDF_CARDINAL, 1},
{"SETWIDTH_NAME", BDF_ATOM, 1},
{"SLANT", BDF_ATOM, 1},
{"SMALL_CAP_SIZE", BDF_INTEGER, 1},
{"SPACING", BDF_ATOM, 1},
{"STRIKEOUT_ASCENT", BDF_INTEGER, 1},
{"STRIKEOUT_DESCENT", BDF_INTEGER, 1},
{"SUBSCRIPT_SIZE", BDF_INTEGER, 1},
{"SUBSCRIPT_X", BDF_INTEGER, 1},
{"SUBSCRIPT_Y", BDF_INTEGER, 1},
{"SUPERSCRIPT_SIZE", BDF_INTEGER, 1},
{"SUPERSCRIPT_X", BDF_INTEGER, 1},
{"SUPERSCRIPT_Y", BDF_INTEGER, 1},
{"UNDERLINE_POSITION", BDF_INTEGER, 1},
{"UNDERLINE_THICKNESS", BDF_INTEGER, 1},
{"WEIGHT", BDF_CARDINAL, 1},
{"WEIGHT_NAME", BDF_ATOM, 1},
{"X_HEIGHT", BDF_INTEGER, 1},
{"_MULE_BASELINE_OFFSET", BDF_INTEGER, 1},
{"_MULE_RELATIVE_COMPOSE", BDF_INTEGER, 1},
};
static const FT_ULong _num_bdf_properties = FT_NUM_ELEMENT(_bdf_properties);
/*
* User defined properties.
*/
/*static bdf_property_t *user_props;
static unsigned long nuser_props = 0;*/
/**************************************************************************
*
* Hash table utilities for the properties.
*
**************************************************************************/
#define INITIAL_HT_SIZE 241
typedef void (*hash_free_func)(hashnode node);
static hashnode*
hash_bucket(char *key, hashtable *ht)
{
char* kp = key;
unsigned long res = 0;
hashnode* bp = ht->table, *ndp;
/*
* Mocklisp hash function.
*/
while (*kp)
res = (res << 5) - res + *kp++;
ndp = bp + (res % ht->size);
while (*ndp)
{
kp = (*ndp)->key;
if (kp[0] == key[0] && ft_strcmp(kp, key) == 0)
break;
ndp--;
if (ndp < bp)
ndp = bp + (ht->size - 1);
}
return ndp;
}
static FT_Error
hash_rehash ( hashtable* ht,
FT_Memory memory )
{
hashnode *obp = ht->table, *bp, *nbp;
int i, sz = ht->size;
FT_Error error;
ht->size <<= 1;
ht->limit = ht->size / 3;
if ( FT_NEW_ARRAY( ht->table , ht->size ) )
return error;
for (i = 0, bp = obp; i < sz; i++, bp++)
{
if (*bp)
{
nbp = hash_bucket((*bp)->key, ht);
*nbp = *bp;
}
}
FT_FREE(obp);
return FT_Err_Ok;
}
static FT_Error
hash_init ( hashtable* ht,
FT_Memory memory )
{
int sz = INITIAL_HT_SIZE;
FT_Error error;
ht->size = sz;
ht->limit = sz / 3;
ht->used = 0;
if ( FT_NEW_ARRAY( ht->table, size ) )
return error;
return FT_Err_Ok;
}
static void
hash_free( hashtable* ht,
FT_Memory memory )
{
/* FT_Error error; */
if ( ht != 0 )
{
int i, sz = ht->size;
hashnode* bp = ht->table;
for (i = 0; i < sz; i++, bp++)
{
if (*bp)
FT_FREE(*bp);
}
if (sz > 0)
FT_FREE(ht->table);
}
}
static FT_Error
hash_insert ( char* key,
void* data,
hashtable* ht,
FT_Memory memory )
{
FT_Error error = FT_Err_Ok;
hashnode nn, *bp = hash_bucket(key, ht);
nn = *bp;
if (!nn)
{
if ( FT_NEW( nn ) )
return error;
*bp = nn;
nn->key = key;
nn->data = data;
if (ht->used >= ht->limit)
error = hash_rehash(ht, memory);
ht->used++;
}
else
nn->data = data;
return error;
}
static hashnode
hash_lookup(char *key, hashtable *ht)
{
hashnode *np = hash_bucket(key, ht);
return *np;
}
#ifdef 0
static void
hash_delete(char *name, hashtable *ht , FT_Memory memory)
{
hashnode *hp;
/* FT_Error error; */
hp = hash_bucket(name, ht);
FT_FREE( *hp );
}
#endif
/*
* The builtin property table.
*/
/*static hashtable proptbl; */ /* XXX eliminate this */
/**************************************************************************
*
* Utility types and functions.
*
**************************************************************************/
/*
* Function type for parsing lines of a BDF font.
*/
typedef int (*_bdf_line_func_t)( char* line,
unsigned long linelen,
unsigned long lineno,
void* call_data,
void* client_data );
/*
* List structure for splitting lines into fields.
*/
typedef struct
{
char** field;
unsigned long size;
unsigned long used;
char* bfield;
unsigned long bsize;
unsigned long bused;
} _bdf_list_t;
/*
* Structure used while loading BDF fonts.
*/
typedef struct
{
unsigned long flags;
unsigned long cnt;
unsigned long row;
unsigned long bpr;
short minlb;
short maxlb;
short maxrb;
short maxas;
short maxds;
short rbearing;
char* glyph_name;
long glyph_enc;
bdf_font_t* font;
bdf_options_t* opts;
void* client_data;
bdf_callback_t callback;
bdf_callback_struct_t cb;
unsigned long have[2048];
_bdf_list_t list;
FT_Memory memory;
} _bdf_parse_t;
#define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7)))
#define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7)))
/*
* An empty string for empty fields.
*/
static const char empty[1] = { 0 }; /* XXX eliminate this */
/*
* Assume the line is NULL terminated and that the `list' parameter was
* initialized the first time it was used.
*/
static FT_Error
_bdf_split ( char* separators,
char* line,
unsigned long linelen,
_bdf_list_t* list,
FT_Memory memory )
{
int mult, final_empty;
char *sp, *ep, *end;
unsigned char seps[32];
FT_Error error;
/*
* Initialize the list.
*/
list->used = list->bused = 0;
/*
* If the line is empty, then simply return.
*/
if ( linelen == 0 || line[0] == 0 )
return FT_Err_Ok;
/*
* If the `separators' parameter is NULL or empty, split the list into
* individual bytes.
*/
if ( separators == 0 || *separators == 0 )
{
if ( linelen > list->bsize )
{
if ( list->bsize )
{
if ( FT_ALLOC ( list->bfield , linelen) )
return error;
}
else
{
if ( FT_REALLOC ( list->bfield , list->bsize, linelen) )
return error;
}
list->bsize = linelen;
}
list->bused = linelen;
FT_MEM_COPY (list->bfield, line, linelen);
return FT_Err_Ok;
}
/*
* Prepare the separator bitmap.
*/
FT_MEM_ZERO( seps, 32 );
/*
* If the very last character of the separator string is a plus, then set
* the `mult' flag to indicate that multiple separators should be
* collapsed into one.
*/
for ( mult = 0, sp = separators; sp && *sp; sp++ )
{
if ( sp[0] == '+' && sp[1] == 0)
mult = 1;
else
setsbit( seps, sp[0] );
}
/*
* Break the line up into fields.
*/
final_empty = 0;
sp = ep = line;
end = sp + linelen;
for ( ; sp < end && *sp;)
{
/*
* Collect everything that is not a separator.
*/
for ( ; *ep && !sbitset( seps, *ep ); ep++ ) ;
/*
* Resize the list if necessary.
*/
if ( list->used == list->size )
{
if ( list->size == 0 )
{
if ( FT_NEW_ARRAY( list->field , 5) )
return error;
}
else
{
if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 )
return error;
}
list->size += 5;
}
/*
* Assign the field appropriately.
*/
list->field[ list->used++ ] = (ep > sp) ? sp : empty;
sp = ep;
if (mult)
{
/*
* If multiple separators should be collapsed, do it now by
* setting all the separator characters to 0.
*/
for ( ; *ep && sbitset(seps, *ep); ep++ )
*ep = 0;
}
else if (*ep != 0)
{
/*
* Don't collapse multiple separators by making them 0, so just
* make the one encountered 0.
*/
*ep++ = 0;
}
final_empty = ( ep > sp && *ep == 0 );
sp = ep;
}
/*
* Finally, NULL terminate the list.
*/
if ( list->used + final_empty + 1 >= list->size )
{
if ( list->used == list->size )
{
if ( list->size == 0 )
{
if ( FT_NEW_ARRAY( list->field, 5 ) )
return error;
}
else
{
if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 ) )
return error;
}
list->size += 5;
}
}
if (final_empty)
list->field[ list->used++ ] = empty;
if ( list->used == list->size )
{
if ( list->size == 0 )
{
if ( FT_NEW_ARRAY( list->field , 5 ) )
return error;
}
else
{
if ( FT_NEW_ARRAY( list->field, list->size, list->size + 5 ) )
return error;
}
list->size += 5;
}
list->field[ list->used ] = 0;
return FT_Err_Ok;
}
static void
_bdf_shift( unsigned long n,
_bdf_list_t* list)
{
unsigned long i, u;
if ( list == 0 || list->used == 0 || n == 0 )
return;
if ( n >= list->used )
{
list->used = 0;
return;
}
for ( u = n, i = 0; u < list->used; i++, u++ )
list->field[i] = list->field[u];
list->used -= n;
}
static char*
_bdf_join( int c,
unsigned long* len,
_bdf_list_t* list)
{
unsigned long i, j;
char *fp, *dp;
if ( list == 0 || list->used == 0 )
return 0;
*len = 0;
dp = list->field[0];
for ( i = j = 0; i < list->used; i++ )
{
fp = list->field[i];
while (*fp)
dp[j++] = *fp++;
if (i + 1 < list->used)
dp[j++] = c;
}
dp[j] = 0;
*len = j;
return dp;
}
/*
* High speed file reader that passes each line to a callback.
*/
int ftreadstream( FT_Stream stream,
char* buffer,
int count )
{
int read_bytes;
int pos = stream->pos;
if ( pos >= stream->size )
{
FT_ERROR(( "FT_Read_Stream_At:" ));
FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
pos, stream->size ));
return 0;
}
if ( stream->read )
read_bytes = stream->read( stream, pos, buffer, count );
else
{
read_bytes = stream->size - pos;
if ( read_bytes > count )
read_bytes = count;
ft_memcpy( buffer, stream->base + pos, read_bytes );
}
stream->pos = pos + read_bytes;
return read_bytes;
}
static int
_bdf_readstream( FT_Stream stream,
_bdf_line_func_t callback,
void* client_data,
unsigned long* lno)
{
_bdf_line_func_t cb;
unsigned long lineno;
int n, res, done, refill, bytes, hold;
char *ls, *le, *pp, *pe, *hp;
char buf[65536];
if (callback == 0)
return -1;
cb = callback;
lineno = 1;
buf[0] = 0;
res = done = 0;
pp = ls = le = buf;
bytes = 65536;
while ( !done && (n = ftreadstream(stream, pp, bytes)) > 0 )
{
/*
* Determine the new end of the buffer pages.
*/
pe = pp + n;
for (refill = 0; done == 0 && refill == 0; )
{
while (le < pe && *le != '\n' && *le != '\r')
le++;
if (le == pe)
{
/*
* Hit the end of the last page in the buffer. Need to find
* out how many pages to shift and how many pages need to be
* read in. Adjust the line start and end pointers down to
* point to the right places in the pages.
*/
pp = buf + (((ls - buf) >> 13) << 13);
n = pp - buf;
ls -= n;
le -= n;
n = pe - pp;
(void) ft_memcpy(buf, pp, n);
pp = buf + n;
bytes = 65536 - n;
refill = 1;
}
else
{
/*
* Temporarily NULL terminate the line.
*/
hp = le;
hold = *le;
*le = 0;
if (callback && *ls != '#' && *ls != 0x1a && le > ls &&
(res = (*cb)(ls, le - ls, lineno, (void *) &cb,
client_data)) != 0)
done = 1;
else {
ls = ++le;
/*
* Handle the case of DOS crlf sequences.
*/
if (le < pe && hold == '\n' && *le =='\r')
ls = ++le;
}
/*
* Increment the line number.
*/
lineno++;
/*
* Restore the character at the end of the line.
*/
*hp = hold;
}
}
}
*lno = lineno;
return res;
}
FT_LOCAL_DEF( void )
_bdf_memmove(char *dest, char *src, unsigned long bytes)
{
long i, j;
i = (long) bytes;
j = i & 7;
i = (i + 7) >> 3;
/*
* Do a memmove using Ye Olde Duff's Device for efficiency.
*/
if (src < dest) {
src += bytes;
dest += bytes;
switch (j) {
case 0: do {
*--dest = *--src;
case 7: *--dest = *--src;
case 6: *--dest = *--src;
case 5: *--dest = *--src;
case 4: *--dest = *--src;
case 3: *--dest = *--src;
case 2: *--dest = *--src;
case 1: *--dest = *--src;
} while (--i > 0);
}
} else if (src > dest) {
switch (j) {
case 0: do {
*dest++ = *src++;
case 7: *dest++ = *src++;
case 6: *dest++ = *src++;
case 5: *dest++ = *src++;
case 4: *dest++ = *src++;
case 3: *dest++ = *src++;
case 2: *dest++ = *src++;
case 1: *dest++ = *src++;
} while (--i > 0);
}
}
}
static const unsigned char a2i[128] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const unsigned char odigits[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char ddigits[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const unsigned char hdigits[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7)))
/*
* Routine to convert an ASCII string into an unsigned long integer.
*/
static unsigned long
_bdf_atoul(char *s, char **end, int base)
{
unsigned long v;
unsigned char *dmap;
if (s == 0 || *s == 0)
return 0;
/*
* Make sure the radix is something recognizable. Default to 10.
*/
switch (base)
{
case 8: dmap = odigits; break;
case 16: dmap = hdigits; break;
default: base = 10; dmap = ddigits; break;
}
/*
* Check for the special hex prefix.
*/
if ( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X'))
{
base = 16;
dmap = hdigits;
s += 2;
}
for ( v = 0; isdigok(dmap, *s); s++ )
v = (v * base) + a2i[(int) *s];
if (end != 0)
*end = s;
return v;
}
/*
* Routine to convert an ASCII string into an signed long integer.
*/
static long
_bdf_atol(char *s, char **end, int base)
{
long v, neg;
unsigned char *dmap;
if (s == 0 || *s == 0)
return 0;
/*
* Make sure the radix is something recognizable. Default to 10.
*/
switch (base) {
case 8: dmap = odigits; break;
case 16: dmap = hdigits; break;
default: base = 10; dmap = ddigits; break;
}
/*
* Check for a minus sign.
*/
neg = 0;
if (*s == '-') {
s++;
neg = 1;
}
/*
* Check for the special hex prefix.
*/
if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
base = 16;
dmap = hdigits;
s += 2;
}
for (v = 0; isdigok(dmap, *s); s++)
v = (v * base) + a2i[(int) *s];
if (end != 0)
*end = s;
return (!neg) ? v : -v;
}
/*
* Routine to convert an ASCII string into an signed short integer.
*/
static short
_bdf_atos(char *s, char **end, int base)
{
short v, neg;
unsigned char *dmap;
if (s == 0 || *s == 0)
return 0;
/*
* Make sure the radix is something recognizable. Default to 10.
*/
switch (base) {
case 8: dmap = odigits; break;
case 16: dmap = hdigits; break;
default: base = 10; dmap = ddigits; break;
}
/*
* Check for a minus.
*/
neg = 0;
if (*s == '-') {
s++;
neg = 1;
}
/*
* Check for the special hex prefix.
*/
if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
base = 16;
dmap = hdigits;
s += 2;
}
for (v = 0; isdigok(dmap, *s); s++)
v = (v * base) + a2i[(int) *s];
if (end != 0)
*end = s;
return (!neg) ? v : -v;
}
/*
* Routine to compare two glyphs by encoding so they can be sorted.
*/
static int
by_encoding(const void *a, const void *b)
{
bdf_glyph_t *c1, *c2;
c1 = (bdf_glyph_t *) a;
c2 = (bdf_glyph_t *) b;
if (c1->encoding < c2->encoding)
return -1;
else if (c1->encoding > c2->encoding)
return 1;
return 0;
}
static FT_Error
bdf_create_property( char* name,
int format,
bdf_font_t* font )
{
unsigned long n;
bdf_property_t* p;
FT_Memory memory = font->memory;
FT_Error error;
/*
* First check to see if the property has
* already been added or not. If it has, then
* simply ignore it.
*/
if ( hash_lookup( name, &(font->proptbl)) )
return FT_Err_Ok;
if (font->nuser_props == 0)
{
if ( FT_NEW( font->user_props ) )
return error;
}
else
{
if ( FT_RENEW_ARRAY( font->user_props, font->nuser_props,
(font->nuser_props + 1) ) )
return error;
}
p = font->user_props + font->nuser_props;
FT_ZERO( p );
n = (unsigned long) (ft_strlen(name) + 1);
if ( FT_ALLOC ( p->name , n) )
return error;
FT_MEM_COPY(p->name, name, n);
p->format = format;
p->builtin = 0;
n = _num_bdf_properties + font->nuser_props;
error = hash_insert(p->name, (void *) n, &(font->proptbl) , memory);
if (error) return error;
font->nuser_props++;
return FT_Err_Ok;
}
FT_LOCAL_DEF( bdf_property_t* )
bdf_get_property(char *name, bdf_font_t *font)
{
hashnode hn;
unsigned long propid;
if (name == 0 || *name == 0)
return 0;
if ((hn = hash_lookup(name, &(font->proptbl))) == 0)
return 0;
propid = (unsigned long) hn->data;
if (propid >= _num_bdf_properties)
return font->user_props + (propid - _num_bdf_properties);
return _bdf_properties + propid;
}
/**************************************************************************
*
* BDF font file parsing flags and functions.
*
**************************************************************************/
/*
* Parse flags.
*/
#define _BDF_START 0x0001
#define _BDF_FONT_NAME 0x0002
#define _BDF_SIZE 0x0004
#define _BDF_FONT_BBX 0x0008
#define _BDF_PROPS 0x0010
#define _BDF_GLYPHS 0x0020
#define _BDF_GLYPH 0x0040
#define _BDF_ENCODING 0x0080
#define _BDF_SWIDTH 0x0100
#define _BDF_DWIDTH 0x0200
#define _BDF_BBX 0x0400
#define _BDF_BITMAP 0x0800
#define _BDF_SWIDTH_ADJ 0x1000
#define _BDF_GLYPH_BITS (_BDF_GLYPH|_BDF_ENCODING|_BDF_SWIDTH|\
_BDF_DWIDTH|_BDF_BBX|_BDF_BITMAP)
#define _BDF_GLYPH_WIDTH_CHECK 0x40000000
#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000
/*
* Auto correction messages.
*/
#define ACMSG1 "FONT_ASCENT property missing. Added \"FONT_ASCENT %hd\"."
#define ACMSG2 "FONT_DESCENT property missing. Added \"FONT_DESCENT %hd\"."
#define ACMSG3 "Font width != actual width. Old: %hd New: %hd."
#define ACMSG4 "Font left bearing != actual left bearing. Old: %hd New: %hd."
#define ACMSG5 "Font ascent != actual ascent. Old: %hd New: %hd."
#define ACMSG6 "Font descent != actual descent. Old: %hd New: %hd."
#define ACMSG7 "Font height != actual height. Old: %hd New: %hd."
#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made."
#define ACMSG9 "SWIDTH field missing at line %ld. Set automatically."
#define ACMSG10 "DWIDTH field missing at line %ld. Set to glyph width."
#define ACMSG11 "SIZE bits per pixel field adjusted to %hd."
#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded."
#define ACMSG13 "Glyph %ld extra rows removed."
#define ACMSG14 "Glyph %ld extra columns removed."
#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found."
/*
* Error messages.
*/
#define ERRMSG1 "[line %ld] Missing \"%s\" line."
#define ERRMSG2 "[line %ld] Font header corrupted or missing fields."
#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields."
static FT_Error
_bdf_add_acmsg ( bdf_font_t* font,
char* msg,
unsigned long len )
{
char* cp;
FT_Memory memory = font->memory;
FT_Error error;
if ( font->acmsgs_len == 0 )
{
if ( FT_ALLOC ( font->acmsgs , len + 1 ) )
return error;
}
else
{
if ( FT_REALLOC ( font->acmsgs , font->acmsgs_len ,
font->acmsgs_len + len + 1 ) )
return error;
}
cp = font->acmsgs + font->acmsgs_len;
FT_MEM_COPY(cp, msg, len);
cp += len;
*cp++ = '\n';
font->acmsgs_len += len + 1;
return FT_Err_Ok;
}
static FT_Error
_bdf_add_comment ( bdf_font_t* font,
char* comment,
unsigned long len )
{
char *cp;
FT_Memory memory = font->memory;
FT_Error error;
if (font->comments_len == 0) {
if ( FT_ALLOC ( font->comments , len + 1 ) )
return error;
}
else
{
if ( FT_REALLOC ( font->comments , font->comments_len,
font->comments_len + len + 1) )
return error;
}
cp = font->comments + font->comments_len;
FT_MEM_COPY(cp, comment, len);
cp += len;
*cp++ = '\n';
font->comments_len += len + 1;
return FT_Err_Ok;
}
/*
* Set the spacing from the font name if it exists, or set it to the default
* specified in the options.
*/
static void
_bdf_set_default_spacing( bdf_font_t* font,
bdf_options_t* opts)
{
unsigned long len;
char name[128];
_bdf_list_t list;
FT_Memory memory;
/* FT_Error error; */
if ( font == 0 || font->name == 0 || font->name[0] == 0 )
return;
memory = font->memory;
font->spacing = opts->font_spacing;
len = (unsigned long) ( ft_strlen(font->name) + 1 );
(void) ft_memcpy(name, font->name, len);
list.size = list.used = 0;
_bdf_split("-", name, len, &list, memory);
if (list.used == 15) {
switch (list.field[11][0]) {
case 'C': case 'c': font->spacing = BDF_CHARCELL; break;
case 'M': case 'm': font->spacing = BDF_MONOWIDTH; break;
case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
}
}
if (list.size > 0)
FT_FREE(list.field);
}
/*
* Determine if the property is an atom or not. If it is, then clean it up so
* the double quotes are removed if they exist.
*/
static int
_bdf_is_atom( char* line,
unsigned long linelen,
char* *name,
char* *value,
bdf_font_t* font)
{
int hold;
char *sp, *ep;
bdf_property_t *p;
*name = sp = ep = line;
while (*ep && *ep != ' ' && *ep != '\t')
ep++;
hold = -1;
if (*ep)
{
hold = *ep;
*ep = 0;
}
p = bdf_get_property(sp, font);
/*
* Restore the character that was saved before any return can happen.
*/
if (hold != -1)
*ep = hold;
/*
* If the propert exists and is not an atom, just return here.
*/
if (p && p->format != BDF_ATOM)
return 0;
/*
* The property is an atom. Trim all leading and trailing whitespace and
* double quotes for the atom value.
*/
sp = ep;
ep = line + linelen;
/*
* Trim the leading whitespace if it exists.
*/
*sp++ = 0;
while (*sp && (*sp == ' ' || *sp == '\t'))
sp++;
/*
* Trim the leading double quote if it exists.
*/
if (*sp == '"')
sp++;
*value = sp;
/*
* Trim the trailing whitespace if it exists.
*/
while (ep > sp && (*(ep - 1) == ' ' || *(ep - 1) == '\t'))
*--ep = 0;
/*
* Trim the trailing double quote if it exists.
*/
if (ep > sp && *(ep - 1) == '"')
*--ep = 0;
return 1;
}
static FT_Error
_bdf_add_property ( bdf_font_t* font,
char* name,
char* value)
{
unsigned long propid;
hashnode hn;
int len;
bdf_property_t *prop, *fp;
FT_Memory memory = font->memory;
FT_Error error;
/* hashtable proptbl = font->proptbl;
bdf_property_t *user_props = font->user_props;
unsigned long nuser_props = font->nuser_props;
*/
/*
* First, check to see if the property already exists in the font.
*/
if ((hn = hash_lookup(name, (hashtable *) font->internal)) != 0) {
/*
* The property already exists in the font, so simply replace
* the value of the property with the current value.
*/
fp = font->props + (unsigned long) hn->data;
switch (prop->format)
{
case BDF_ATOM:
{
/*
* Delete the current atom if it exists.
*/
FT_FREE ( fp->value.atom );
if (value == 0)
len = 1;
else
len = ft_strlen(value) + 1;
if (len > 1)
{
if ( FT_ALLOC ( fp->value.atom , len ) )
return error;
FT_MEM_COPY(fp->value.atom, value, len);
}
else
fp->value.atom = 0;
}
break;
case BDF_INTEGER:
fp->value.int32 = _bdf_atol(value, 0, 10);
break;
case BDF_CARDINAL:
fp->value.card32 = _bdf_atoul(value, 0, 10);
break;
default:
;
}
return FT_Err_Ok;
}
/*
* See if this property type exists yet or not. If not, create it.
*/
hn = hash_lookup(name, &(font->proptbl));
if (hn == 0) {
bdf_create_property(name, BDF_ATOM, font);
hn = hash_lookup(name, &(font->proptbl));
}
/*
* Allocate another property if this is overflow.
*/
if (font->props_used == font->props_size)
{
if (font->props_size == 0)
{
if ( FT_NEW( font->props ) )
return error;
}
else
{
if ( FT_RENEW_ARRAY( font->props, font->props_size,
(font->props_size + 1) ) )
return error;
}
fp = font->props + font->props_size;
FT_ZERO( fp );
font->props_size++;
}
propid = (unsigned long) hn->data;
if (propid >= _num_bdf_properties)
prop = font->user_props + (propid - _num_bdf_properties);
else
prop = _bdf_properties + propid;
fp = font->props + font->props_used;
fp->name = prop->name;
fp->format = prop->format;
fp->builtin = prop->builtin;
switch (prop->format)
{
case BDF_ATOM:
{
fp->value.atom = NULL;
if ( value && value[0] != 0 )
{
len = ft_strlen(value) + 1;
if ( FT_ALLOC ( fp->value.atom , len ) )
return error;
FT_MEM_COPY (fp->value.atom, value, len);
}
}
break;
case BDF_INTEGER:
fp->value.int32 = _bdf_atol(value, 0, 10);
break;
case BDF_CARDINAL:
fp->value.card32 = _bdf_atoul(value, 0, 10);
break;
default:
;
}
/*
* If the property happens to be a comment, then it doesn't need
* to be added to the internal hash table.
*/
if ( ft_memcmp(name, "COMMENT", 7) != 0 )
/*
* Add the property to the font property table.
*/
hash_insert( fp->name, (void *) font->props_used,
(hashtable *) font->internal, memory);
font->props_used++;
/*
* Some special cases need to be handled here. The DEFAULT_CHAR property
* needs to be located if it exists in the property list, the FONT_ASCENT
* and FONT_DESCENT need to be assigned if they are present, and the
* SPACING property should override the default spacing.
*/
if ( ft_memcmp(name, "DEFAULT_CHAR", 12) == 0 )
font->default_glyph = fp->value.int32;
else if ( ft_memcmp(name, "FONT_ASCENT", 11) == 0 )
font->font_ascent = fp->value.int32;
else if ( ft_memcmp(name, "FONT_DESCENT", 12) == 0 )
font->font_descent = fp->value.int32;
else if ( ft_memcmp(name, "SPACING", 7) == 0 )
{
if (fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P')
font->spacing = BDF_PROPORTIONAL;
else if (fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M')
font->spacing = BDF_MONOWIDTH;
else if (fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C')
font->spacing = BDF_CHARCELL;
}
return FT_Err_Ok;
}
/*
* Actually parse the glyph info and bitmaps.
*/
static int
_bdf_parse_glyphs( char* line,
unsigned long linelen,
unsigned long lineno,
void* call_data,
void* client_data)
{
int c;
char *s;
unsigned char *bp;
unsigned long i, slen, nibbles;
double ps, rx, dw, sw;
_bdf_line_func_t *next;
_bdf_parse_t *p;
bdf_glyph_t *glyph;
bdf_font_t *font;
char nbuf[128];
FT_Memory memory;
FT_Error error;
next = (_bdf_line_func_t *) call_data;
p = (_bdf_parse_t *) client_data;
font = p->font;
memory = font->memory;
/*
* Check for a comment.
*/
if (ft_memcmp(line, "COMMENT", 7) == 0) {
linelen -= 7;
s = line + 7;
if (*s != 0) {
s++;
linelen--;
}
_bdf_add_comment(p->font, s, linelen);
return 0;
}
/*
* The very first thing expected is the number of glyphs.
*/
if (!(p->flags & _BDF_GLYPHS)) {
if (ft_memcmp(line, "CHARS", 5) != 0) {
sprintf(nbuf, ERRMSG1, lineno, "CHARS");
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
return BDF_MISSING_CHARS;
}
_bdf_split(" +", line, linelen, &p->list, memory);
p->cnt = font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10);
/*
* Make sure the number of glyphs is non-zero.
*/
if (p->cnt == 0)
font->glyphs_size = 64;
if ( FT_ALLOC ( font->glyphs , sizeof(bdf_glyph_t) *
font->glyphs_size ) )
return FT_Err_Out_Of_Memory;
/*
* Set up the callback to indicate the glyph loading is about to
* begin.
*/
if (p->callback != 0) {
p->cb.reason = BDF_LOAD_START;
p->cb.total = p->cnt;
p->cb.current = 0;
(*p->callback)(&p->cb, p->client_data);
}
p->flags |= _BDF_GLYPHS;
return 0;
}
/*
* Check for the ENDFONT field.
*/
if (ft_memcmp(line, "ENDFONT", 7) == 0) {
/*
* Sort the glyphs by encoding.
*/
qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t),
by_encoding);
p->flags &= ~_BDF_START;
return 0;
}
/*
* Check for the ENDCHAR field.
*/
if (ft_memcmp(line, "ENDCHAR", 7) == 0) {
/*
* Set up and call the callback if it was passed.
*/
if (p->callback != 0) {
p->cb.reason = BDF_LOADING;
p->cb.total = font->glyphs_size;
p->cb.current = font->glyphs_used;
(*p->callback)(&p->cb, p->client_data);
}
p->glyph_enc = 0;
p->flags &= ~_BDF_GLYPH_BITS;
return 0;
}
/*
* Check to see if a glyph is being scanned but should be ignored
* because it is an unencoded glyph.
*/
if ((p->flags & _BDF_GLYPH) &&
p->glyph_enc == -1 && p->opts->keep_unencoded == 0)
return 0;
/*
* Check for the STARTCHAR field.
*/
if (ft_memcmp(line, "STARTCHAR", 9) == 0) {
/*
* Set the character name in the parse info first until the
* encoding can be checked for an unencoded character.
*/
if (p->glyph_name != 0)
FT_FREE(p->glyph_name);
_bdf_split(" +", line, linelen, &p->list,memory);
_bdf_shift(1, &p->list);
s = _bdf_join(' ', &slen, &p->list);
if ( FT_ALLOC ( p->glyph_name , (slen + 1) ) )
return BDF_OUT_OF_MEMORY;
FT_MEM_COPY(p->glyph_name, s, slen + 1);
p->flags |= _BDF_GLYPH;
return 0;
}
/*
* Check for the ENCODING field.
*/
if (ft_memcmp(line, "ENCODING", 8) == 0) {
if (!(p->flags & _BDF_GLYPH)) {
/*
* Missing STARTCHAR field.
*/
sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR");
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
return BDF_MISSING_STARTCHAR;
}
_bdf_split(" +", line, linelen, &p->list, memory);
p->glyph_enc = _bdf_atol(p->list.field[1], 0, 10);
/*
* Check to see if this encoding has already been encountered. If it
* has then change it to unencoded so it gets added if indicated.
*/
if (p->glyph_enc >= 0) {
if (_bdf_glyph_modified(p->have, p->glyph_enc)) {
/*
* Add a message saying a glyph has been moved to the
* unencoded area.
*/
sprintf(nbuf, ACMSG12, p->glyph_enc, p->glyph_name);
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
p->glyph_enc = -1;
font->modified = 1;
} else
_bdf_set_glyph_modified(p->have, p->glyph_enc);
}
if (p->glyph_enc >= 0) {
/*
* Make sure there are enough glyphs allocated in case the
* number of characters happen to be wrong.
*/
if (font->glyphs_used == font->glyphs_size) {
if ( FT_REALLOC ( font->glyphs,
sizeof(bdf_glyph_t) * font->glyphs_size,
sizeof(bdf_glyph_t) * (font->glyphs_size + 64) ) )
return BDF_OUT_OF_MEMORY;
FT_MEM_SET ((char *) (font->glyphs + font->glyphs_size),
0, sizeof(bdf_glyph_t) << 6); /* FZ inutile */
font->glyphs_size += 64;
}
glyph = font->glyphs + font->glyphs_used++;
glyph->name = p->glyph_name;
glyph->encoding = p->glyph_enc;
/*
* Reset the initial glyph info.
*/
p->glyph_name = 0;
} else {
/*
* Unencoded glyph. Check to see if it should be added or not.
*/
if (p->opts->keep_unencoded != 0) {
/*
* Allocate the next unencoded glyph.
*/
if (font->unencoded_used == font->unencoded_size) {
if (font->unencoded_size == 0) {
if ( FT_ALLOC ( font->unencoded , sizeof(bdf_glyph_t) << 2 ) )
return BDF_OUT_OF_MEMORY;
}
else {
if ( FT_REALLOC ( font->unencoded ,
sizeof(bdf_glyph_t) * font->unencoded_size,
sizeof(bdf_glyph_t) *
(font->unencoded_size + 4) ) )
return BDF_OUT_OF_MEMORY;
}
font->unencoded_size += 4;
}
glyph = font->unencoded + font->unencoded_used;
glyph->name = p->glyph_name;
glyph->encoding = font->unencoded_used++;
} else
/*
* Free up the glyph name if the unencoded shouldn't be
* kept.
*/
FT_FREE( p->glyph_name );
p->glyph_name = 0;
}
/*
* Clear the flags that might be added when width and height are
* checked for consistency.
*/
p->flags &= ~(_BDF_GLYPH_WIDTH_CHECK|_BDF_GLYPH_HEIGHT_CHECK);
p->flags |= _BDF_ENCODING;
return 0;
}
/*
* Point at the glyph being constructed.
*/
if (p->glyph_enc == -1)
glyph = font->unencoded + (font->unencoded_used - 1);
else
glyph = font->glyphs + (font->glyphs_used - 1);
/*
* Check to see if a bitmap is being constructed.
*/
if (p->flags & _BDF_BITMAP) {
/*
* If there are more rows than are specified in the glyph metrics,
* ignore the remaining lines.
*/
if (p->row >= glyph->bbx.height) {
if (!(p->flags & _BDF_GLYPH_HEIGHT_CHECK)) {
sprintf(nbuf, ACMSG13, glyph->encoding);
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
font->modified = 1;
}
return 0;
}
/*
* Only collect the number of nibbles indicated by the glyph metrics.
* If there are more columns, they are simply ignored.
*/
nibbles = p->bpr << 1;
bp = glyph->bitmap + (p->row * p->bpr);
for (i = 0, *bp = 0; i < nibbles; i++) {
c = line[i];
*bp = (*bp << 4) + a2i[c];
if (i + 1 < nibbles && (i & 1))
*++bp = 0;
}
/*
* If any line has extra columns, indicate they have been removed.
*/
if ((line[nibbles] == '0' || a2i[(int) line[nibbles]] != 0) &&
!(p->flags & _BDF_GLYPH_WIDTH_CHECK)) {
sprintf(nbuf, ACMSG14, glyph->encoding);
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
p->flags |= _BDF_GLYPH_WIDTH_CHECK;
font->modified = 1;
}
p->row++;
return 0;
}
/*
* Expect the SWIDTH (scalable width) field next.
*/
if (ft_memcmp(line, "SWIDTH", 6) == 0) {
if (!(p->flags & _BDF_ENCODING)) {
/*
* Missing ENCODING field.
*/
sprintf(nbuf, ERRMSG1, lineno, "ENCODING");
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
return BDF_MISSING_ENCODING;
}
_bdf_split(" +", line, linelen, &p->list, memory);
glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10);
p->flags |= _BDF_SWIDTH;
return 0;
}
/*
* Expect the DWIDTH (scalable width) field next.
*/
if (ft_memcmp(line, "DWIDTH", 6) == 0) {
_bdf_split(" +", line, linelen, &p->list,memory);
glyph->dwidth = _bdf_atoul(p->list.field[1], 0, 10);
if (!(p->flags & _BDF_SWIDTH)) {
/*
* Missing SWIDTH field. Add an auto correction message and set
* the scalable width from the device width.
*/
sprintf(nbuf, ACMSG9, lineno);
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
ps = (double) font->point_size;
rx = (double) font->resolution_x;
dw = (double) glyph->dwidth;
glyph->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
}
p->flags |= _BDF_DWIDTH;
return 0;
}
/*
* Expect the BBX field next.
*/
if (ft_memcmp(line, "BBX", 3) == 0) {
_bdf_split(" +", line, linelen, &p->list, memory);
glyph->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
glyph->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
glyph->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
glyph->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
/*
* Generate the ascent and descent of the character.
*/
glyph->bbx.ascent = glyph->bbx.height + glyph->bbx.y_offset;
glyph->bbx.descent = -glyph->bbx.y_offset;
/*
* Determine the overall font bounding box as the characters are
* loaded so corrections can be done later if indicated.
*/
p->maxas = MAX(glyph->bbx.ascent, p->maxas);
p->maxds = MAX(glyph->bbx.descent, p->maxds);
p->rbearing = glyph->bbx.width + glyph->bbx.x_offset;
p->maxrb = MAX(p->rbearing, p->maxrb);
p->minlb = MIN(glyph->bbx.x_offset, p->minlb);
p->maxlb = MAX(glyph->bbx.x_offset, p->maxlb);
if (!(p->flags & _BDF_DWIDTH)) {
/*
* Missing DWIDTH field. Add an auto correction message and set
* the device width to the glyph width.
*/
sprintf(nbuf, ACMSG10, lineno);
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
glyph->dwidth = glyph->bbx.width;
}
/*
* If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH
* value if necessary.
*/
if (p->opts->correct_metrics != 0) {
/*
* Determine the point size of the glyph.
*/
ps = (double) font->point_size;
rx = (double) font->resolution_x;
dw = (double) glyph->dwidth;
sw = (unsigned short) ((dw * 72000.0) / (ps * rx));
if (sw != glyph->swidth) {
glyph->swidth = sw;
if (p->glyph_enc == -1)
_bdf_set_glyph_modified(font->umod,
font->unencoded_used - 1);
else
_bdf_set_glyph_modified(font->nmod, glyph->encoding);
p->flags |= _BDF_SWIDTH_ADJ;
font->modified = 1;
}
}
p->flags |= _BDF_BBX;
return 0;
}
/*
* And finally, gather up the bitmap.
*/
if (ft_memcmp(line, "BITMAP", 6) == 0) {
if (!(p->flags & _BDF_BBX)) {
/*
* Missing BBX field.
*/
sprintf(nbuf, ERRMSG1, lineno, "BBX");
_bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
return BDF_MISSING_BBX;
}
/*
* Allocate enough space for the bitmap.
*/
p->bpr = ((glyph->bbx.width * p->font->bpp) + 7) >> 3;
glyph->bytes = p->bpr * glyph->bbx.height;
if ( FT_ALLOC ( glyph->bitmap , glyph->bytes ) )
return BDF_OUT_OF_MEMORY;
p->row = 0;
p->flags |= _BDF_BITMAP;
return 0;
}
return BDF_INVALID_LINE;
}
/*
* Load the font properties.
*/
static int
_bdf_parse_properties(char *line, unsigned long linelen, unsigned long lineno,
void *call_data, void *client_data)
{
unsigned long vlen;
_bdf_line_func_t *next;
_bdf_parse_t *p;
char *name, *value, nbuf[128];
FT_Memory memory;
next = (_bdf_line_func_t *) call_data;
p = (_bdf_parse_t *) client_data;
memory = p->font->memory;
/*
* Check for the end of the properties.
*/
if (ft_memcmp(line, "ENDPROPERTIES", 13) == 0) {
/*
* If the FONT_ASCENT or FONT_DESCENT properties have not been
* encountered yet, then make sure they are added as properties and
* make sure they are set from the font bounding box info.
*
* This is *always* done regardless of the options, because X11
* requires these two fields to compile fonts.
*/
if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
p->font->font_ascent = p->font->bbx.ascent;
sprintf(nbuf, "%hd", p->font->bbx.ascent);
_bdf_add_property(p->font, "FONT_ASCENT", nbuf);
sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
p->font->modified = 1;
}
if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
p->font->font_descent = p->font->bbx.descent;
sprintf(nbuf, "%hd", p->font->bbx.descent);
_bdf_add_property(p->font, "FONT_DESCENT", nbuf);
sprintf(nbuf, ACMSG2, p->font->bbx.descent);
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
p->font->modified = 1;
}
p->flags &= ~_BDF_PROPS;
*next = _bdf_parse_glyphs;
return 0;
}
/*
* Ignore the _XFREE86_GLYPH_RANGES properties.
*/
if (ft_memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0)
return 0;
/*
* Handle COMMENT fields and properties in a special way to preserve
* the spacing.
*/
if (ft_memcmp(line, "COMMENT", 7) == 0) {
name = value = line;
value += 7;
if (*value)
*value++ = 0;
_bdf_add_property(p->font, name, value);
} else if (_bdf_is_atom(line, linelen, &name, &value, p->font))
_bdf_add_property(p->font, name, value);
else {
_bdf_split(" +", line, linelen, &p->list, memory);
name = p->list.field[0];
_bdf_shift(1, &p->list);
value = _bdf_join(' ', &vlen, &p->list);
_bdf_add_property(p->font, name, value);
}
return 0;
}
/*
* Load the font header.
*/
static int
_bdf_parse_start(char *line, unsigned long linelen, unsigned long lineno,
void *call_data, void *client_data)
{
unsigned long slen;
_bdf_line_func_t *next;
_bdf_parse_t *p;
bdf_font_t *font;
char *s, nbuf[128];
/* int test; */
FT_Memory memory;
FT_Error error;
next = (_bdf_line_func_t *) call_data;
p = (_bdf_parse_t *) client_data;
if (p->font)
memory = p->font->memory;
/*
* Check for a comment. This is done to handle those fonts that have
* comments before the STARTFONT line for some reason.
*/
if (ft_memcmp(line, "COMMENT", 7) == 0) {
if (p->opts->keep_comments != 0 && p->font != 0) {
linelen -= 7;
s = line + 7;
if (*s != 0) {
s++;
linelen--;
}
_bdf_add_comment(p->font, s, linelen);
/* here font is not defined ! */
}
return 0;
}
if (!(p->flags & _BDF_START)) {
memory = p->memory;
if (ft_memcmp(line, "STARTFONT", 9) != 0)
/*
* No STARTFONT field is a good indication of a problem.
*/
return BDF_MISSING_START;
p->flags = _BDF_START;
font = p->font = 0;
if ( FT_ALLOC ( font, sizeof(bdf_font_t) ) )
return BDF_OUT_OF_MEMORY;
p->font = font;
font->memory = p->memory;
p->memory = 0;
/* if (font == 0) {
fprintf(stderr,"failed font\n");
}*/ /* XXX */
{ /* setup */
unsigned long i;
bdf_property_t *prop;
hash_init(&(font->proptbl), memory);
for (i = 0, prop = _bdf_properties;
i < _num_bdf_properties; i++, prop++)
hash_insert(prop->name, (void *) i, &(font->proptbl) , memory);
}
if ( FT_ALLOC ( p->font->internal , sizeof(hashtable) ) )
return BDF_OUT_OF_MEMORY;
hash_init((hashtable *) p->font->internal,memory);
p->font->spacing = p->opts->font_spacing;
p->font->default_glyph = -1;
return 0;
}
/*
* Check for the start of the properties.
*/
if (ft_memcmp(line, "STARTPROPERTIES", 15) == 0) {
_bdf_split(" +", line, linelen, &p->list, memory);
p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
if ( FT_ALLOC ( p->font->props , (sizeof(bdf_property_t) * p->cnt) ) )
return BDF_OUT_OF_MEMORY;
p->flags |= _BDF_PROPS;
*next = _bdf_parse_properties;
return 0;
}
/*
* Check for the FONTBOUNDINGBOX field.
*/
if (ft_memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
if (!(p->flags & _BDF_SIZE)) {
/*
* Missing the SIZE field.
*/
sprintf(nbuf, ERRMSG1, lineno, "SIZE");
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
return BDF_MISSING_SIZE;
}
_bdf_split(" +", line, linelen, &p->list , memory);
p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
p->font->bbx.descent = -p->font->bbx.y_offset;
p->flags |= _BDF_FONT_BBX;
return 0;
}
/*
* The next thing to check for is the FONT field.
*/
if (ft_memcmp(line, "FONT", 4) == 0) {
_bdf_split(" +", line, linelen, &p->list , memory);
_bdf_shift(1, &p->list);
s = _bdf_join(' ', &slen, &p->list);
if ( FT_ALLOC ( p->font->name , slen + 1 ) )
return BDF_OUT_OF_MEMORY;
(void) ft_memcpy(p->font->name, s, slen + 1);
/*
* If the font name is an XLFD name, set the spacing to the one in the
* font name. If there is no spacing fall back on the default.
*/
_bdf_set_default_spacing(p->font, p->opts);
p->flags |= _BDF_FONT_NAME;
return 0;
}
/*
* Check for the SIZE field.
*/
if (ft_memcmp(line, "SIZE", 4) == 0) {
if (!(p->flags & _BDF_FONT_NAME)) {
/*
* Missing the FONT field.
*/
sprintf(nbuf, ERRMSG1, lineno, "FONT");
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
return BDF_MISSING_FONTNAME;
}
_bdf_split(" +", line, linelen, &p->list, memory);
p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
/*
* Check for the bits per pixel field.
*/
if (p->list.used == 5) {
p->font->bpp = _bdf_atos(p->list.field[4], 0, 10);
if (p->font->bpp > 1 && (p->font->bpp & 1)) {
/*
* Move up to the next bits per pixel value if an odd number
* is encountered.
*/
p->font->bpp++;
if (p->font->bpp <= 4) {
sprintf(nbuf, ACMSG11, p->font->bpp);
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
}
}
if (p->font->bpp > 4) {
sprintf(nbuf, ACMSG11, p->font->bpp);
_bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
p->font->bpp = 4;
}
} else
p->font->bpp = 1;
p->flags |= _BDF_SIZE;
return 0;
}
return BDF_INVALID_LINE;
}
/**************************************************************************
*
* API.
*
**************************************************************************/
FT_LOCAL_DEF( bdf_font_t* )
bdf_load_font( FT_Stream stream,
FT_Memory extmemory,
bdf_options_t* opts,
bdf_callback_t callback,
void* data)
{
int n;
unsigned long lineno;
char msgbuf[128];
_bdf_parse_t p;
FT_Memory memory;
FT_Error error;
(void) ft_memset((char *) &p, 0, sizeof(_bdf_parse_t));
p.opts = (opts != 0) ? opts : &_bdf_opts;
p.minlb = 32767;
p.callback = callback;
p.client_data = data;
p.memory = extmemory; /* only during font creation */
n = _bdf_readstream(stream, _bdf_parse_start, (void *) &p, &lineno);
if (p.font != 0) {
/*
* If the font is not proportional, set the fonts monowidth
* field to the width of the font bounding box.
*/
memory = p.font->memory;
if (p.font->spacing != BDF_PROPORTIONAL)
p.font->monowidth = p.font->bbx.width;
/*
* If the number of glyphs loaded is not that of the original count,
* indicate the difference.
*/
if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) {
sprintf(msgbuf, ACMSG15, p.cnt,
p.font->glyphs_used + p.font->unencoded_used);
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
p.font->modified = 1;
}
/*
* Once the font has been loaded, adjust the overall font metrics if
* necessary.
*/
if (p.opts->correct_metrics != 0 &&
(p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) {
if (p.maxrb - p.minlb != p.font->bbx.width) {
sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb);
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
p.font->bbx.width = p.maxrb - p.minlb;
p.font->modified = 1;
}
if (p.font->bbx.x_offset != p.minlb) {
sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb);
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
p.font->bbx.x_offset = p.minlb;
p.font->modified = 1;
}
if (p.font->bbx.ascent != p.maxas) {
sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas);
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
p.font->bbx.ascent = p.maxas;
p.font->modified = 1;
}
if (p.font->bbx.descent != p.maxds) {
sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds);
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
p.font->bbx.descent = p.maxds;
p.font->bbx.y_offset = -p.maxds;
p.font->modified = 1;
}
if (p.maxas + p.maxds != p.font->bbx.height) {
sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds);
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
}
p.font->bbx.height = p.maxas + p.maxds;
if (p.flags & _BDF_SWIDTH_ADJ)
_bdf_add_acmsg(p.font, ACMSG8, ft_strlen(ACMSG8));
}
}
/*
* Last, if an error happened during loading, handle the messages.
*/
if (n < 0 && callback != 0) {
/*
* An error was returned. Alert the client.
*/
p.cb.reason = BDF_ERROR;
p.cb.errlineno = lineno;
(*callback)(&p.cb, data);
} else if (p.flags & _BDF_START) {
if (p.font != 0) {
/*
* The ENDFONT field was never reached or did not exist.
*/
if (!(p.flags & _BDF_GLYPHS))
/*
* Error happened while parsing header.
*/
sprintf(msgbuf, ERRMSG2, lineno);
else
/*
* Error happened when parsing glyphs.
*/
sprintf(msgbuf, ERRMSG3, lineno);
_bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
}
if (callback != 0) {
p.cb.reason = BDF_ERROR;
p.cb.errlineno = lineno;
(*callback)(&p.cb, data);
}
} else if (callback != 0) {
/*
* This forces the progress bar to always finish.
*/
p.cb.current = p.cb.total;
(*p.callback)(&p.cb, p.client_data);
}
/*
* Free up the list used during the parsing.
*/
if (p.list.size > 0)
FT_FREE( p.list.field );
if (p.font != 0) {
/*
* Make sure the comments are NULL terminated if they exist.
*/
memory = p.font->memory;
if (p.font->comments_len > 0) {
if ( FT_REALLOC ( p.font->comments , p.font->comments_len ,
p.font->comments_len + 1 ) )
return 0;
p.font->comments[p.font->comments_len] = 0;
}
/*
* Make sure the auto-correct messages are NULL terminated if they
* exist.
*/
if (p.font->acmsgs_len > 0) {
memory = p.font->memory;
if ( FT_REALLOC ( p.font->acmsgs , p.font->acmsgs_len ,
p.font->acmsgs_len + 1 ) )
return 0;
p.font->acmsgs[p.font->acmsgs_len] = 0;
}
}
return p.font;
}
FT_LOCAL_DEF( void )
bdf_free_font( bdf_font_t *font )
{
bdf_property_t *prop;
unsigned long i;
bdf_glyph_t *glyphs;
FT_Memory memory;
if (font == 0)
return;
memory = font->memory;
if (font->name != 0)
FT_FREE(font->name);
/*
* Free up the internal hash table of property names.
*/
if (font->internal) {
hash_free((hashtable *) font->internal, memory);
FT_FREE(font->internal);
}
/*
* Free up the comment info.
*/
if (font->comments_len > 0)
FT_FREE(font->comments);
/*
* Free up the auto-correction messages.
*/
if (font->acmsgs_len > 0)
FT_FREE(font->acmsgs);
/*
* Free up the properties.
*/
for (i = 0; i < font->props_size; i++) {
if (font->props[i].format == BDF_ATOM && font->props[i].value.atom)
FT_FREE(font->props[i].value.atom);
}
if (font->props_size > 0 && font->props != 0)
FT_FREE(font->props);
/*
* Free up the character info.
*/
for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) {
if (glyphs->name)
FT_FREE(glyphs->name);
if (glyphs->bytes > 0 && glyphs->bitmap != 0)
FT_FREE(glyphs->bitmap);
}
for (i = 0, glyphs = font->unencoded; i < font->unencoded_used;
i++, glyphs++) {
if (glyphs->name)
FT_FREE(glyphs->name);
if (glyphs->bytes > 0)
FT_FREE(glyphs->bitmap);
}
if (font->glyphs_size > 0)
FT_FREE( font->glyphs);
if (font->unencoded_size > 0)
FT_FREE( font->unencoded);
/*
* Free up the overflow storage if it was used.
*/
for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used;
i++, glyphs++) {
if (glyphs->name != 0)
FT_FREE(glyphs->name);
if (glyphs->bytes > 0)
FT_FREE( glyphs->bitmap);;
}
if (font->overflow.glyphs_size > 0)
FT_FREE(font->overflow.glyphs);
/* bdf_cleanup */
hash_free(&(font->proptbl),memory);
/*
* Free up the user defined properties.
*/
for (prop = font->user_props, i = 0; i < font->nuser_props; i++, prop++) {
FT_FREE(prop->name);
if (prop->format == BDF_ATOM && prop->value.atom != 0)
FT_FREE(prop->value.atom);
}
if (font->nuser_props > 0)
FT_FREE(font->user_props);
/*FREE( font);*/ /* XXX Fixme */
}
FT_LOCAL_DEF( bdf_property_t* )
bdf_get_font_property( bdf_font_t* font,
char* name)
{
hashnode hn;
if (font == 0 || font->props_size == 0 || name == 0 || *name == 0)
return 0;
hn = hash_lookup(name, (hashtable *) font->internal);
return (hn) ? (font->props + ((unsigned long) hn->data)) : 0;
}