1// Copyright (c) 2009 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#if !defined(_WIN32) 6#ifdef __linux__ 7// Linux 8#include <freetype/ftoutln.h> 9#include <ft2build.h> 10#include FT_FREETYPE_H 11#else 12// Mac OS X 13#include <ApplicationServices/ApplicationServices.h> // g++ -framework Cocoa 14#endif // __linux__ 15#include <unistd.h> 16#else 17// Windows 18#include <io.h> 19#include <Windows.h> 20#endif // !defiend(_WIN32) 21 22#include <fcntl.h> 23#include <sys/stat.h> 24 25#include <cstdio> 26#include <cstdlib> 27#include <cstring> 28 29#include "opentype-sanitiser.h" 30#include "ots-memory-stream.h" 31 32namespace { 33 34int Usage(const char *argv0) { 35 std::fprintf(stderr, "Usage: %s <ttf file>\n", argv0); 36 return 1; 37} 38 39bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size); 40bool DumpResults(const uint8_t *result1, const size_t len1, 41 const uint8_t *result2, const size_t len2); 42 43#if defined(_WIN32) 44#define ADDITIONAL_OPEN_FLAGS O_BINARY 45#else 46#define ADDITIONAL_OPEN_FLAGS 0 47#endif 48 49bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size) { 50 const int fd = open(file_name, O_RDONLY | ADDITIONAL_OPEN_FLAGS); 51 if (fd < 0) { 52 return false; 53 } 54 55 struct stat st; 56 fstat(fd, &st); 57 58 *file_size = st.st_size; 59 *data = new uint8_t[st.st_size]; 60 if (read(fd, *data, st.st_size) != st.st_size) { 61 close(fd); 62 return false; 63 } 64 close(fd); 65 return true; 66} 67 68bool DumpResults(const uint8_t *result1, const size_t len1, 69 const uint8_t *result2, const size_t len2) { 70 int fd1 = open("out1.ttf", 71 O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600); 72 int fd2 = open("out2.ttf", 73 O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600); 74 if (fd1 < 0 || fd2 < 0) { 75 perror("opening output file"); 76 return false; 77 } 78 if ((write(fd1, result1, len1) < 0) || 79 (write(fd2, result2, len2) < 0)) { 80 perror("writing output file"); 81 close(fd1); 82 close(fd2); 83 return false; 84 } 85 close(fd1); 86 close(fd2); 87 return true; 88} 89 90// Platform specific implementations. 91bool VerifyTranscodedFont(uint8_t *result, const size_t len); 92 93#if defined(__linux__) 94// Linux 95bool VerifyTranscodedFont(uint8_t *result, const size_t len) { 96 FT_Library library; 97 FT_Error error = ::FT_Init_FreeType(&library); 98 if (error) { 99 return false; 100 } 101 FT_Face dummy; 102 error = ::FT_New_Memory_Face(library, result, len, 0, &dummy); 103 if (error) { 104 return false; 105 } 106 ::FT_Done_Face(dummy); 107 return true; 108} 109 110#elif defined(__APPLE_CC__) 111// Mac 112bool VerifyTranscodedFont(uint8_t *result, const size_t len) { 113 CFDataRef data = CFDataCreate(0, result, len); 114 if (!data) { 115 return false; 116 } 117 118 CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data); 119 CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider); 120 CGDataProviderRelease(dataProvider); 121 CFRelease(data); 122 if (!cgFontRef) { 123 return false; 124 } 125 126 size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef); 127 CGFontRelease(cgFontRef); 128 if (!numGlyphs) { 129 return false; 130 } 131 return true; 132} 133 134#elif defined(_WIN32) 135// Windows 136bool VerifyTranscodedFont(uint8_t *result, const size_t len) { 137 DWORD num_fonts = 0; 138 HANDLE handle = AddFontMemResourceEx(result, len, 0, &num_fonts); 139 if (!handle) { 140 return false; 141 } 142 RemoveFontMemResourceEx(handle); 143 return true; 144} 145 146#else 147bool VerifyTranscodedFont(uint8_t *result, const size_t len) { 148 std::fprintf(stderr, "Can't verify the transcoded font on this platform.\n"); 149 return false; 150} 151 152#endif 153 154} // namespace 155 156int main(int argc, char **argv) { 157 if (argc != 2) return Usage(argv[0]); 158 159 size_t file_size = 0; 160 uint8_t *data = 0; 161 if (!ReadFile(argv[1], &data, &file_size)) { 162 std::fprintf(stderr, "Failed to read file!\n"); 163 return 1; 164 } 165 166 // A transcoded font is usually smaller than an original font. 167 // However, it can be slightly bigger than the original one due to 168 // name table replacement and/or padding for glyf table. 169 // 170 // However, a WOFF font gets decompressed and so can be *much* larger than 171 // the original. 172 uint8_t *result = new uint8_t[file_size * 8]; 173 ots::MemoryStream output(result, file_size * 8); 174 175 bool r = ots::Process(&output, data, file_size); 176 if (!r) { 177 std::fprintf(stderr, "Failed to sanitise file!\n"); 178 return 1; 179 } 180 const size_t result_len = output.Tell(); 181 delete[] data; 182 183 uint8_t *result2 = new uint8_t[result_len]; 184 ots::MemoryStream output2(result2, result_len); 185 r = ots::Process(&output2, result, result_len); 186 if (!r) { 187 std::fprintf(stderr, "Failed to sanitise previous output!\n"); 188 return 1; 189 } 190 const size_t result2_len = output2.Tell(); 191 192 bool dump_results = false; 193 if (result2_len != result_len) { 194 std::fprintf(stderr, "Outputs differ in length\n"); 195 dump_results = true; 196 } else if (std::memcmp(result2, result, result_len)) { 197 std::fprintf(stderr, "Outputs differ in content\n"); 198 dump_results = true; 199 } 200 201 if (dump_results) { 202 std::fprintf(stderr, "Dumping results to out1.tff and out2.tff\n"); 203 if (!DumpResults(result, result_len, result2, result2_len)) { 204 std::fprintf(stderr, "Failed to dump output files.\n"); 205 return 1; 206 } 207 } 208 209 // Verify that the transcoded font can be opened by the font renderer for 210 // Linux (FreeType2), Mac OS X, or Windows. 211 if (!VerifyTranscodedFont(result, result_len)) { 212 std::fprintf(stderr, "Failed to verify the transcoded font\n"); 213 return 1; 214 } 215 216 return 0; 217} 218