/src/freetype/src/tools/ftrandom/ftrandom.c

https://bitbucket.org/cabalistic/ogredeps/ · C · 659 lines · 500 code · 118 blank · 41 comment · 201 complexity · f8dbe88018051ef89f129326b706c473 MD5 · raw file

  1. /* Copyright (C) 2005, 2007, 2008 by George Williams */
  2. /*
  3. * Redistribution and use in source and binary forms, with or without
  4. * modification, are permitted provided that the following conditions are met:
  5. * Redistributions of source code must retain the above copyright notice, this
  6. * list of conditions and the following disclaimer.
  7. * Redistributions in binary form must reproduce the above copyright notice,
  8. * this list of conditions and the following disclaimer in the documentation
  9. * and/or other materials provided with the distribution.
  10. * The name of the author may not be used to endorse or promote products
  11. * derived from this software without specific prior written permission.
  12. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  13. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  14. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  15. * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  16. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  17. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  18. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  19. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  20. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  21. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. /* modified by Werner Lemberg <wl@gnu.org> */
  24. /* This file is now part of the FreeType library */
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <strings.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <sys/wait.h>
  32. #include <unistd.h>
  33. #include <dirent.h>
  34. #include <math.h>
  35. #include <signal.h>
  36. #include <time.h>
  37. #include <ft2build.h>
  38. #include FT_FREETYPE_H
  39. #include FT_OUTLINE_H
  40. #define true 1
  41. #define false 0
  42. #define forever for (;;)
  43. static int check_outlines = false;
  44. static int nohints = false;
  45. static int rasterize = false;
  46. static char* results_dir = "results";
  47. #define GOOD_FONTS_DIR "/home/wl/freetype-testfonts"
  48. static char* default_dir_list[] =
  49. {
  50. GOOD_FONTS_DIR,
  51. NULL
  52. };
  53. static char* default_ext_list[] =
  54. {
  55. "ttf",
  56. "otf",
  57. "ttc",
  58. "cid",
  59. "pfb",
  60. "pfa",
  61. "bdf",
  62. "pcf",
  63. "pfr",
  64. "fon",
  65. "otb",
  66. "cff",
  67. NULL
  68. };
  69. static int error_count = 1;
  70. static int error_fraction = 0;
  71. static FT_F26Dot6 font_size = 12 * 64;
  72. static struct fontlist
  73. {
  74. char* name;
  75. int len;
  76. unsigned int isbinary: 1;
  77. unsigned int isascii: 1;
  78. unsigned int ishex: 1;
  79. } *fontlist;
  80. static int fcnt;
  81. static int
  82. FT_MoveTo( const FT_Vector *to,
  83. void *user )
  84. {
  85. return 0;
  86. }
  87. static int
  88. FT_LineTo( const FT_Vector *to,
  89. void *user )
  90. {
  91. return 0;
  92. }
  93. static int
  94. FT_ConicTo( const FT_Vector *_cp,
  95. const FT_Vector *to,
  96. void *user )
  97. {
  98. return 0;
  99. }
  100. static int
  101. FT_CubicTo( const FT_Vector *cp1,
  102. const FT_Vector *cp2,
  103. const FT_Vector *to,
  104. void *user )
  105. {
  106. return 0;
  107. }
  108. static FT_Outline_Funcs outlinefuncs =
  109. {
  110. FT_MoveTo,
  111. FT_LineTo,
  112. FT_ConicTo,
  113. FT_CubicTo,
  114. 0, 0 /* No shift, no delta */
  115. };
  116. static void
  117. TestFace( FT_Face face )
  118. {
  119. int gid;
  120. int load_flags = FT_LOAD_DEFAULT;
  121. if ( check_outlines &&
  122. FT_IS_SCALABLE( face ) )
  123. load_flags = FT_LOAD_NO_BITMAP;
  124. if ( nohints )
  125. load_flags |= FT_LOAD_NO_HINTING;
  126. FT_Set_Char_Size( face, 0, font_size, 72, 72 );
  127. for ( gid = 0; gid < face->num_glyphs; ++gid )
  128. {
  129. if ( check_outlines &&
  130. FT_IS_SCALABLE( face ) )
  131. {
  132. if ( !FT_Load_Glyph( face, gid, load_flags ) )
  133. FT_Outline_Decompose( &face->glyph->outline, &outlinefuncs, NULL );
  134. }
  135. else
  136. FT_Load_Glyph( face, gid, load_flags );
  137. if ( rasterize )
  138. FT_Render_Glyph( face->glyph, ft_render_mode_normal );
  139. }
  140. FT_Done_Face( face );
  141. }
  142. static void
  143. ExecuteTest( char* testfont )
  144. {
  145. FT_Library context;
  146. FT_Face face;
  147. int i, num;
  148. if ( FT_Init_FreeType( &context ) )
  149. {
  150. fprintf( stderr, "Can't initialize FreeType.\n" );
  151. exit( 1 );
  152. }
  153. if ( FT_New_Face( context, testfont, 0, &face ) )
  154. {
  155. /* The font is erroneous, so if this fails that's ok. */
  156. exit( 0 );
  157. }
  158. if ( face->num_faces == 1 )
  159. TestFace( face );
  160. else
  161. {
  162. num = face->num_faces;
  163. FT_Done_Face( face );
  164. for ( i = 0; i < num; ++i )
  165. {
  166. if ( !FT_New_Face( context, testfont, i, &face ) )
  167. TestFace( face );
  168. }
  169. }
  170. exit( 0 );
  171. }
  172. static int
  173. extmatch( char* filename,
  174. char** extensions )
  175. {
  176. int i;
  177. char* pt;
  178. if ( extensions == NULL )
  179. return true;
  180. pt = strrchr( filename, '.' );
  181. if ( pt == NULL )
  182. return false;
  183. if ( pt < strrchr( filename, '/' ) )
  184. return false;
  185. for ( i = 0; extensions[i] != NULL; ++i )
  186. if ( strcasecmp( pt + 1, extensions[i] ) == 0 ||
  187. strcasecmp( pt, extensions[i] ) == 0 )
  188. return true;
  189. return false;
  190. }
  191. static void
  192. figurefiletype( struct fontlist* item )
  193. {
  194. FILE* foo;
  195. item->isbinary = item->isascii = item->ishex = false;
  196. foo = fopen( item->name, "rb" );
  197. if ( foo != NULL )
  198. {
  199. /* Try to guess the file type from the first few characters... */
  200. int ch1 = getc( foo );
  201. int ch2 = getc( foo );
  202. int ch3 = getc( foo );
  203. int ch4 = getc( foo );
  204. fclose( foo );
  205. if ( ( ch1 == 0 && ch2 == 1 && ch3 == 0 && ch4 == 0 ) ||
  206. ( ch1 == 'O' && ch2 == 'T' && ch3 == 'T' && ch4 == 'O' ) ||
  207. ( ch1 == 't' && ch2 == 'r' && ch3 == 'u' && ch4 == 'e' ) ||
  208. ( ch1 == 't' && ch2 == 't' && ch3 == 'c' && ch4 == 'f' ) )
  209. {
  210. /* ttf, otf, ttc files */
  211. item->isbinary = true;
  212. }
  213. else if ( ch1 == 0x80 && ch2 == '\01' )
  214. {
  215. /* PFB header */
  216. item->isbinary = true;
  217. }
  218. else if ( ch1 == '%' && ch2 == '!' )
  219. {
  220. /* Random PostScript */
  221. if ( strstr( item->name, ".pfa" ) != NULL ||
  222. strstr( item->name, ".PFA" ) != NULL )
  223. item->ishex = true;
  224. else
  225. item->isascii = true;
  226. }
  227. else if ( ch1 == 1 && ch2 == 0 && ch3 == 4 )
  228. {
  229. /* Bare CFF */
  230. item->isbinary = true;
  231. }
  232. else if ( ch1 == 'S' && ch2 == 'T' && ch3 == 'A' && ch4 == 'R' )
  233. {
  234. /* BDF */
  235. item->ishex = true;
  236. }
  237. else if ( ch1 == 'P' && ch2 == 'F' && ch3 == 'R' && ch4 == '0' )
  238. {
  239. /* PFR */
  240. item->isbinary = true;
  241. }
  242. else if ( ( ch1 == '\1' && ch2 == 'f' && ch3 == 'c' && ch4 == 'p' ) ||
  243. ( ch1 == 'M' && ch2 == 'Z' ) )
  244. {
  245. /* Windows FON */
  246. item->isbinary = true;
  247. }
  248. else
  249. {
  250. fprintf( stderr,
  251. "Can't recognize file type of `%s', assuming binary\n",
  252. item->name );
  253. item->isbinary = true;
  254. }
  255. }
  256. else
  257. {
  258. fprintf( stderr, "Can't open `%s' for typing the file.\n",
  259. item->name );
  260. item->isbinary = true;
  261. }
  262. }
  263. static void
  264. FindFonts( char** fontdirs,
  265. char** extensions )
  266. {
  267. DIR* examples;
  268. struct dirent* ent;
  269. int i, max;
  270. char buffer[1025];
  271. struct stat statb;
  272. max = 0;
  273. fcnt = 0;
  274. for ( i = 0; fontdirs[i] != NULL; ++i )
  275. {
  276. examples = opendir( fontdirs[i] );
  277. if ( examples == NULL )
  278. {
  279. fprintf( stderr,
  280. "Can't open example font directory `%s'\n",
  281. fontdirs[i] );
  282. exit( 1 );
  283. }
  284. while ( ( ent = readdir( examples ) ) != NULL )
  285. {
  286. snprintf( buffer, sizeof ( buffer ),
  287. "%s/%s", fontdirs[i], ent->d_name );
  288. if ( stat( buffer, &statb ) == -1 || S_ISDIR( statb.st_mode ) )
  289. continue;
  290. if ( extensions == NULL || extmatch( buffer, extensions ) )
  291. {
  292. if ( fcnt >= max )
  293. {
  294. max += 100;
  295. fontlist = realloc( fontlist, max * sizeof ( struct fontlist ) );
  296. if ( fontlist == NULL )
  297. {
  298. fprintf( stderr, "Can't allocate memory\n" );
  299. exit( 1 );
  300. }
  301. }
  302. fontlist[fcnt].name = strdup( buffer );
  303. fontlist[fcnt].len = statb.st_size;
  304. figurefiletype( &fontlist[fcnt] );
  305. ++fcnt;
  306. }
  307. }
  308. closedir( examples );
  309. }
  310. if ( fcnt == 0 )
  311. {
  312. fprintf( stderr, "Can't find matching font files.\n" );
  313. exit( 1 );
  314. }
  315. fontlist[fcnt].name = NULL;
  316. }
  317. static int
  318. getErrorCnt( struct fontlist* item )
  319. {
  320. if ( error_count == 0 && error_fraction == 0 )
  321. return 0;
  322. return error_count + ceil( error_fraction * item->len );
  323. }
  324. static int
  325. getRandom( int low,
  326. int high )
  327. {
  328. if ( low - high < 0x10000L )
  329. return low + ( ( random() >> 8 ) % ( high + 1 - low ) );
  330. return low + ( random() % ( high + 1 - low ) );
  331. }
  332. static int
  333. copyfont( struct fontlist* item,
  334. char* newfont )
  335. {
  336. static char buffer[8096];
  337. FILE *good, *new;
  338. int len;
  339. int i, err_cnt;
  340. good = fopen( item->name, "r" );
  341. if ( good == NULL )
  342. {
  343. fprintf( stderr, "Can't open `%s'\n", item->name );
  344. return false;
  345. }
  346. new = fopen( newfont, "w+" );
  347. if ( new == NULL )
  348. {
  349. fprintf( stderr, "Can't create temporary output file `%s'\n",
  350. newfont );
  351. exit( 1 );
  352. }
  353. while ( ( len = fread( buffer, 1, sizeof ( buffer ), good ) ) > 0 )
  354. fwrite( buffer, 1, len, new );
  355. fclose( good );
  356. err_cnt = getErrorCnt( item );
  357. for ( i = 0; i < err_cnt; ++i )
  358. {
  359. fseek( new, getRandom( 0, item->len - 1 ), SEEK_SET );
  360. if ( item->isbinary )
  361. putc( getRandom( 0, 0xff ), new );
  362. else if ( item->isascii )
  363. putc( getRandom( 0x20, 0x7e ), new );
  364. else
  365. {
  366. int hex = getRandom( 0, 15 );
  367. if ( hex < 10 )
  368. hex += '0';
  369. else
  370. hex += 'A' - 10;
  371. putc( hex, new );
  372. }
  373. }
  374. if ( ferror( new ) )
  375. {
  376. fclose( new );
  377. unlink( newfont );
  378. return false;
  379. }
  380. fclose( new );
  381. return true;
  382. }
  383. static int child_pid;
  384. static void
  385. abort_test( int sig )
  386. {
  387. /* If a time-out happens, then kill the child */
  388. kill( child_pid, SIGFPE );
  389. write( 2, "Timeout... ", 11 );
  390. }
  391. static void
  392. do_test( void )
  393. {
  394. int i = getRandom( 0, fcnt - 1 );
  395. static int test_num = 0;
  396. char buffer[1024];
  397. sprintf( buffer, "%s/test%d", results_dir, test_num++ );
  398. if ( copyfont ( &fontlist[i], buffer ) )
  399. {
  400. signal( SIGALRM, abort_test );
  401. /* Anything that takes more than 20 seconds */
  402. /* to parse and/or rasterize is an error. */
  403. alarm( 20 );
  404. if ( ( child_pid = fork() ) == 0 )
  405. ExecuteTest( buffer );
  406. else if ( child_pid != -1 )
  407. {
  408. int status;
  409. waitpid( child_pid, &status, 0 );
  410. alarm( 0 );
  411. if ( WIFSIGNALED ( status ) )
  412. printf( "Error found in file `%s'\n", buffer );
  413. else
  414. unlink( buffer );
  415. }
  416. else
  417. {
  418. fprintf( stderr, "Can't fork test case.\n" );
  419. exit( 1 );
  420. }
  421. alarm( 0 );
  422. }
  423. }
  424. static void
  425. usage( FILE* out,
  426. char* name )
  427. {
  428. fprintf( out, "%s [options] -- Generate random erroneous fonts\n"
  429. " and attempt to parse them with FreeType.\n\n", name );
  430. fprintf( out, " --all All non-directory files are assumed to be fonts.\n" );
  431. fprintf( out, " --check-outlines Make sure we can parse the outlines of each glyph.\n" );
  432. fprintf( out, " --dir <path> Append <path> to list of font search directories.\n" );
  433. fprintf( out, " --error-count <cnt> Introduce <cnt> single byte errors into each font.\n" );
  434. fprintf( out, " --error-fraction <frac> Introduce <frac>*filesize single byte errors\n"
  435. " into each font.\n" );
  436. fprintf( out, " --ext <ext> Add <ext> to list of extensions indicating fonts.\n" );
  437. fprintf( out, " --help Print this.\n" );
  438. fprintf( out, " --nohints Turn off hinting.\n" );
  439. fprintf( out, " --rasterize Attempt to rasterize each glyph.\n" );
  440. fprintf( out, " --results <dir> Directory in which to place the test fonts.\n" );
  441. fprintf( out, " --size <float> Use the given font size for the tests.\n" );
  442. fprintf( out, " --test <file> Run a single test on an already existing file.\n" );
  443. }
  444. int
  445. main( int argc,
  446. char** argv )
  447. {
  448. char **dirs, **exts;
  449. char *pt, *end;
  450. int dcnt = 0, ecnt = 0, rset = false, allexts = false;
  451. int i;
  452. time_t now;
  453. char* testfile = NULL;
  454. dirs = calloc( argc + 1, sizeof ( char ** ) );
  455. exts = calloc( argc + 1, sizeof ( char ** ) );
  456. for ( i = 1; i < argc; ++i )
  457. {
  458. pt = argv[i];
  459. if ( pt[0] == '-' && pt[1] == '-' )
  460. ++pt;
  461. if ( strcmp( pt, "-all" ) == 0 )
  462. allexts = true;
  463. else if ( strcmp( pt, "-check-outlines" ) == 0 )
  464. check_outlines = true;
  465. else if ( strcmp( pt, "-dir" ) == 0 )
  466. dirs[dcnt++] = argv[++i];
  467. else if ( strcmp( pt, "-error-count" ) == 0 )
  468. {
  469. if ( !rset )
  470. error_fraction = 0;
  471. rset = true;
  472. error_count = strtol( argv[++i], &end, 10 );
  473. if ( *end != '\0' )
  474. {
  475. fprintf( stderr, "Bad value for error-count: %s\n", argv[i] );
  476. exit( 1 );
  477. }
  478. }
  479. else if ( strcmp( pt, "-error-fraction" ) == 0 )
  480. {
  481. if ( !rset )
  482. error_count = 0;
  483. rset = true;
  484. error_fraction = strtod( argv[++i], &end );
  485. if ( *end != '\0' )
  486. {
  487. fprintf( stderr, "Bad value for error-fraction: %s\n", argv[i] );
  488. exit( 1 );
  489. }
  490. }
  491. else if ( strcmp( pt, "-ext" ) == 0 )
  492. exts[ecnt++] = argv[++i];
  493. else if ( strcmp( pt, "-help" ) == 0 )
  494. {
  495. usage( stdout, argv[0] );
  496. exit( 0 );
  497. }
  498. else if ( strcmp( pt, "-nohints" ) == 0 )
  499. nohints = true;
  500. else if ( strcmp( pt, "-rasterize" ) == 0 )
  501. rasterize = true;
  502. else if ( strcmp( pt, "-results" ) == 0 )
  503. results_dir = argv[++i];
  504. else if ( strcmp( pt, "-size" ) == 0 )
  505. {
  506. font_size = (FT_F26Dot6)( strtod( argv[++i], &end ) * 64 );
  507. if ( *end != '\0' || font_size < 64 )
  508. {
  509. fprintf( stderr, "Bad value for size: %s\n", argv[i] );
  510. exit( 1 );
  511. }
  512. }
  513. else if ( strcmp( pt, "-test" ) == 0 )
  514. testfile = argv[++i];
  515. else
  516. {
  517. usage( stderr, argv[0] );
  518. exit( 1 );
  519. }
  520. }
  521. if ( allexts )
  522. exts = NULL;
  523. else if ( ecnt == 0 )
  524. exts = default_ext_list;
  525. if ( dcnt == 0 )
  526. dirs = default_dir_list;
  527. if ( testfile != NULL )
  528. ExecuteTest( testfile ); /* This should never return */
  529. time( &now );
  530. srandom( now );
  531. FindFonts( dirs, exts );
  532. mkdir( results_dir, 0755 );
  533. forever
  534. do_test();
  535. return 0;
  536. }
  537. /* EOF */