misc/libfreetype/src/tools/ftrandom/ftrandom.c
changeset 9372 915436ff64ab
parent 9371 f3840de881bd
child 9373 b769a8e38cbd
equal deleted inserted replaced
9371:f3840de881bd 9372:915436ff64ab
     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   {
       
    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          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 )
       
   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 */