* src/bdf/bdflib.c: various improvements to the bdf loader, mainly

used to reduce the amount of heap size required to only test wether
    we're dealing with a BDF font (the old code allocated 64 Kb right
    before any test).

    * src/lzw/ftlzw.c (FT_Stream_OpenLZW): modified the function to check
    the LZW header before doing anything else. This helps avoid un-necessary
    heap allocations (400 Kb of heap memory for the LZW decoder ! Oh my !)

    * src/gzip/ftgzip.c (FT_Stream_OpenGZip): ditto for the .gz decoder,
    though the code savings is smaller.
This commit is contained in:
David Turner 2005-03-15 18:18:57 +00:00
parent 1dbcbabf6d
commit 68df4f732d
6 changed files with 331 additions and 286 deletions

View File

@ -1,3 +1,12 @@
2005-03-15 David Turner <david@freetype.org>
* src/lzw/ftlzw.c (FT_Stream_OpenLZW): modified the function to check
the LZW header before doing anything else. This helps avoid un-necessary
heap allocations (400 Kb of heap memory for the LZW decoder ! Oh my !)
* src/gzip/ftgzip.c (FT_Stream_OpenGZip): ditto for the .gz decoder,
though the code savings is smaller.
2005-03-10 David Turner <david@freetype.org>
* src/tools/glnames.py: Add comment to explain the compression

View File

@ -343,7 +343,7 @@ FT_BEGIN_HEADER
/* free a stream */
FT_BASE( void )
FT_Stream_Free( FT_Stream stream,
FT_Stream_Free( FT_Stream stream,
FT_Int external );
/* initialize a stream for reading in-memory data */
@ -385,6 +385,14 @@ FT_BEGIN_HEADER
FT_Byte* buffer,
FT_ULong count );
/* try to read bytes at the end of a stream, return
* the number of bytes really available
*/
FT_BASE( FT_ULong )
FT_Stream_TryRead( FT_Stream stream,
FT_Byte* buffer,
FT_ULong count );
/* Enter a frame of `count' consecutive bytes in a stream. Returns an */
/* error if the frame could not be read/accessed. The caller can use */
/* the FT_Stream_Get_XXX functions to retrieve frame data without */

View File

@ -153,6 +153,35 @@
}
FT_BASE_DEF( FT_ULong )
FT_Stream_TryRead( FT_Stream stream,
FT_Byte* buffer,
FT_ULong count )
{
FT_ULong read_bytes = 0;
if ( stream->pos >= stream->size )
goto Exit;
if ( stream->read )
read_bytes = stream->read( stream, stream->pos, buffer, count );
else
{
read_bytes = stream->size - stream->pos;
if ( read_bytes > count )
read_bytes = count;
FT_MEM_COPY( buffer, stream->base + stream->pos, read_bytes );
}
stream->pos += read_bytes;
Exit:
return read_bytes;
}
FT_BASE_DEF( FT_Error )
FT_Stream_ExtractFrame( FT_Stream stream,
FT_ULong count,

View File

@ -224,7 +224,6 @@
if ( FT_NEW_ARRAY( ht->table, ht->size ) )
goto Exit;
FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * ht->size );
for ( i = 0, bp = obp; i < sz; i++, bp++ )
{
@ -255,7 +254,6 @@
if ( FT_NEW_ARRAY( ht->table, sz ) )
goto Exit;
FT_MEM_ZERO( ht->table, sizeof ( hashnode ) * sz );
Exit:
return error;
@ -351,6 +349,7 @@
char** field;
unsigned long size;
unsigned long used;
FT_Memory memory;
} _bdf_list_t;
@ -389,20 +388,123 @@
#define sbitset( m, cc ) ( m[(cc) >> 3] & ( 1 << ( (cc) & 7 ) ) )
static void
_bdf_list_init( _bdf_list_t* list,
FT_Memory memory )
{
FT_ZERO(list);
list->memory = memory;
}
static void
_bdf_list_done( _bdf_list_t* list )
{
FT_Memory memory = list->memory;
if ( memory )
{
FT_FREE( list->field );
FT_ZERO(list);
}
}
static FT_Error
_bdf_list_ensure( _bdf_list_t* list,
int num_items )
{
FT_Error error = 0;
if ( num_items > list->size )
{
int oldsize = list->size;
int newsize = oldsize + (oldsize >> 1) + 4;
int bigsize = FT_INT_MAX / sizeof(char*);
FT_Memory memory = list->memory;
if ( oldsize == bigsize )
{
error = FT_Err_Out_Of_Memory;
goto Exit;
}
else if ( newsize < oldsize || newsize > bigsize )
newsize = bigsize;
if ( FT_RENEW_ARRAY( list->field, oldsize, newsize ) )
goto Exit;
list->size = newsize;
}
Exit:
return error;
}
static void
_bdf_list_shift( _bdf_list_t* list,
unsigned long n )
{
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_list_join( _bdf_list_t* list,
int c,
unsigned long *alen )
{
unsigned long i, j;
char *fp, *dp;
*alen = 0;
if ( list == 0 || list->used == 0 )
return 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++] = (char)c;
}
dp[j] = 0;
*alen = j;
return dp;
}
/* 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 )
_bdf_list_split( _bdf_list_t* list,
char* separators,
char* line,
unsigned long linelen )
{
int mult, final_empty;
char *sp, *ep, *end;
@ -451,20 +553,9 @@
/* Resize the list if necessary. */
if ( list->used == list->size )
{
if ( list->size == 0 )
{
if ( FT_NEW_ARRAY( list->field, 5 ) )
goto Exit;
}
else
{
if ( FT_RENEW_ARRAY ( list->field ,
list->size,
list->size + 5 ) )
goto Exit;
}
list->size += 5;
error = _bdf_list_ensure( list, list->used+1 );
if ( error )
goto Exit;
}
/* Assign the field appropriately. */
@ -489,48 +580,16 @@
}
/* Finally, NULL-terminate the list. */
if ( list->used + final_empty + 1 >= list->size )
if ( list->used + final_empty >= list->size )
{
if ( list->used == list->size )
{
if ( list->size == 0 )
{
if ( FT_NEW_ARRAY( list->field, 5 ) )
goto Exit;
}
else
{
if ( FT_RENEW_ARRAY( list->field,
list->size,
list->size + 5 ) )
goto Exit;
}
list->size += 5;
}
error = _bdf_list_ensure( list, list->used+final_empty+1 );
if ( error )
goto Exit;
}
if ( final_empty )
list->field[list->used++] = (char*)empty;
if ( list->used == list->size )
{
if ( list->size == 0 )
{
if ( FT_NEW_ARRAY( list->field, 5 ) )
goto Exit;
}
else
{
if ( FT_RENEW_ARRAY( list->field,
list->size,
list->size + 5 ) )
goto Exit;
}
list->size += 5;
}
list->field[list->used] = 0;
Exit:
@ -538,100 +597,8 @@
}
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++] = (char)c;
}
dp[j] = 0;
*len = j;
return dp;
}
/* High speed file reader that passes each line to a callback. */
static FT_Error
bdf_internal_readstream( FT_Stream stream,
char* buffer,
int count,
int *read_bytes )
{
int rbytes;
unsigned long pos = stream->pos;
FT_Error error = BDF_Err_Ok;
if ( pos > stream->size )
{
FT_ERROR(( "bdf_internal_readstream:" ));
FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
pos, stream->size ));
error = BDF_Err_Invalid_Stream_Operation;
goto Exit;
}
if ( stream->read )
rbytes = stream->read( stream, pos,
(unsigned char *)buffer, count );
else
{
rbytes = stream->size - pos;
if ( rbytes > count )
rbytes = count;
FT_MEM_COPY( buffer, stream->base + pos, rbytes );
}
stream->pos = pos + rbytes;
*read_bytes = rbytes;
Exit:
return error;
}
#define NO_SKIP 256 /* this value cannot be stored in a 'char' */
static FT_Error
_bdf_readstream( FT_Stream stream,
@ -640,10 +607,10 @@
unsigned long *lno )
{
_bdf_line_func_t cb;
unsigned long lineno;
int n, done, refill, bytes, hold;
char *ls, *le, *pp, *pe, *hp;
char *buf = 0;
unsigned long lineno, buf_size;
int refill, bytes, hold, to_skip;
int start, end, cursor, avail;
char* buf = 0;
FT_Memory memory = stream->memory;
FT_Error error = BDF_Err_Ok;
@ -654,85 +621,115 @@
goto Exit;
}
if ( FT_NEW_ARRAY( buf, 65536L ) )
/* initial size and allocation of the input buffer
*/
buf_size = 1024;
if ( FT_NEW_ARRAY( buf, buf_size ) )
goto Exit;
cb = callback;
lineno = 1;
buf[0] = 0;
cb = callback;
lineno = 1;
buf[0] = 0;
start = 0;
end = 0;
avail = 0;
cursor = 0;
refill = 1;
to_skip = NO_SKIP;
done = 0;
pp = ls = le = buf;
bytes = 65536L;
while ( !done )
for (;;)
{
error = bdf_internal_readstream( stream, pp, bytes, &n );
if ( error )
goto Exit;
if ( n == 0 )
break;
/* Determine the new end of the buffer pages. */
pe = pp + n;
for ( refill = 0; done == 0 && refill == 0; )
if ( refill )
{
while ( le < pe && *le != '\n' && *le != '\r' )
le++;
bytes = (int) FT_Stream_TryRead( stream, buf + cursor,
(FT_ULong)(buf_size - cursor) );
avail = cursor + bytes;
cursor = 0;
refill = 0;
}
if ( le == pe )
end = start;
/* should we skip an optional character like \n or \r ? */
if ( start < avail && buf[start] == to_skip )
{
start += 1;
to_skip = NO_SKIP;
continue;
}
/* try to find the end of the line */
while ( end < avail && buf[end] != '\n' && buf[end] != '\r' )
end++;
/* if we hit the end of the buffer, try shifting its content
* or even resizing it
*/
if ( end >= avail )
{
if ( bytes == 0 ) /* last line in file doesn't end in \r or \n */
break; /* ignore it then exit */
if ( start == 0 )
{
/* 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. */
/* this line is definitely too long, try resizing the input buffer
* a bit to handle it.
*/
FT_ULong new_size;
pp = buf + ( ( ( ls - buf ) >> 13 ) << 13 );
n = pp - buf;
ls -= n;
le -= n;
n = pe - pp;
if ( buf_size >= 65536UL ) /* limit ourselves to 64 Kb */
{
error = BDF_Err_Invalid_Argument;
goto Exit;
}
FT_MEM_MOVE( buf, pp, n );
new_size = buf_size*2;
if ( FT_RENEW_ARRAY( buf, buf_size, new_size ) )
goto Exit;
pp = buf + n;
bytes = 65536L - n;
refill = 1;
cursor = buf_size;
buf_size = new_size;
}
else
{
/* Temporarily NULL-terminate the line. */
hp = le;
hold = *le;
*le = 0;
bytes = avail - start;
/* XXX: Use encoding independent value for 0x1a */
if ( *ls != '#' && *ls != 0x1a &&
le > ls &&
( error = (*cb)( ls, le - ls, lineno, (void *)&cb,
client_data ) ) != BDF_Err_Ok )
done = 1;
else
{
ls = ++le;
/* Handle the case of DOS crlf sequences. */
if ( le < pe && hold == '\n' && *le =='\r' )
ls = ++le;
}
FT_MEM_COPY( buf, buf+start, bytes );
/* Increment the line number. */
lineno++;
/* Restore the character at the end of the line. */
*hp = (char)hold;
cursor = bytes;
avail -= bytes;
start = 0;
}
refill = 1;
continue;
}
/* Temporarily NUL-terminate the line. */
hold = buf[end];
buf[end] = 0;
/* XXX: Use encoding independent value for 0x1a */
if ( buf[start] != '#' && buf[start] != 0x1a && end > start )
{
error = (*cb)( buf+start, end-start, lineno, (void*)&cb, client_data );
if ( error )
break;
}
lineno += 1;
buf[end] = (char)hold;
start = end+1;
if ( hold == '\n' )
to_skip = '\r';
else if ( hold == '\r' )
to_skip = '\n';
else
to_skip = NO_SKIP;
}
*lno = lineno;
*lno = lineno;
Exit:
FT_FREE( buf );
@ -955,7 +952,8 @@
if ( c1->encoding < c2->encoding )
return -1;
else if ( c1->encoding > c2->encoding )
if ( c1->encoding > c2->encoding )
return 1;
return 0;
@ -979,23 +977,16 @@
if ( hash_lookup( name, &(font->proptbl) ) )
goto Exit;
if ( font->nuser_props == 0 )
{
if ( FT_NEW_ARRAY( font->user_props, 1 ) )
goto Exit;
}
else
{
if ( FT_RENEW_ARRAY( font->user_props,
font->nuser_props,
font->nuser_props + 1 ) )
goto Exit;
}
if ( FT_RENEW_ARRAY( font->user_props,
font->nuser_props,
font->nuser_props + 1 ) )
goto Exit;
p = font->user_props + font->nuser_props;
FT_MEM_ZERO( p, sizeof ( bdf_property_t ) );
FT_ZERO( p );
n = (unsigned long)( ft_strlen( name ) + 1 );
if ( FT_NEW_ARRAY( p->name, n ) )
goto Exit;
@ -1110,23 +1101,16 @@
FT_Error error = BDF_Err_Ok;
if ( font->comments_len == 0 )
{
if ( FT_NEW_ARRAY( font->comments, len + 1 ) )
goto Exit;
}
else
{
if ( FT_RENEW_ARRAY( font->comments,
font->comments_len,
font->comments_len + len + 1 ) )
goto Exit;
}
if ( FT_RENEW_ARRAY( font->comments,
font->comments_len,
font->comments_len + len + 1 ) )
goto Exit;
cp = font->comments + font->comments_len;
FT_MEM_COPY( cp, comment, len );
cp += len;
*cp++ = '\n';
cp[len] = '\n';
font->comments_len += len + 1;
Exit:
@ -1155,16 +1139,16 @@
memory = font->memory;
_bdf_list_init( &list, memory );
font->spacing = opts->font_spacing;
len = (unsigned long)( ft_strlen( font->name ) + 1 );
FT_MEM_COPY( name, font->name, len );
list.size = list.used = 0;
error = _bdf_split( (char *)"-", name, len, &list, memory );
error = _bdf_list_split( &list, (char *)"-", name, len );
if ( error )
goto Exit;
goto Fail;
if ( list.used == 15 )
{
@ -1185,7 +1169,8 @@
}
}
FT_FREE( list.field );
Fail:
_bdf_list_done( &list );
Exit:
return error;
@ -1484,7 +1469,7 @@
goto Exit;
}
error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
p->cnt = font->glyphs_size = _bdf_atoul( p->list.field[1], 0, 10 );
@ -1538,15 +1523,17 @@
/* encoding can be checked for an unencoded character. */
FT_FREE( p->glyph_name );
error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
_bdf_shift( 1, &p->list );
s = _bdf_join( ' ', &slen, &p->list );
_bdf_list_shift( &p->list, 1 );
s = _bdf_list_join( &p->list, ' ', &slen );
if ( FT_NEW_ARRAY( p->glyph_name, slen + 1 ) )
goto Exit;
FT_MEM_COPY( p->glyph_name, s, slen + 1 );
p->flags |= _BDF_GLYPH;
@ -1565,9 +1552,10 @@
goto Exit;
}
error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
p->glyph_enc = _bdf_atol( p->list.field[1], 0, 10 );
/* Check to see whether this encoding has already been encountered. */
@ -1598,8 +1586,7 @@
font->glyphs_size,
font->glyphs_size + 64 ) )
goto Exit;
FT_MEM_ZERO( font->glyphs + font->glyphs_size,
sizeof ( bdf_glyph_t ) * 64 ); /* FZ inutile */
font->glyphs_size += 64;
}
@ -1619,18 +1606,11 @@
/* Allocate the next unencoded glyph. */
if ( font->unencoded_used == font->unencoded_size )
{
if ( font->unencoded_size == 0 )
{
if ( FT_NEW_ARRAY( font->unencoded, 4 ) )
goto Exit;
}
else
{
if ( FT_RENEW_ARRAY( font->unencoded ,
font->unencoded_size,
font->unencoded_size + 4 ) )
goto Exit;
}
if ( FT_RENEW_ARRAY( font->unencoded ,
font->unencoded_size,
font->unencoded_size + 4 ) )
goto Exit;
font->unencoded_size += 4;
}
@ -1719,9 +1699,10 @@
goto Exit;
}
error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
glyph->swidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
p->flags |= _BDF_SWIDTH;
@ -1731,9 +1712,10 @@
/* Expect the DWIDTH (scalable width) field next. */
if ( ft_memcmp( line, "DWIDTH", 6 ) == 0 )
{
error = _bdf_split( (char *)" +", line, linelen, &p->list,memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
glyph->dwidth = (unsigned short)_bdf_atoul( p->list.field[1], 0, 10 );
if ( !( p->flags & _BDF_SWIDTH ) )
@ -1755,7 +1737,7 @@
/* Expect the BBX field next. */
if ( ft_memcmp( line, "BBX", 3 ) == 0 )
{
error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
@ -1936,13 +1918,13 @@
}
else
{
error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
name = p->list.field[0];
_bdf_shift( 1, &p->list );
value = _bdf_join( ' ', &vlen, &p->list );
_bdf_list_shift( &p->list, 1 );
value = _bdf_list_join( &p->list, ' ', &vlen );
error = _bdf_add_property( p->font, name, value );
if ( error )
@ -2057,7 +2039,7 @@
/* Check for the start of the properties. */
if ( ft_memcmp( line, "STARTPROPERTIES", 15 ) == 0 )
{
error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
p->cnt = p->font->props_size = _bdf_atoul( p->list.field[1], 0, 10 );
@ -2082,7 +2064,7 @@
goto Exit;
}
error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
@ -2105,12 +2087,12 @@
/* The next thing to check for is the FONT field. */
if ( ft_memcmp( line, "FONT", 4 ) == 0 )
{
error = _bdf_split( (char *)" +", line, linelen, &p->list , memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
_bdf_shift( 1, &p->list );
_bdf_list_shift( &p->list, 1 );
s = _bdf_join( ' ', &slen, &p->list );
s = _bdf_list_join( &p->list, ' ', &slen );
if ( FT_NEW_ARRAY( p->font->name, slen + 1 ) )
goto Exit;
FT_MEM_COPY( p->font->name, s, slen + 1 );
@ -2137,7 +2119,7 @@
goto Exit;
}
error = _bdf_split( (char *)" +", line, linelen, &p->list, memory );
error = _bdf_list_split( &p->list, (char *)" +", line, linelen );
if ( error )
goto Exit;
@ -2207,7 +2189,7 @@
FT_Error error = BDF_Err_Ok;
if ( FT_ALLOC( p, sizeof ( _bdf_parse_t ) ) )
if ( FT_NEW( p ) )
goto Exit;
memory = NULL;
@ -2215,6 +2197,8 @@
p->minlb = 32767;
p->memory = extmemory; /* only during font creation */
_bdf_list_init( &p->list, extmemory );
error = _bdf_readstream( stream, _bdf_parse_start,
(void *)p, &lineno );
if ( error )
@ -2301,10 +2285,6 @@
}
}
/* Free up the list used during the parsing. */
if ( memory != NULL )
FT_FREE( p->list.field );
if ( p->font != 0 )
{
/* Make sure the comments are NULL terminated if they exist. */
@ -2327,7 +2307,10 @@
Exit:
if ( p )
{
_bdf_list_done( &p->list );
memory = extmemory;
FT_FREE( p );
}

View File

@ -561,6 +561,12 @@
FT_Memory memory = source->memory;
FT_GZipFile zip;
/* check the header right now, this prevents allocating un-necessary
* objects when we don't need them
*/
error = ft_gzip_check_header( source );
if ( error )
goto Exit;
FT_ZERO( stream );
stream->memory = memory;

View File

@ -414,6 +414,16 @@
FT_Memory memory = source->memory;
FT_LZWFile zip;
/* check the header right now, this will prevent us from
* allocating a huge LZWFile object (400 Kb of heap memory !!)
* when not necessary.
*
* Did I mention that you should never use .Z compressed font
* file ?
*/
error = ft_lzw_check_header( source );
if ( error )
goto Exit;
FT_ZERO( stream );
stream->memory = memory;