32#define _XOPEN_SOURCE 600
53#define forever for (;;)
56 static int check_outlines =
false;
57 static int nohints =
false;
58 static int rasterize =
false;
59 static char* results_dir =
"results";
61#define GOOD_FONTS_DIR "/usr/local/share/fonts"
63 static char* default_dir_list[] =
69 static char* default_ext_list[] =
86 static unsigned int error_count = 1;
87 static double error_fraction = 0.0;
89 static FT_F26Dot6 font_size = 12 * 64;
91 static struct fontlist
95 unsigned int isbinary: 1;
96 unsigned int isascii: 1;
97 unsigned int ishex: 1;
101 static unsigned int fcnt;
105 FT_MoveTo(
const FT_Vector *to,
116 FT_LineTo(
const FT_Vector *to,
127 FT_ConicTo(
const FT_Vector *_cp,
140 FT_CubicTo(
const FT_Vector *cp1,
141 const FT_Vector *cp2,
154 static FT_Outline_Funcs outlinefuncs =
165 TestFace( FT_Face face )
168 int load_flags = FT_LOAD_DEFAULT;
171 if ( check_outlines &&
172 FT_IS_SCALABLE( face ) )
173 load_flags = FT_LOAD_NO_BITMAP;
176 load_flags |= FT_LOAD_NO_HINTING;
178 FT_Set_Char_Size( face, 0, font_size, 72, 72 );
180 for ( gid = 0; gid < face->num_glyphs; gid++ )
182 if ( check_outlines &&
183 FT_IS_SCALABLE( face ) )
185 if ( !FT_Load_Glyph( face, gid, load_flags ) )
186 FT_Outline_Decompose( &face->glyph->outline, &outlinefuncs, NULL );
189 FT_Load_Glyph( face, gid, load_flags );
192 FT_Render_Glyph( face->glyph, ft_render_mode_normal );
195 FT_Done_Face( face );
200 ExecuteTest(
char* testfont )
206 if ( FT_Init_FreeType( &context ) )
208 fprintf( stderr,
"Can't initialize FreeType.\n" );
212 if ( FT_New_Face( context, testfont, 0, &face ) )
218 if ( face->num_faces == 1 )
225 num = face->num_faces;
226 FT_Done_Face( face );
228 for ( i = 0; i < num; i++ )
230 if ( !FT_New_Face( context, testfont, i, &face ) )
235 FT_Done_FreeType( context );
242 extmatch(
char* filename,
252 pt = strrchr( filename,
'.' );
255 if ( pt < strrchr( filename,
'/' ) )
258 for ( i = 0; extensions[i] != NULL; i++ )
259 if ( strcasecmp( pt + 1, extensions[i] ) == 0 ||
260 strcasecmp( pt, extensions[i] ) == 0 )
268 figurefiletype(
struct fontlist* item )
273 item->isbinary = item->isascii = item->ishex =
false;
275 foo = fopen( item->name,
"rb" );
279 int ch1 = getc( foo );
280 int ch2 = getc( foo );
281 int ch3 = getc( foo );
282 int ch4 = getc( foo );
287 if ( ( ch1 == 0 && ch2 == 1 && ch3 == 0 && ch4 == 0 ) ||
288 ( ch1 ==
'O' && ch2 ==
'T' && ch3 ==
'T' && ch4 ==
'O' ) ||
289 ( ch1 ==
't' && ch2 ==
'r' && ch3 ==
'u' && ch4 ==
'e' ) ||
290 ( ch1 ==
't' && ch2 ==
't' && ch3 ==
'c' && ch4 ==
'f' ) )
293 item->isbinary =
true;
295 else if ( ch1 == 0x80 && ch2 ==
'\01' )
298 item->isbinary =
true;
300 else if ( ch1 ==
'%' && ch2 ==
'!' )
303 if ( strstr( item->name,
".pfa" ) ||
304 strstr( item->name,
".PFA" ) )
307 item->isascii =
true;
309 else if ( ch1 == 1 && ch2 == 0 && ch3 == 4 )
312 item->isbinary =
true;
314 else if ( ch1 ==
'S' && ch2 ==
'T' && ch3 ==
'A' && ch4 ==
'R' )
319 else if ( ch1 ==
'P' && ch2 ==
'F' && ch3 ==
'R' && ch4 ==
'0' )
322 item->isbinary =
true;
324 else if ( ( ch1 ==
'\1' && ch2 ==
'f' && ch3 ==
'c' && ch4 ==
'p' ) ||
325 ( ch1 ==
'M' && ch2 ==
'Z' ) )
328 item->isbinary =
true;
333 "Can't recognize file type of `%s', assuming binary\n",
335 item->isbinary =
true;
340 fprintf( stderr,
"Can't open `%s' for typing the file.\n",
342 item->isbinary =
true;
348 FindFonts(
char** fontdirs,
360 for ( i = 0; fontdirs[i] != NULL; i++ )
366 examples = opendir( fontdirs[i] );
370 "Can't open example font directory `%s'\n",
375 while ( ( ent = readdir( examples ) ) != NULL )
377 snprintf( buffer,
sizeof ( buffer ),
378 "%s/%s", fontdirs[i], ent->d_name );
379 if ( stat( buffer, &statb ) == -1 || S_ISDIR( statb.st_mode ) )
381 if ( !extensions || extmatch( buffer, extensions ) )
386 fontlist = realloc( fontlist, max *
sizeof (
struct fontlist ) );
389 fprintf( stderr,
"Can't allocate memory\n" );
394 fontlist[fcnt].name = strdup( buffer );
395 fontlist[fcnt].len = statb.st_size;
397 figurefiletype( &fontlist[fcnt] );
402 closedir( examples );
407 fprintf( stderr,
"Can't find matching font files.\n" );
411 fontlist[fcnt].name = NULL;
416 getErrorCnt(
struct fontlist* item )
418 if ( error_count == 0 && error_fraction == 0.0 )
421 return error_count + (
unsigned int)( error_fraction * item->len );
429 if ( low - high < 0x10000L )
430 return low + ( ( random() >> 8 ) % ( high + 1 - low ) );
432 return low + ( random() % ( high + 1 - low ) );
437 copyfont(
struct fontlist* item,
440 static char buffer[8096];
443 unsigned int i, err_cnt;
446 good = fopen( item->name,
"r" );
449 fprintf( stderr,
"Can't open `%s'\n", item->name );
453 newf = fopen( newfont,
"w+" );
456 fprintf( stderr,
"Can't create temporary output file `%s'\n",
461 while ( ( len = fread( buffer, 1,
sizeof ( buffer ), good ) ) > 0 )
462 fwrite( buffer, 1, len, newf );
466 err_cnt = getErrorCnt( item );
467 for ( i = 0; i < err_cnt; i++ )
469 fseek( newf, getRandom( 0, (
int)( item->len - 1 ) ), SEEK_SET );
471 if ( item->isbinary )
472 putc( getRandom( 0, 0xFF ), newf );
473 else if ( item->isascii )
474 putc( getRandom( 0x20, 0x7E ), newf );
477 int hex = getRandom( 0, 15 );
489 if ( ferror( newf ) )
502 static int child_pid;
505 abort_test(
int sig )
510 kill( child_pid, SIGFPE );
511 write( 2,
"Timeout... ", 11 );
518 int i = getRandom( 0, (
int)( fcnt - 1 ) );
519 static int test_num = 0;
523 snprintf( buffer, 1024,
"%s/test%d", results_dir, test_num++ );
525 if ( copyfont ( &fontlist[i], buffer ) )
527 signal( SIGALRM, abort_test );
531 if ( ( child_pid = fork() ) == 0 )
532 ExecuteTest( buffer );
533 else if ( child_pid != -1 )
538 waitpid( child_pid, &status, 0 );
540 if ( WIFSIGNALED ( status ) )
541 printf(
"Error found in file `%s'\n", buffer );
547 fprintf( stderr,
"Can't fork test case.\n" );
559 char** d = default_dir_list;
560 char** e = default_ext_list;
563 fprintf( out,
"%s [options] -- Generate random erroneous fonts\n"
564 " and attempt to parse them with FreeType.\n\n", name );
566 fprintf( out,
" --all All non-directory files are assumed to be fonts.\n" );
567 fprintf( out,
" --check-outlines Make sure we can parse the outlines of each glyph.\n" );
568 fprintf( out,
" --dir <path> Append <path> to list of font search directories\n"
569 " (no recursive search).\n" );
570 fprintf( out,
" --error-count <cnt> Introduce <cnt> single byte errors into each font\n"
572 fprintf( out,
" --error-fraction <frac> Introduce <frac>*filesize single byte errors\n"
573 " into each font (default: 0.0).\n" );
574 fprintf( out,
" --ext <ext> Add <ext> to list of extensions indicating fonts.\n" );
575 fprintf( out,
" --help Print this.\n" );
576 fprintf( out,
" --nohints Turn off hinting.\n" );
577 fprintf( out,
" --rasterize Attempt to rasterize each glyph.\n" );
578 fprintf( out,
" --results <path> Place the created test fonts into <path>\n"
579 " (default: `results')\n" );
580 fprintf( out,
" --size <float> Use the given font size for the tests.\n" );
581 fprintf( out,
" --test <file> Run a single test on an already existing file.\n" );
582 fprintf( out,
"\n" );
584 fprintf( out,
"Default font extensions:\n" );
587 fprintf( out,
" .%s", *e++ );
588 fprintf( out,
"\n" );
590 fprintf( out,
"Default font directories:\n" );
593 fprintf( out,
" %s", *d++ );
594 fprintf( out,
"\n" );
603 int dcnt = 0, ecnt = 0, rset =
false, allexts =
false;
606 char* testfile = NULL;
609 dirs = calloc( (
size_t)( argc + 1 ),
sizeof (
char ** ) );
610 exts = calloc( (
size_t)( argc + 1 ),
sizeof (
char ** ) );
612 for ( i = 1; i < argc; i++ )
618 if ( pt[0] ==
'-' && pt[1] ==
'-' )
621 if ( strcmp( pt,
"-all" ) == 0 )
623 else if ( strcmp( pt,
"-check-outlines" ) == 0 )
624 check_outlines =
true;
625 else if ( strcmp( pt,
"-dir" ) == 0 )
626 dirs[dcnt++] = argv[++i];
627 else if ( strcmp( pt,
"-error-count" ) == 0 )
630 error_fraction = 0.0;
632 error_count = (
unsigned int)strtoul( argv[++i], &end, 10 );
635 fprintf( stderr,
"Bad value for error-count: %s\n", argv[i] );
639 else if ( strcmp( pt,
"-error-fraction" ) == 0 )
644 error_fraction = strtod( argv[++i], &end );
647 fprintf( stderr,
"Bad value for error-fraction: %s\n", argv[i] );
650 if ( error_fraction < 0.0 || error_fraction > 1.0 )
652 fprintf( stderr,
"error-fraction must be in the range [0;1]\n" );
656 else if ( strcmp( pt,
"-ext" ) == 0 )
657 exts[ecnt++] = argv[++i];
658 else if ( strcmp( pt,
"-help" ) == 0 )
660 usage( stdout, argv[0] );
663 else if ( strcmp( pt,
"-nohints" ) == 0 )
665 else if ( strcmp( pt,
"-rasterize" ) == 0 )
667 else if ( strcmp( pt,
"-results" ) == 0 )
668 results_dir = argv[++i];
669 else if ( strcmp( pt,
"-size" ) == 0 )
671 font_size = (FT_F26Dot6)( strtod( argv[++i], &end ) * 64 );
672 if ( *end !=
'\0' || font_size < 64 )
674 fprintf( stderr,
"Bad value for size: %s\n", argv[i] );
678 else if ( strcmp( pt,
"-test" ) == 0 )
679 testfile = argv[++i];
682 usage( stderr, argv[0] );
692 else if ( ecnt == 0 )
695 exts = default_ext_list;
701 dirs = default_dir_list;
705 ExecuteTest( testfile );
708 srandom( (
unsigned int)now );
710 FindFonts( dirs, exts );
711 mkdir( results_dir, 0755 );