Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenftrandom.c
Go to the documentation of this file.
00001 /* Copyright (C) 2005, 2007, 2008 by George Williams */ 00002 /* 00003 * Redistribution and use in source and binary forms, with or without 00004 * modification, are permitted provided that the following conditions are met: 00005 00006 * Redistributions of source code must retain the above copyright notice, this 00007 * list of conditions and the following disclaimer. 00008 00009 * Redistributions in binary form must reproduce the above copyright notice, 00010 * this list of conditions and the following disclaimer in the documentation 00011 * and/or other materials provided with the distribution. 00012 00013 * The name of the author may not be used to endorse or promote products 00014 * derived from this software without specific prior written permission. 00015 00016 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00017 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00018 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 00019 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00020 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00021 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 00022 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00023 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 00025 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 */ 00027 00028 /* modified by Werner Lemberg <wl@gnu.org> */ 00029 /* This file is now part of the FreeType library */ 00030 00031 00032 #include <stdio.h> 00033 #include <stdlib.h> 00034 #include <string.h> 00035 #include <strings.h> 00036 #include <sys/types.h> 00037 #include <sys/stat.h> 00038 #include <sys/wait.h> 00039 #include <unistd.h> 00040 #include <dirent.h> 00041 #include <math.h> 00042 #include <signal.h> 00043 #include <time.h> 00044 00045 #include <ft2build.h> 00046 #include FT_FREETYPE_H 00047 #include FT_OUTLINE_H 00048 00049 #define true 1 00050 #define false 0 00051 #define forever for (;;) 00052 00053 00054 static int check_outlines = false; 00055 static int nohints = false; 00056 static int rasterize = false; 00057 static char* results_dir = "results"; 00058 00059 #define GOOD_FONTS_DIR "/home/wl/freetype-testfonts" 00060 00061 static char* default_dir_list[] = 00062 { 00063 GOOD_FONTS_DIR, 00064 NULL 00065 }; 00066 00067 static char* default_ext_list[] = 00068 { 00069 "ttf", 00070 "otf", 00071 "ttc", 00072 "cid", 00073 "pfb", 00074 "pfa", 00075 "bdf", 00076 "pcf", 00077 "pfr", 00078 "fon", 00079 "otb", 00080 "cff", 00081 NULL 00082 }; 00083 00084 static int error_count = 1; 00085 static int error_fraction = 0; 00086 00087 static FT_F26Dot6 font_size = 12 * 64; 00088 00089 static struct fontlist 00090 { 00091 char* name; 00092 int len; 00093 unsigned int isbinary: 1; 00094 unsigned int isascii: 1; 00095 unsigned int ishex: 1; 00096 00097 } *fontlist; 00098 00099 static int fcnt; 00100 00101 00102 static int 00103 FT_MoveTo( const FT_Vector *to, 00104 void *user ) 00105 { 00106 return 0; 00107 } 00108 00109 00110 static int 00111 FT_LineTo( const FT_Vector *to, 00112 void *user ) 00113 { 00114 return 0; 00115 } 00116 00117 00118 static int 00119 FT_ConicTo( const FT_Vector *_cp, 00120 const FT_Vector *to, 00121 void *user ) 00122 { 00123 return 0; 00124 } 00125 00126 00127 static int 00128 FT_CubicTo( const FT_Vector *cp1, 00129 const FT_Vector *cp2, 00130 const FT_Vector *to, 00131 void *user ) 00132 { 00133 return 0; 00134 } 00135 00136 00137 static FT_Outline_Funcs outlinefuncs = 00138 { 00139 FT_MoveTo, 00140 FT_LineTo, 00141 FT_ConicTo, 00142 FT_CubicTo, 00143 0, 0 /* No shift, no delta */ 00144 }; 00145 00146 00147 static void 00148 TestFace( FT_Face face ) 00149 { 00150 int gid; 00151 int load_flags = FT_LOAD_DEFAULT; 00152 00153 00154 if ( check_outlines && 00155 FT_IS_SCALABLE( face ) ) 00156 load_flags = FT_LOAD_NO_BITMAP; 00157 00158 if ( nohints ) 00159 load_flags |= FT_LOAD_NO_HINTING; 00160 00161 FT_Set_Char_Size( face, 0, font_size, 72, 72 ); 00162 00163 for ( gid = 0; gid < face->num_glyphs; ++gid ) 00164 { 00165 if ( check_outlines && 00166 FT_IS_SCALABLE( face ) ) 00167 { 00168 if ( !FT_Load_Glyph( face, gid, load_flags ) ) 00169 FT_Outline_Decompose( &face->glyph->outline, &outlinefuncs, NULL ); 00170 } 00171 else 00172 FT_Load_Glyph( face, gid, load_flags ); 00173 00174 if ( rasterize ) 00175 FT_Render_Glyph( face->glyph, ft_render_mode_normal ); 00176 } 00177 00178 FT_Done_Face( face ); 00179 } 00180 00181 00182 static void 00183 ExecuteTest( char* testfont ) 00184 { 00185 FT_Library context; 00186 FT_Face face; 00187 int i, num; 00188 00189 00190 if ( FT_Init_FreeType( &context ) ) 00191 { 00192 fprintf( stderr, "Can't initialize FreeType.\n" ); 00193 exit( 1 ); 00194 } 00195 00196 if ( FT_New_Face( context, testfont, 0, &face ) ) 00197 { 00198 /* The font is erroneous, so if this fails that's ok. */ 00199 exit( 0 ); 00200 } 00201 00202 if ( face->num_faces == 1 ) 00203 TestFace( face ); 00204 else 00205 { 00206 num = face->num_faces; 00207 FT_Done_Face( face ); 00208 00209 for ( i = 0; i < num; ++i ) 00210 { 00211 if ( !FT_New_Face( context, testfont, i, &face ) ) 00212 TestFace( face ); 00213 } 00214 } 00215 00216 exit( 0 ); 00217 } 00218 00219 00220 static int 00221 extmatch( char* filename, 00222 char** extensions ) 00223 { 00224 int i; 00225 char* pt; 00226 00227 00228 if ( extensions == NULL ) 00229 return true; 00230 00231 pt = strrchr( filename, '.' ); 00232 if ( pt == NULL ) 00233 return false; 00234 if ( pt < strrchr( filename, '/' ) ) 00235 return false; 00236 00237 for ( i = 0; extensions[i] != NULL; ++i ) 00238 if ( strcasecmp( pt + 1, extensions[i] ) == 0 || 00239 strcasecmp( pt, extensions[i] ) == 0 ) 00240 return true; 00241 00242 return false; 00243 } 00244 00245 00246 static void 00247 figurefiletype( struct fontlist* item ) 00248 { 00249 FILE* foo; 00250 00251 00252 item->isbinary = item->isascii = item->ishex = false; 00253 00254 foo = fopen( item->name, "rb" ); 00255 if ( foo != NULL ) 00256 { 00257 /* Try to guess the file type from the first few characters... */ 00258 int ch1 = getc( foo ); 00259 int ch2 = getc( foo ); 00260 int ch3 = getc( foo ); 00261 int ch4 = getc( foo ); 00262 00263 00264 fclose( foo ); 00265 00266 if ( ( ch1 == 0 && ch2 == 1 && ch3 == 0 && ch4 == 0 ) || 00267 ( ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O' ) || 00268 ( ch1 == 't' && ch2 == 'r' && ch3 == 'u' && ch4 == 'e' ) || 00269 ( ch1 == 't' && ch2 == 't' && ch3 == 'c' && ch4 == 'f' ) ) 00270 { 00271 /* ttf, otf, ttc files */ 00272 item->isbinary = true; 00273 } 00274 else if ( ch1 == 0x80 && ch2 == '\01' ) 00275 { 00276 /* PFB header */ 00277 item->isbinary = true; 00278 } 00279 else if ( ch1 == '%' && ch2 == '!' ) 00280 { 00281 /* Random PostScript */ 00282 if ( strstr( item->name, ".pfa" ) != NULL || 00283 strstr( item->name, ".PFA" ) != NULL ) 00284 item->ishex = true; 00285 else 00286 item->isascii = true; 00287 } 00288 else if ( ch1 == 1 && ch2 == 0 && ch3 == 4 ) 00289 { 00290 /* Bare CFF */ 00291 item->isbinary = true; 00292 } 00293 else if ( ch1 == 'S' && ch2 == 'T' && ch3 == 'A' && ch4 == 'R' ) 00294 { 00295 /* BDF */ 00296 item->ishex = true; 00297 } 00298 else if ( ch1 == 'P' && ch2 == 'F' && ch3 == 'R' && ch4 == '0' ) 00299 { 00300 /* PFR */ 00301 item->isbinary = true; 00302 } 00303 else if ( ( ch1 == '\1' && ch2 == 'f' && ch3 == 'c' && ch4 == 'p' ) || 00304 ( ch1 == 'M' && ch2 == 'Z' ) ) 00305 { 00306 /* Windows FON */ 00307 item->isbinary = true; 00308 } 00309 else 00310 { 00311 fprintf( stderr, 00312 "Can't recognize file type of `%s', assuming binary\n", 00313 item->name ); 00314 item->isbinary = true; 00315 } 00316 } 00317 else 00318 { 00319 fprintf( stderr, "Can't open `%s' for typing the file.\n", 00320 item->name ); 00321 item->isbinary = true; 00322 } 00323 } 00324 00325 00326 static void 00327 FindFonts( char** fontdirs, 00328 char** extensions ) 00329 { 00330 DIR* examples; 00331 struct dirent* ent; 00332 00333 int i, max; 00334 char buffer[1025]; 00335 struct stat statb; 00336 00337 00338 max = 0; 00339 fcnt = 0; 00340 00341 for ( i = 0; fontdirs[i] != NULL; ++i ) 00342 { 00343 examples = opendir( fontdirs[i] ); 00344 if ( examples == NULL ) 00345 { 00346 fprintf( stderr, 00347 "Can't open example font directory `%s'\n", 00348 fontdirs[i] ); 00349 exit( 1 ); 00350 } 00351 00352 while ( ( ent = readdir( examples ) ) != NULL ) 00353 { 00354 snprintf( buffer, sizeof ( buffer ), 00355 "%s/%s", fontdirs[i], ent->d_name ); 00356 if ( stat( buffer, &statb ) == -1 || S_ISDIR( statb.st_mode ) ) 00357 continue; 00358 if ( extensions == NULL || extmatch( buffer, extensions ) ) 00359 { 00360 if ( fcnt >= max ) 00361 { 00362 max += 100; 00363 fontlist = realloc( fontlist, max * sizeof ( struct fontlist ) ); 00364 if ( fontlist == NULL ) 00365 { 00366 fprintf( stderr, "Can't allocate memory\n" ); 00367 exit( 1 ); 00368 } 00369 } 00370 00371 fontlist[fcnt].name = strdup( buffer ); 00372 fontlist[fcnt].len = statb.st_size; 00373 00374 figurefiletype( &fontlist[fcnt] ); 00375 ++fcnt; 00376 } 00377 } 00378 00379 closedir( examples ); 00380 } 00381 00382 if ( fcnt == 0 ) 00383 { 00384 fprintf( stderr, "Can't find matching font files.\n" ); 00385 exit( 1 ); 00386 } 00387 00388 fontlist[fcnt].name = NULL; 00389 } 00390 00391 00392 static int 00393 getErrorCnt( struct fontlist* item ) 00394 { 00395 if ( error_count == 0 && error_fraction == 0 ) 00396 return 0; 00397 00398 return error_count + ceil( error_fraction * item->len ); 00399 } 00400 00401 00402 static int 00403 getRandom( int low, 00404 int high ) 00405 { 00406 if ( low - high < 0x10000L ) 00407 return low + ( ( random() >> 8 ) % ( high + 1 - low ) ); 00408 00409 return low + ( random() % ( high + 1 - low ) ); 00410 } 00411 00412 00413 static int 00414 copyfont( struct fontlist* item, 00415 char* newfont ) 00416 { 00417 static char buffer[8096]; 00418 FILE *good, *new; 00419 int len; 00420 int i, err_cnt; 00421 00422 00423 good = fopen( item->name, "r" ); 00424 if ( good == NULL ) 00425 { 00426 fprintf( stderr, "Can't open `%s'\n", item->name ); 00427 return false; 00428 } 00429 00430 new = fopen( newfont, "w+" ); 00431 if ( new == NULL ) 00432 { 00433 fprintf( stderr, "Can't create temporary output file `%s'\n", 00434 newfont ); 00435 exit( 1 ); 00436 } 00437 00438 while ( ( len = fread( buffer, 1, sizeof ( buffer ), good ) ) > 0 ) 00439 fwrite( buffer, 1, len, new ); 00440 00441 fclose( good ); 00442 00443 err_cnt = getErrorCnt( item ); 00444 for ( i = 0; i < err_cnt; ++i ) 00445 { 00446 fseek( new, getRandom( 0, item->len - 1 ), SEEK_SET ); 00447 00448 if ( item->isbinary ) 00449 putc( getRandom( 0, 0xff ), new ); 00450 else if ( item->isascii ) 00451 putc( getRandom( 0x20, 0x7e ), new ); 00452 else 00453 { 00454 int hex = getRandom( 0, 15 ); 00455 00456 00457 if ( hex < 10 ) 00458 hex += '0'; 00459 else 00460 hex += 'A' - 10; 00461 00462 putc( hex, new ); 00463 } 00464 } 00465 00466 if ( ferror( new ) ) 00467 { 00468 fclose( new ); 00469 unlink( newfont ); 00470 return false; 00471 } 00472 00473 fclose( new ); 00474 00475 return true; 00476 } 00477 00478 00479 static int child_pid; 00480 00481 static void 00482 abort_test( int sig ) 00483 { 00484 /* If a time-out happens, then kill the child */ 00485 kill( child_pid, SIGFPE ); 00486 write( 2, "Timeout... ", 11 ); 00487 } 00488 00489 00490 static void 00491 do_test( void ) 00492 { 00493 int i = getRandom( 0, fcnt - 1 ); 00494 static int test_num = 0; 00495 char buffer[1024]; 00496 00497 00498 sprintf( buffer, "%s/test%d", results_dir, test_num++ ); 00499 00500 if ( copyfont ( &fontlist[i], buffer ) ) 00501 { 00502 signal( SIGALRM, abort_test ); 00503 /* Anything that takes more than 20 seconds */ 00504 /* to parse and/or rasterize is an error. */ 00505 alarm( 20 ); 00506 if ( ( child_pid = fork() ) == 0 ) 00507 ExecuteTest( buffer ); 00508 else if ( child_pid != -1 ) 00509 { 00510 int status; 00511 00512 00513 waitpid( child_pid, &status, 0 ); 00514 alarm( 0 ); 00515 if ( WIFSIGNALED ( status ) ) 00516 printf( "Error found in file `%s'\n", buffer ); 00517 else 00518 unlink( buffer ); 00519 } 00520 else 00521 { 00522 fprintf( stderr, "Can't fork test case.\n" ); 00523 exit( 1 ); 00524 } 00525 alarm( 0 ); 00526 } 00527 } 00528 00529 00530 static void 00531 usage( FILE* out, 00532 char* name ) 00533 { 00534 fprintf( out, "%s [options] -- Generate random erroneous fonts\n" 00535 " and attempt to parse them with FreeType.\n\n", name ); 00536 00537 fprintf( out, " --all All non-directory files are assumed to be fonts.\n" ); 00538 fprintf( out, " --check-outlines Make sure we can parse the outlines of each glyph.\n" ); 00539 fprintf( out, " --dir <path> Append <path> to list of font search directories.\n" ); 00540 fprintf( out, " --error-count <cnt> Introduce <cnt> single byte errors into each font.\n" ); 00541 fprintf( out, " --error-fraction <frac> Introduce <frac>*filesize single byte errors\n" 00542 " into each font.\n" ); 00543 fprintf( out, " --ext <ext> Add <ext> to list of extensions indicating fonts.\n" ); 00544 fprintf( out, " --help Print this.\n" ); 00545 fprintf( out, " --nohints Turn off hinting.\n" ); 00546 fprintf( out, " --rasterize Attempt to rasterize each glyph.\n" ); 00547 fprintf( out, " --results <dir> Directory in which to place the test fonts.\n" ); 00548 fprintf( out, " --size <float> Use the given font size for the tests.\n" ); 00549 fprintf( out, " --test <file> Run a single test on an already existing file.\n" ); 00550 } 00551 00552 00553 int 00554 main( int argc, 00555 char** argv ) 00556 { 00557 char **dirs, **exts; 00558 char *pt, *end; 00559 int dcnt = 0, ecnt = 0, rset = false, allexts = false; 00560 int i; 00561 time_t now; 00562 char* testfile = NULL; 00563 00564 00565 dirs = calloc( argc + 1, sizeof ( char ** ) ); 00566 exts = calloc( argc + 1, sizeof ( char ** ) ); 00567 00568 for ( i = 1; i < argc; ++i ) 00569 { 00570 pt = argv[i]; 00571 if ( pt[0] == '-' && pt[1] == '-' ) 00572 ++pt; 00573 00574 if ( strcmp( pt, "-all" ) == 0 ) 00575 allexts = true; 00576 else if ( strcmp( pt, "-check-outlines" ) == 0 ) 00577 check_outlines = true; 00578 else if ( strcmp( pt, "-dir" ) == 0 ) 00579 dirs[dcnt++] = argv[++i]; 00580 else if ( strcmp( pt, "-error-count" ) == 0 ) 00581 { 00582 if ( !rset ) 00583 error_fraction = 0; 00584 rset = true; 00585 error_count = strtol( argv[++i], &end, 10 ); 00586 if ( *end != '\0' ) 00587 { 00588 fprintf( stderr, "Bad value for error-count: %s\n", argv[i] ); 00589 exit( 1 ); 00590 } 00591 } 00592 else if ( strcmp( pt, "-error-fraction" ) == 0 ) 00593 { 00594 if ( !rset ) 00595 error_count = 0; 00596 rset = true; 00597 error_fraction = strtod( argv[++i], &end ); 00598 if ( *end != '\0' ) 00599 { 00600 fprintf( stderr, "Bad value for error-fraction: %s\n", argv[i] ); 00601 exit( 1 ); 00602 } 00603 } 00604 else if ( strcmp( pt, "-ext" ) == 0 ) 00605 exts[ecnt++] = argv[++i]; 00606 else if ( strcmp( pt, "-help" ) == 0 ) 00607 { 00608 usage( stdout, argv[0] ); 00609 exit( 0 ); 00610 } 00611 else if ( strcmp( pt, "-nohints" ) == 0 ) 00612 nohints = true; 00613 else if ( strcmp( pt, "-rasterize" ) == 0 ) 00614 rasterize = true; 00615 else if ( strcmp( pt, "-results" ) == 0 ) 00616 results_dir = argv[++i]; 00617 else if ( strcmp( pt, "-size" ) == 0 ) 00618 { 00619 font_size = (FT_F26Dot6)( strtod( argv[++i], &end ) * 64 ); 00620 if ( *end != '\0' || font_size < 64 ) 00621 { 00622 fprintf( stderr, "Bad value for size: %s\n", argv[i] ); 00623 exit( 1 ); 00624 } 00625 } 00626 else if ( strcmp( pt, "-test" ) == 0 ) 00627 testfile = argv[++i]; 00628 else 00629 { 00630 usage( stderr, argv[0] ); 00631 exit( 1 ); 00632 } 00633 } 00634 00635 if ( allexts ) 00636 exts = NULL; 00637 else if ( ecnt == 0 ) 00638 exts = default_ext_list; 00639 00640 if ( dcnt == 0 ) 00641 dirs = default_dir_list; 00642 00643 if ( testfile != NULL ) 00644 ExecuteTest( testfile ); /* This should never return */ 00645 00646 time( &now ); 00647 srandom( now ); 00648 00649 FindFonts( dirs, exts ); 00650 mkdir( results_dir, 0755 ); 00651 00652 forever 00653 do_test(); 00654 00655 return 0; 00656 } 00657 00658 00659 /* EOF */ Generated on Sat May 26 2012 04:32:57 for ReactOS by
1.7.6.1
|