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