Visualization Library 2.0.0-b5

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
ftrandom.c
Go to the documentation of this 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 
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  {
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  FT_IS_SCALABLE( face ) )
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  FT_IS_SCALABLE( face ) )
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 )
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 */
#define GOOD_FONTS_DIR
Definition: ftrandom.c:59
int write(int fd, const char *buf, int nbytes)
Definition: tif_acorn.c:325
#define NULL
Definition: ftobjs.h:61
FT_Long num_faces
Definition: freetype.h:921
#define FT_LOAD_NO_HINTING
Definition: freetype.h:2550
#define FT_LOAD_DEFAULT
Definition: freetype.h:2548
const char * filename
Definition: ioapi.h:135
png_uint_32 i
Definition: png.h:2640
FT_Init_FreeType(FT_Library *alibrary)
Definition: ftinit.c:232
GLenum GLuint GLint GLenum face
FT_Outline outline
Definition: freetype.h:1631
FT_Load_Glyph(FT_Face face, FT_UInt glyph_index, FT_Int32 load_flags)
Definition: ftobjs.c:574
int main(int argc, char **argv)
Definition: ftrandom.c:554
VLCORE_EXPORT real random(real min, real max)
Returns a random number N between &#39;min&#39; and &#39;max&#39; (included) with 53 bits of randomness generated usi...
Definition: math_utils.cpp:44
GLsizeiptr const GLvoid GLenum usage
GLenum GLsizei len
FT_Set_Char_Size(FT_Face face, FT_F26Dot6 char_width, FT_F26Dot6 char_height, FT_UInt horz_resolution, FT_UInt vert_resolution)
Definition: ftobjs.c:2899
local int out(void *out_desc, unsigned char *buf, unsigned len)
Definition: gun.c:131
#define ft_render_mode_normal
Definition: freetype.h:2773
GLuint buffer
FT_Render_Glyph(FT_GlyphSlot slot, FT_Render_Mode render_mode)
Definition: ftobjs.c:4107
#define forever
Definition: ftrandom.c:51
T ceil(T a)
Definition: glsl_math.hpp:903
FT_BEGIN_HEADER FT_Outline_Decompose(FT_Outline *outline, const FT_Outline_Funcs *func_interface, void *user)
Definition: ftoutln.c:51
GLuint GLuint end
local int max
Definition: enough.c:170
GLuint const GLchar * name
signed long FT_F26Dot6
Definition: fttypes.h:272
FT_Long num_glyphs
Definition: freetype.h:927
FT_GlyphSlot glyph
Definition: freetype.h:956
GLuint GLuint num
FT_New_Face(FT_Library library, const char *filepathname, FT_Long face_index, FT_Face *aface)
Definition: ftobjs.c:1210
FT_Done_Face(FT_Face face)
Definition: ftobjs.c:2341
#define FT_LOAD_NO_BITMAP
Definition: freetype.h:2552
#define FT_IS_SCALABLE(face)
Definition: freetype.h:1148
#define SEEK_SET
Definition: zconf.h:249