/* Copyright (C) 2005 by George Williams */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef TEST_FREETYPE # include # include FT_FREETYPE_H # include FT_OUTLINE_H #endif #define true 1 #define false 0 #define forever for (;;) #ifdef TEST_FREETYPE static int check_outlines = false; static int nohints = false; static int rasterize = false; #else static char *command = "fontforge"; #endif static char *results_dir = "results"; #define GOOD_FONTS_DIR "/home/gww/myfonts/fontforge/others" static char *default_dir_list[] = { GOOD_FONTS_DIR, NULL }; static char *default_ext_list[] = { "ttf", "otf", "ttc", "cid", "pfb", "pfa", "bdf", #ifdef TEST_FREETYPE #else "sfd", "svg", "pt3", #endif NULL }; static int error_count = 1; static int error_fraction = 0; static struct fontlist { char *name; int len; unsigned int isbinary: 1; unsigned int isascii: 1; unsigned int ishex: 1; } *fontlist; static int fcnt; static int extmatch(char *filename,char **extensions) { int i; char *pt; if ( extensions==NULL ) return( true ); pt = strrchr(filename,'.'); if ( pt==NULL ) return( false ); if ( ptisbinary = item->isascii = item->ishex = false; foo = fopen(item->name,"rb"); if ( foo!=NULL ) { /* Try to guess the file type from the first few characters... */ int ch1 = getc(foo); int ch2 = getc(foo); int ch3 = getc(foo); int ch4 = getc(foo); int ch5 = getc(foo); int ch6 = getc(foo); int ch7 = getc(foo); fclose(foo); if (( ch1==0 && ch2==1 && ch3==0 && ch4==0 ) || (ch1=='O' && ch2=='T' && ch3=='T' && ch4=='O') || (ch1=='t' && ch2=='r' && ch3=='u' && ch4=='e') || (ch1=='t' && ch2=='t' && ch3=='c' && ch4=='f') ) { /* ttf, otf, ttc files */ item->isbinary = true; } else if ( ch1==0x80 && ch2=='\01' ) { /* PFB header */ item->isbinary = true; } else if ( ch1=='%' && ch2=='!' ) { /* Random PostScript */ if ( strstr(item->name,".pfa")!=NULL || strstr(item->name,".PFA")!=NULL ) item->ishex = true; else item->isascii = true; } else if ( ch1==1 && ch2==0 && ch3==4 ) { /* Bare CFF */ item->isbinary = true; } else if ( ch1=='<' && ch2=='?' && (ch3=='x'||ch3=='X') && (ch4=='m'||ch4=='M') ) { /* SVG */ item->isascii = true; } else if ( ch1==0xef && ch2==0xbb && ch3==0xbf && ch4=='<' && ch5=='?' && (ch6=='x'||ch6=='X') && (ch7=='m'||ch7=='M') ) { /* UTF-8 SVG with initial byte ordering mark */ item->isascii = true; } else if ( ch1=='S' && ch2=='p' && ch3=='l' && ch4=='i' ) { /* SFD */ item->isascii = true; } else if ( ch1=='S' && ch2=='T' && ch3=='A' && ch4=='R' ) { /* BDF */ item->ishex = true; } else if ( ch1=='\1' && ch2=='f' && ch3=='c' && ch4=='p' ) { /* Windows FON */ item->isbinary = true; } else { fprintf( stderr, "Didn't recognize file type of %s, assumed binary\n", item->name ); item->isbinary = true; } } else { fprintf( stderr, "Could not open %s for typing the file.\n", item->name ); item->isbinary = true; } } static void FindFonts(char **fontdirs,char **extensions) { DIR *examples; struct dirent *ent; int i, max; char buffer[1025]; struct stat statb; max = 0; fcnt = 0; for ( i=0; fontdirs[i]!=NULL; ++i ) { examples = opendir(fontdirs[i]); if ( examples==NULL ) { fprintf( stderr, "Could not open example font directory.\n\t%s\n", fontdirs[i] ); exit(1); } while ( (ent = readdir(examples))!=NULL ) { snprintf(buffer,sizeof(buffer),"%s/%s", fontdirs[i], ent->d_name ); if ( stat(buffer,&statb)==-1 || S_ISDIR(statb.st_mode)) continue; if ( extensions==NULL || extmatch(buffer,extensions)) { if ( fcnt>=max ) { max += 100; fontlist = realloc(fontlist,max*sizeof(struct fontlist)); if ( fontlist==NULL ) { fprintf( stderr, "Couldn't allocate memory\n" ); exit(1); } } fontlist[fcnt].name = strdup(buffer); fontlist[fcnt].len = statb.st_size; figurefiletype(&fontlist[fcnt]); ++fcnt; } } closedir(examples); } if ( fcnt==0 ) { fprintf( stderr, "No matching font files found.\n" ); exit(1); } fontlist[fcnt].name = NULL; } static int getErrorCnt(struct fontlist *item) { if ( error_count==0 && error_fraction==0 ) return( 0 ); return( error_count + ceil(error_fraction*item->len)); } static int getRandom(int low, int high) { if ( low-high<0x10000 ) return( low + ((random()>>8)%(high+1-low)) ); return( low + (random()%(high+1-low)) ); } static int copyfont(struct fontlist *item,char *newfont) { static char buffer[8096]; FILE *good, *new; int len; int i, err_cnt; good = fopen(item->name,"r"); if ( good==NULL ) { fprintf( stderr, "Could not open %s\n", item->name ); return( false ); } new = fopen(newfont,"w+"); if ( new==NULL ) { fprintf( stderr, "Could not create temporary output file %s\n", newfont ); exit( 1 ); } while ( (len = fread(buffer,1,sizeof(buffer), good ))>0 ) fwrite(buffer,1,len,new); fclose(good); err_cnt = getErrorCnt(item); for ( i=0; ilen-1),SEEK_SET); if ( item->isbinary ) putc(getRandom(0,0xff),new); else if ( item->isascii ) putc(getRandom(0x20,0x7e),new); else { int hex = getRandom(0,15); if ( hex<10 ) hex += '0'; else hex += 'A'-10; putc(hex,new); } } if ( ferror(new)) { fclose(new); unlink(newfont); return( false ); } fclose(new); return( true ); } #ifdef TEST_FREETYPE static int FT_MoveTo(FT_Vector *to,void *user) { return( 0 ); } static int FT_LineTo(FT_Vector *to,void *user) { return( 0 ); } static int FT_ConicTo(FT_Vector *_cp, FT_Vector *to,void *user) { return( 0 ); } static int FT_CubicTo(FT_Vector *cp1, FT_Vector *cp2,FT_Vector *to,void *user) { return( 0 ); } static FT_Outline_Funcs outlinefuncs = { FT_MoveTo, FT_LineTo, FT_ConicTo, FT_CubicTo, 0,0 /* No shift, no delta */ }; static void TestFace(FT_Face face) { int gid; int load_flags = FT_LOAD_DEFAULT; if ( check_outlines && (face->face_flags&FT_FACE_FLAG_SCALABLE)) load_flags = FT_LOAD_NO_BITMAP; if ( nohints ) load_flags |= FT_LOAD_NO_HINTING; FT_Set_Char_Size(face,0,(int) (12*64), 72, 72); for ( gid=0; gidnum_glyphs; ++gid ) { if ( check_outlines && (face->face_flags&FT_FACE_FLAG_SCALABLE)) { if ( !FT_Load_Glyph(face,gid,load_flags)) FT_Outline_Decompose(&face->glyph->outline,&outlinefuncs,NULL); } else { FT_Load_Glyph(face,gid,load_flags); } if ( rasterize ) FT_Render_Glyph(face->glyph,ft_render_mode_normal); } FT_Done_Face(face); } static void ExecuteTest(char *testfont) { FT_Library context; FT_Face face; int i,num; if ( FT_Init_FreeType( &context )) { fprintf( stderr, "Could not initialize freetype.\n" ); exit(1); } if ( FT_New_Face(context,testfont,0,&face)) { /* The font is erroneous, so if this fails that's ok */ exit( 0 ); } if ( face->num_faces==1 ) TestFace(face); else { num = face->num_faces; FT_Done_Face(face); for ( i=0; i\tAdds to list of dirs searched for fonts\n" ); fprintf( stderr, "\t--ext \tAdds to list of extension indicating fonts\n" ); fprintf( stderr, "\t--all \t\tAll non-directory files are assumed to be fonts\n" ); fprintf( stderr, "\t--results \tDirectory in which to place the test fonts.\n" ); fprintf( stderr, "\t--test \tRun a single test on an already existing file.\n" ); fprintf( stderr, "\t--error-count \tIntroduce single byte errors into each font.\n" ); fprintf( stderr, "\t--error-fraction \tIntroduce *filesize single byte errors into each font.\n" ); #ifdef TEST_FREETYPE fprintf( stderr, "\t--rasterize \t\tAttempt to rasterize each glyph.\n" ); fprintf( stderr, "\t--nohints \t\tTurn off hinting.\n" ); fprintf( stderr, "\t--check-outlines \t\tMake sure we can parse the outlines of each glyph.\n" ); #else fprintf( stderr, "\t--command \tProgram to execute.\n" ); #endif fprintf( stderr, "\t--usage \t\tPrint this.\n" ); exit(1); } } if ( allexts ) exts = NULL; else if ( ecnt==0 ) exts = default_ext_list; if ( dcnt==0 ) dirs = default_dir_list; if ( testfile!=NULL ) ExecuteTest(testfile); /* This should never return */ time(&now); srandom(now); FindFonts(dirs,exts); mkdir(results_dir,0755); forever do_test(); return( 0 ); }