mirror of
git://git.savannah.gnu.org/freetype/freetype2.git
synced 2025-04-11 22:56:50 +02:00
325 lines
7.3 KiB
C
325 lines
7.3 KiB
C
/* memtest.c */
|
|
|
|
#include <freetype/freetype.h>
|
|
#include <freetype/internal/ftobjs.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
FT_Error error;
|
|
|
|
FT_Library library;
|
|
FT_Face face;
|
|
FT_Size size;
|
|
FT_GlyphSlot slot;
|
|
|
|
unsigned int num_glyphs;
|
|
int ptsize;
|
|
|
|
int Fail;
|
|
int Num;
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
/****************************************************************************/
|
|
/****************************************************************************/
|
|
/****************************************************************************/
|
|
|
|
/* Our own memory allocator. To check that a single block isn't freed */
|
|
/* several time, we simply do not call "free".. */
|
|
|
|
#define MAX_RECORDED_BLOCKS 1638400
|
|
#define CHECK_DUPLICATES
|
|
|
|
typedef struct MyBlock
|
|
{
|
|
void* base;
|
|
long size;
|
|
|
|
} MyBlock;
|
|
|
|
static MyBlock my_blocks[ MAX_RECORDED_BLOCKS ];
|
|
static int num_my_blocks = 0;
|
|
|
|
/* record a new block in the table, check for duplicates too */
|
|
static
|
|
void record_my_block( void* base, long size )
|
|
{
|
|
if (size <= 0)
|
|
{
|
|
fprintf( stderr, "adding a block with non-positive length - should not happen \n" );
|
|
exit(1);
|
|
}
|
|
|
|
if ( num_my_blocks < MAX_RECORDED_BLOCKS )
|
|
{
|
|
MyBlock* block;
|
|
|
|
#ifdef CHECK_DUPLICATES
|
|
MyBlock* limit;
|
|
block = my_blocks;
|
|
limit = block + num_my_blocks;
|
|
for ( ; block < limit; block++ )
|
|
{
|
|
if ( block->base == base && block->size != 0 )
|
|
{
|
|
fprintf( stderr, "duplicate memory block at %08lx\n", (long)block->base );
|
|
exit(1);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
block = my_blocks + num_my_blocks++;
|
|
block->base = base;
|
|
block->size = size;
|
|
}
|
|
else
|
|
{
|
|
fprintf( stderr, "Too many memory blocks -- test exited !!\n" );
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/* forget a block, and check that it isn't part of our table already */
|
|
static
|
|
void forget_my_block( void* base )
|
|
{
|
|
MyBlock* block = my_blocks + num_my_blocks-1;
|
|
|
|
/* we scan in reverse, because transient blocks are always located */
|
|
/* at the end of the table.. (it supposedly faster then..) */
|
|
for ( ; block >= my_blocks; block-- )
|
|
{
|
|
if ( block->base == base )
|
|
{
|
|
if (block->size > 0)
|
|
{
|
|
block->size = 0;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
fprintf( stderr, "Block at %08lx released twice \n", (long)base );
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
fprintf( stderr, "Trying to release an unallocated block at %08lx\n",
|
|
(long)base );
|
|
exit(1);
|
|
}
|
|
|
|
|
|
static
|
|
void* my_alloc( FT_Memory memory,
|
|
long size )
|
|
{
|
|
void* p = malloc(size);
|
|
if (p)
|
|
record_my_block(p,size);
|
|
|
|
return p;
|
|
}
|
|
|
|
static
|
|
void my_free( FT_Memory memory, void* block )
|
|
{
|
|
forget_my_block(block);
|
|
free(block);
|
|
}
|
|
|
|
static
|
|
void* my_realloc( FT_Memory memory,
|
|
long cur_size,
|
|
long new_size,
|
|
void* block )
|
|
{
|
|
void* p;
|
|
|
|
p = my_alloc( memory, new_size );
|
|
if (p)
|
|
{
|
|
my_free( memory, block );
|
|
record_my_block( p, new_size );
|
|
}
|
|
return p;
|
|
}
|
|
|
|
|
|
struct FT_MemoryRec_ my_memory =
|
|
{
|
|
0,
|
|
my_alloc,
|
|
my_free,
|
|
my_realloc
|
|
};
|
|
|
|
static void dump_mem( void )
|
|
{
|
|
MyBlock* block = my_blocks + num_my_blocks-1;
|
|
int bad = 0;
|
|
|
|
printf( "total allocated blocks = %d\n", num_my_blocks );
|
|
|
|
/* we scan in reverse, because transient blocks are always located */
|
|
/* at the end of the table.. (it supposedly faster then..) */
|
|
for ( ; block >= my_blocks; block-- )
|
|
{
|
|
if (block->size > 0)
|
|
{
|
|
fprintf( stderr, "%08lx (%6ld bytes) leaked !!\n", (long)block->base, (long)block->size );
|
|
bad = 1;
|
|
}
|
|
}
|
|
if (!bad)
|
|
fprintf( stderr, "no leaked memory block, congratulations ;-)" );
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/****************************************************************************/
|
|
/****************************************************************************/
|
|
/****************************************************************************/
|
|
|
|
|
|
static void Usage( char* name )
|
|
{
|
|
printf( "memtest: simple memory tester -- part of the FreeType project\n" );
|
|
printf( "-------------------------------------------------------------\n" );
|
|
printf( "\n" );
|
|
printf( "Usage: %s ppem fontname[.ttf|.ttc] [fontname2..]\n", name );
|
|
printf( "\n" );
|
|
|
|
exit( 1 );
|
|
}
|
|
|
|
|
|
static void Panic( const char* message )
|
|
{
|
|
fprintf( stderr, "%s\n error code = 0x%04x\n", message, error );
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int main( int argc, char** argv )
|
|
{
|
|
int i, file_index;
|
|
unsigned int id;
|
|
char filename[128 + 4];
|
|
char alt_filename[128 + 4];
|
|
char* execname;
|
|
char* fname;
|
|
|
|
execname = argv[0];
|
|
|
|
if ( argc < 3 )
|
|
Usage( execname );
|
|
|
|
if ( sscanf( argv[1], "%d", &ptsize ) != 1 )
|
|
Usage( execname );
|
|
|
|
/* Create a new library with our own memory manager */
|
|
error = FT_New_Library( &my_memory, &library );
|
|
if (error) Panic( "Could not create library object" );
|
|
|
|
/* the new library has no drivers in it, add the default ones */
|
|
/* (implemented in ftinit.c).. */
|
|
FT_Default_Drivers(library);
|
|
|
|
|
|
/* Now check all files */
|
|
for ( file_index = 2; file_index < argc; file_index++ )
|
|
{
|
|
fname = argv[file_index];
|
|
i = strlen( fname );
|
|
while ( i > 0 && fname[i] != '\\' && fname[i] != '/' )
|
|
{
|
|
if ( fname[i] == '.' )
|
|
i = 0;
|
|
i--;
|
|
}
|
|
|
|
filename[128] = '\0';
|
|
alt_filename[128] = '\0';
|
|
|
|
strncpy( filename, fname, 128 );
|
|
strncpy( alt_filename, fname, 128 );
|
|
|
|
#ifndef macintosh
|
|
if ( i >= 0 )
|
|
{
|
|
strncpy( filename + strlen( filename ), ".ttf", 4 );
|
|
strncpy( alt_filename + strlen( alt_filename ), ".ttc", 4 );
|
|
}
|
|
#endif
|
|
i = strlen( filename );
|
|
fname = filename;
|
|
|
|
while ( i >= 0 )
|
|
#ifndef macintosh
|
|
if ( filename[i] == '/' || filename[i] == '\\' )
|
|
#else
|
|
if ( filename[i] == ':' )
|
|
#endif
|
|
{
|
|
fname = filename + i + 1;
|
|
i = -1;
|
|
}
|
|
else
|
|
i--;
|
|
|
|
printf( "%s: ", fname );
|
|
|
|
/* Load face */
|
|
error = FT_New_Face( library, filename, 0, &face );
|
|
if (error)
|
|
{
|
|
if (error == FT_Err_Invalid_File_Format)
|
|
printf( "unknown format\n" );
|
|
else
|
|
printf( "could not find/open file (error: %d)\n", error );
|
|
continue;
|
|
}
|
|
if (error) Panic( "Could not open file" );
|
|
|
|
num_glyphs = face->num_glyphs;
|
|
|
|
error = FT_Set_Char_Size( face, ptsize << 6, ptsize << 6, 72, 72 );
|
|
if (error) Panic( "Could not set character size" );
|
|
|
|
Fail = 0;
|
|
{
|
|
for ( id = 0; id < num_glyphs; id++ )
|
|
{
|
|
error = FT_Load_Glyph( face, id, FT_LOAD_DEFAULT );
|
|
if (error)
|
|
{
|
|
if ( Fail < 10 )
|
|
printf( "glyph %4u: 0x%04x\n" , id, error );
|
|
Fail++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Fail == 0 )
|
|
printf( "OK.\n" );
|
|
else
|
|
if ( Fail == 1 )
|
|
printf( "1 fail.\n" );
|
|
else
|
|
printf( "%d fails.\n", Fail );
|
|
|
|
FT_Done_Face( face );
|
|
}
|
|
|
|
FT_Done_FreeType(library);
|
|
|
|
dump_mem();
|
|
|
|
exit( 0 ); /* for safety reasons */
|
|
return 0; /* never reached */
|
|
}
|
|
|
|
|
|
|