1d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// Copyright (c) 2009 The Chromium Authors. All rights reserved.
2d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// Use of this source code is governed by a BSD-style license that can be
3d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// found in the LICENSE file.
4d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
59601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#if !defined(_MSC_VER)
69601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#ifdef __linux__
79601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Linux
89601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#include <freetype/ftoutln.h>
9d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <ft2build.h>
10d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include FT_FREETYPE_H
119601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else
129601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Mac OS X
139601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#include <ApplicationServices/ApplicationServices.h>  // g++ -framework Cocoa
149601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif  // __linux__
159601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else
169601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Windows
179601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// TODO(yusukes): Support Windows.
189601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif  // _MSC_VER
199601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org
209601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#include <fcntl.h>
21d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <sys/stat.h>
22d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <sys/types.h>
238ad0a175fe440054932dd25ae9b4b1867e66d387yusukes@chromium.org#include <unistd.h>
24d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
25d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstdio>
26d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstdlib>
27d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstring>
28d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
29d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include "opentype-sanitiser.h"
30d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include "ots-memory-stream.h"
31d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
32d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgnamespace {
33d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
349601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#if !defined(_MSC_VER)
359601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#ifdef __linux__
369601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Linux
37d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgvoid LoadChar(FT_Face face, int pt, FT_ULong c) {
38d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  FT_Matrix matrix;
39d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  matrix.xx = matrix.yy = 1 << 16;
40d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  matrix.xy = matrix.yx = 0 << 16;
41d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
42d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  FT_Set_Char_Size(face, pt * (1 << 6), 0, 72, 0);
43d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  FT_Set_Transform(face, &matrix, 0);
44d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  FT_Load_Char(face, c, FT_LOAD_RENDER);
45d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}
46d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
479601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.orgint OpenAndLoadChars(
489601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    const char *file_name, uint8_t *trans_font, size_t trans_len) {
499601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  FT_Library library;
509601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  FT_Error error = FT_Init_FreeType(&library);
519601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  if (error) {
529601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    std::fprintf(stderr, "Failed to initialize FreeType2!\n");
539601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    return 1;
549601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  }
559601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org
56d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  FT_Face trans_face;
579601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  error = FT_New_Memory_Face(library, trans_font, trans_len, 0, &trans_face);
58d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (error) {
59d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    std::fprintf(stderr,
60d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org                 "OK: FreeType2 couldn't open the transcoded font: %s\n",
61d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org                 file_name);
62d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return 0;
63d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
64d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
65d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  static const int kPts[] = {100, 20, 18, 16, 12, 10, 8};  // pt
66d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  static const size_t kPtsLen = sizeof(kPts) / sizeof(kPts[0]);
67d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
68d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  static const int kUnicodeRanges[] = {
69d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    0x0020, 0x007E,  // Basic Latin (ASCII)
70d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    0x00A1, 0x017F,  // Latin-1
71d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    0x1100, 0x11FF,  // Hangul
72d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    0x3040, 0x309F,  // Japanese HIRAGANA letters
73d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    0x3130, 0x318F,  // Hangul
74d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    0x4E00, 0x4F00,  // CJK Kanji/Hanja
75d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    0xAC00, 0xAD00,  // Hangul
76d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  };
77d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  static const size_t kUnicodeRangesLen
78d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      = sizeof(kUnicodeRanges) / sizeof(kUnicodeRanges[0]);
79d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
80d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  for (size_t i = 0; i < kPtsLen; ++i) {
81d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    for (size_t j = 0; j < kUnicodeRangesLen; j += 2) {
82d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      for (int k = 0; k <= kUnicodeRanges[j + 1] - kUnicodeRanges[j]; ++k) {
83d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org        LoadChar(trans_face, kPts[i], kUnicodeRanges[j] + k);
84d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org      }
85d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    }
86d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
87d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
88d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  std::fprintf(stderr, "OK: FreeType2 didn't crash: %s\n", file_name);
89d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  return 0;
90d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}
919601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else
929601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Mac OS X
939601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.orgint OpenAndLoadChars(
949601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    const char *file_name, uint8_t *trans_font, size_t trans_len) {
952e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  CFDataRef data = CFDataCreate(0, trans_font, trans_len);
962e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  if (!data) {
979601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    std::fprintf(stderr,
989601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org                 "OK: font renderer couldn't open the transcoded font: %s\n",
999601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org                 file_name);
1009601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    return 0;
1019601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  }
1029601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org
1032e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
1042e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider);
1052e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  CGDataProviderRelease(dataProvider);
1062e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  CFRelease(data);
1072e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  if (!cgFontRef) {
1089601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    std::fprintf(stderr,
1099601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org                 "OK: font renderer couldn't open the transcoded font: %s\n",
1109601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org                 file_name);
1119601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    return 0;
1129601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  }
1139601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org
1142e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef);
1152e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  CGFontRelease(cgFontRef);
1162e1bb350e46543d05bbe6cb567d62f5182947f30ksakamoto@chromium.org  if (!numGlyphs) {
1179601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    std::fprintf(stderr,
1189601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org                 "OK: font renderer couldn't open the transcoded font: %s\n",
1199601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org                 file_name);
1209601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org    return 0;
1219601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  }
1229601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  std::fprintf(stderr, "OK: font renderer didn't crash: %s\n", file_name);
1239601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  // TODO(yusukes): would be better to perform LoadChar() like Linux.
1249601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  return 0;
1259601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org}
1269601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif  // __linux__
1279601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#else
1289601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// Windows
1299601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org// TODO(yusukes): Support Windows.
1309601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org#endif  // _MSC_VER
131d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
132d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}  // namespace
133d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
134d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgint main(int argc, char **argv) {
135d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  ots::DisableDebugOutput();  // turn off ERROR and WARNING outputs.
136d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
137d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (argc != 2) {
138d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    std::fprintf(stderr, "Usage: %s ttf_or_otf_filename\n", argv[0]);
139d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return 1;
140d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
141d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
142d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  // load the font to memory.
143d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  const int fd = ::open(argv[1], O_RDONLY);
144d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (fd < 0) {
145d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    ::perror("open");
146d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return 1;
147d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
148d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
149d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  struct stat st;
150d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  ::fstat(fd, &st);
151d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  const off_t orig_len = st.st_size;
152d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
153d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  uint8_t *orig_font = new uint8_t[orig_len];
154d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (::read(fd, orig_font, orig_len) != orig_len) {
155d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    std::fprintf(stderr, "Failed to read file!\n");
156d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return 1;
157d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
158d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  ::close(fd);
159d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
160d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  // transcode the malicious font.
161d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  static const size_t kBigPadLen = 1024 * 1024;  // 1MB
162d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  uint8_t *trans_font = new uint8_t[orig_len + kBigPadLen];
163d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  ots::MemoryStream output(trans_font, orig_len + kBigPadLen);
164d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
165d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  bool result = ots::Process(&output, orig_font, orig_len);
166d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  if (!result) {
167d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    std::fprintf(stderr, "OK: the malicious font was filtered: %s\n", argv[1]);
168d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org    return 0;
169d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  }
170d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org  const size_t trans_len = output.Tell();
171d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org
1729601aa951182ae319e52589c2f2858637e76ccb5yusukes@chromium.org  return OpenAndLoadChars(argv[1], trans_font, trans_len);
173d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}
174