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 5d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include "ots.h" 6d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 7d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <sys/types.h> 85089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org#include <zlib.h> 9d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 10d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <algorithm> 11d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstdlib> 12d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <cstring> 13455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org#include <limits> 14d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <map> 15d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#include <vector> 16d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 1774343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org#include "woff2.h" 1874343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org 19d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org// The OpenType Font File 2093aedf7d27cb93f93077f9f7f758e830a392bdfcbashi@google.com// http://www.microsoft.com/typography/otspec/cmap.htm 21d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 22d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgnamespace { 23d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 24d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgbool g_debug_output = true; 2574343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.orgbool g_enable_woff2 = false; 26d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 27d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgstruct OpenTypeTable { 28d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint32_t tag; 29d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint32_t chksum; 30d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint32_t offset; 31d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint32_t length; 325089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uint32_t uncompressed_length; 33d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}; 34d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 35d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgbool CheckTag(uint32_t tag_value) { 36d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; i < 4; ++i) { 37d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t check = tag_value & 0xff; 38d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (check < 32 || check > 126) { 39d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return false; // non-ASCII character found. 40d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 41d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org tag_value >>= 8; 42d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 43d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return true; 44d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 45d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 46a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.orguint32_t Tag(const char *tag_str) { 47a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org uint32_t ret; 48a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org std::memcpy(&ret, tag_str, 4); 49a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org return ret; 50a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org} 51a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org 52d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgstruct OutputTable { 53d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint32_t tag; 54d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org size_t offset; 55d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org size_t length; 56d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint32_t chksum; 57d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 58d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org static bool SortByTag(const OutputTable& a, const OutputTable& b) { 59d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t atag = ntohl(a.tag); 60d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t btag = ntohl(b.tag); 61d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return atag < btag; 62d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 63d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}; 64d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 655089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.orgstruct Arena { 665089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org public: 675089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org ~Arena() { 685089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org for (std::vector<uint8_t*>::iterator 695089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org i = hunks_.begin(); i != hunks_.end(); ++i) { 705089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org delete[] *i; 715089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 725089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 735089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 745089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uint8_t* Allocate(size_t length) { 755089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uint8_t* p = new uint8_t[length]; 765089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org hunks_.push_back(p); 775089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return p; 785089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 795089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 805089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org private: 815089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org std::vector<uint8_t*> hunks_; 825089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org}; 835089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 84d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgconst struct { 85a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org const char* tag; 86d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length); 87d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file); 88d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org bool (*should_serialise)(ots::OpenTypeFile *file); 89d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org void (*free)(ots::OpenTypeFile *file); 90d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org bool required; 91d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} table_parsers[] = { 92a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "maxp", ots::ots_maxp_parse, ots::ots_maxp_serialise, 93a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_maxp_should_serialise, ots::ots_maxp_free, true }, 94a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "head", ots::ots_head_parse, ots::ots_head_serialise, 95a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_head_should_serialise, ots::ots_head_free, true }, 96a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "OS/2", ots::ots_os2_parse, ots::ots_os2_serialise, 97a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_os2_should_serialise, ots::ots_os2_free, true }, 98a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "cmap", ots::ots_cmap_parse, ots::ots_cmap_serialise, 99a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_cmap_should_serialise, ots::ots_cmap_free, true }, 100a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "hhea", ots::ots_hhea_parse, ots::ots_hhea_serialise, 101a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_hhea_should_serialise, ots::ots_hhea_free, true }, 102a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "hmtx", ots::ots_hmtx_parse, ots::ots_hmtx_serialise, 103a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true }, 104a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "name", ots::ots_name_parse, ots::ots_name_serialise, 105a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_name_should_serialise, ots::ots_name_free, true }, 106a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "post", ots::ots_post_parse, ots::ots_post_serialise, 107a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_post_should_serialise, ots::ots_post_free, true }, 108a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "loca", ots::ots_loca_parse, ots::ots_loca_serialise, 109a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_loca_should_serialise, ots::ots_loca_free, false }, 110a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "glyf", ots::ots_glyf_parse, ots::ots_glyf_serialise, 111a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_glyf_should_serialise, ots::ots_glyf_free, false }, 112a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "CFF ", ots::ots_cff_parse, ots::ots_cff_serialise, 113a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_cff_should_serialise, ots::ots_cff_free, false }, 114a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "VDMX", ots::ots_vdmx_parse, ots::ots_vdmx_serialise, 115a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false }, 116a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "hdmx", ots::ots_hdmx_parse, ots::ots_hdmx_serialise, 117a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false }, 118a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "gasp", ots::ots_gasp_parse, ots::ots_gasp_serialise, 119a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_gasp_should_serialise, ots::ots_gasp_free, false }, 120a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "cvt ", ots::ots_cvt_parse, ots::ots_cvt_serialise, 121a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_cvt_should_serialise, ots::ots_cvt_free, false }, 122a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "fpgm", ots::ots_fpgm_parse, ots::ots_fpgm_serialise, 123a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false }, 124a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "prep", ots::ots_prep_parse, ots::ots_prep_serialise, 125a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_prep_should_serialise, ots::ots_prep_free, false }, 126a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "LTSH", ots::ots_ltsh_parse, ots::ots_ltsh_serialise, 127a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false }, 128a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "VORG", ots::ots_vorg_parse, ots::ots_vorg_serialise, 129a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org ots::ots_vorg_should_serialise, ots::ots_vorg_free, false }, 130a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "kern", ots::ots_kern_parse, ots::ots_kern_serialise, 131f12575f6e5a4b053188d4e205ae6ceb95a60fb2cyusukes@chromium.org ots::ots_kern_should_serialise, ots::ots_kern_free, false }, 132ced7112cb41d09cd344bbe4b20459049d6039491bashi@chromium.org // We need to parse GDEF table in advance of parsing GSUB/GPOS tables 133ced7112cb41d09cd344bbe4b20459049d6039491bashi@chromium.org // because they could refer GDEF table. 134a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "GDEF", ots::ots_gdef_parse, ots::ots_gdef_serialise, 13500b790a7ad0d65b066a61760f58e7dbfc055cd2dbashi@google.com ots::ots_gdef_should_serialise, ots::ots_gdef_free, false }, 136a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise, 137ced7112cb41d09cd344bbe4b20459049d6039491bashi@chromium.org ots::ots_gpos_should_serialise, ots::ots_gpos_free, false }, 138a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise, 139a574866c0e4b1539098e64422f59d01c80cea6cfbashi@chromium.org ots::ots_gsub_should_serialise, ots::ots_gsub_free, false }, 140a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise, 1414dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org ots::ots_vhea_should_serialise, ots::ots_vhea_free, false }, 142a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise, 1434dcad600f99d85201d9db3cb8bee166ec2aaca85bashi@chromium.org ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false }, 144eea48361b1ffcc1bded0ba25c8f747e634cd8e51ksakamoto@chromium.org { "MATH", ots::ots_math_parse, ots::ots_math_serialise, 145eea48361b1ffcc1bded0ba25c8f747e634cd8e51ksakamoto@chromium.org ots::ots_math_should_serialise, ots::ots_math_free, false }, 1466462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org { "CBDT", ots::ots_cbdt_parse, ots::ots_cbdt_serialise, 1476462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org ots::ots_cbdt_should_serialise, ots::ots_cbdt_free, false }, 1486462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org { "CBLC", ots::ots_cblc_parse, ots::ots_cblc_serialise, 1496462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org ots::ots_cblc_should_serialise, ots::ots_cblc_free, false }, 150a574866c0e4b1539098e64422f59d01c80cea6cfbashi@chromium.org // TODO(bashi): Support mort, base, and jstf tables. 151a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org { 0, NULL, NULL, NULL, NULL, false }, 152d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org}; 153d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 1546926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.orgbool ProcessGeneric(ots::OpenTypeFile *header, 1556926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org uint32_t signature, 1566926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org ots::OTSStream *output, 1575089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org const uint8_t *data, size_t length, 1585089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org const std::vector<OpenTypeTable>& tables, 1595089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org ots::Buffer& file); 1605089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 1615089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.orgbool ProcessTTF(ots::OpenTypeFile *header, 1625089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org ots::OTSStream *output, const uint8_t *data, size_t length) { 163d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org ots::Buffer file(data, length); 164d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 165d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // we disallow all files > 1GB in size for sanity. 166d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (length > 1024 * 1024 * 1024) { 167d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 168d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 169d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 170d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!file.ReadTag(&header->version)) { 171d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 172d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 17374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org if (!ots::IsValidVersionTag(header->version)) { 1745089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 175d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 176d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 177d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!file.ReadU16(&header->num_tables) || 178d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !file.ReadU16(&header->search_range) || 179d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !file.ReadU16(&header->entry_selector) || 180d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !file.ReadU16(&header->range_shift)) { 181d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 182d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 183d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 184d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid 185d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // overflow num_tables is, at most, 2^16 / 16 = 2^12 186d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (header->num_tables >= 4096 || header->num_tables < 1) { 187d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 188d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 189d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 190d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org unsigned max_pow2 = 0; 191d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org while (1u << (max_pow2 + 1) <= header->num_tables) { 192d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org max_pow2++; 193d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 194d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint16_t expected_search_range = (1u << max_pow2) << 4; 195d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 196d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in 197a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org // http://www.princexml.com/fonts/ have unexpected search_range value. 198d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (header->search_range != expected_search_range) { 199d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org OTS_WARNING("bad search range"); 200d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org header->search_range = expected_search_range; // Fix the value. 201d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 202d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 203d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // entry_selector is Log2(maximum power of 2 <= numTables) 204d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (header->entry_selector != max_pow2) { 205d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 206d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 207d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 208d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // range_shift is NumTables x 16-searchRange. We know that 16*num_tables 209d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // doesn't over flow because we range checked it above. Also, we know that 210d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // it's > header->search_range by construction of search_range. 211d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t expected_range_shift 212d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org = 16 * header->num_tables - header->search_range; 213d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (header->range_shift != expected_range_shift) { 214d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org OTS_WARNING("bad range shift"); 215d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org header->range_shift = expected_range_shift; // the same as above. 216d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 217d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 218d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // Next up is the list of tables. 219d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::vector<OpenTypeTable> tables; 220d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 221d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; i < header->num_tables; ++i) { 222d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org OpenTypeTable table; 223d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!file.ReadTag(&table.tag) || 224d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !file.ReadU32(&table.chksum) || 225d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !file.ReadU32(&table.offset) || 226d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !file.ReadU32(&table.length)) { 227d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 228d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 229d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 2305089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org table.uncompressed_length = table.length; 231d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org tables.push_back(table); 232d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 233d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 2346926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org return ProcessGeneric(header, header->version, output, data, length, 2356926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org tables, file); 2365089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org} 2375089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 2385089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.orgbool ProcessWOFF(ots::OpenTypeFile *header, 2395089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org ots::OTSStream *output, const uint8_t *data, size_t length) { 2405089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org ots::Buffer file(data, length); 2415089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 2425089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // we disallow all files > 1GB in size for sanity. 2435089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (length > 1024 * 1024 * 1024) { 2445089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2455089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2465089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 2475089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uint32_t woff_tag; 2485089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (!file.ReadTag(&woff_tag)) { 2495089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2505089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2515089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 252a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org if (woff_tag != Tag("wOFF")) { 2535089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2545089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2555089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 2565089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (!file.ReadTag(&header->version)) { 2575089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2585089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 25974343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org if (!ots::IsValidVersionTag(header->version)) { 2605089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2615089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2625089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 2635089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org header->search_range = 0; 2645089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org header->entry_selector = 0; 2655089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org header->range_shift = 0; 2665089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 2675089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uint32_t reported_length; 2685089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (!file.ReadU32(&reported_length) || length != reported_length) { 2695089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2705089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2715089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 272455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (!file.ReadU16(&header->num_tables) || !header->num_tables) { 2735089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2745089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2755089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 2765089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uint16_t reserved_value; 2775089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (!file.ReadU16(&reserved_value) || reserved_value) { 2785089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2795089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2805089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 281455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t reported_total_sfnt_size; 282455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (!file.ReadU32(&reported_total_sfnt_size)) { 283455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 284455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 285455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org 2865089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // We don't care about these fields of the header: 2875089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // uint16_t major_version, minor_version 288455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (!file.Skip(2 * 2)) { 2895089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 2905089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 2915089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 292455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org // Checks metadata block size. 293455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t meta_offset; 294455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t meta_length; 295455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t meta_length_orig; 296455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (!file.ReadU32(&meta_offset) || 297455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org !file.ReadU32(&meta_length) || 298455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org !file.ReadU32(&meta_length_orig)) { 299455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 300455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 301455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (meta_offset) { 302455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (meta_offset >= length || length - meta_offset < meta_length) { 303455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 304455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 305455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 306455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org 307455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org // Checks private data block size. 308455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t priv_offset; 309455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t priv_length; 310455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (!file.ReadU32(&priv_offset) || 311455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org !file.ReadU32(&priv_length)) { 312455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 313455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 314455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (priv_offset) { 315455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (priv_offset >= length || length - priv_offset < priv_length) { 316455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 317455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 318455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 319455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org 3205089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // Next up is the list of tables. 3215089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org std::vector<OpenTypeTable> tables; 3225089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 323455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t first_index = 0; 324455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint32_t last_index = 0; 325455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org // Size of sfnt header plus size of table records. 326455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org uint64_t total_sfnt_size = 12 + 16 * header->num_tables; 3275089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org for (unsigned i = 0; i < header->num_tables; ++i) { 3285089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org OpenTypeTable table; 3295089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (!file.ReadTag(&table.tag) || 3305089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org !file.ReadU32(&table.offset) || 3315089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org !file.ReadU32(&table.length) || 3325089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org !file.ReadU32(&table.uncompressed_length) || 3335089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org !file.ReadU32(&table.chksum)) { 3345089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 3355089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 3365089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 33774343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org total_sfnt_size += ots::Round4(table.uncompressed_length); 338455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) { 339455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 340455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 3415089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org tables.push_back(table); 342455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (i == 0 || tables[first_index].offset > table.offset) 343455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org first_index = i; 344455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (i == 0 || tables[last_index].offset < table.offset) 345455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org last_index = i; 346455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 347455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org 348455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (reported_total_sfnt_size != total_sfnt_size) { 349455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 350455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 351455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org 352455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org // Table data must follow immediately after the header. 35374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org if (tables[first_index].offset != ots::Round4(file.offset())) { 354455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 355455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 356455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org 357455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (tables[last_index].offset >= length || 358455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org length - tables[last_index].offset < tables[last_index].length) { 359455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 360455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 361455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org // Blocks must follow immediately after the previous block. 362455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org // (Except for padding with a maximum of three null bytes) 36374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org uint64_t block_end = ots::Round4( 364455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org static_cast<uint64_t>(tables[last_index].offset) + 365455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org static_cast<uint64_t>(tables[last_index].length)); 366455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (block_end > std::numeric_limits<uint32_t>::max()) { 367455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 368455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 369455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (meta_offset) { 370455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (block_end != meta_offset) { 371455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 372455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 37374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org block_end = ots::Round4(static_cast<uint64_t>(meta_offset) + 37474343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org static_cast<uint64_t>(meta_length)); 375455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (block_end > std::numeric_limits<uint32_t>::max()) { 376455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 377455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 378455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 379455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (priv_offset) { 380455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (block_end != priv_offset) { 381455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 382455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 38374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org block_end = ots::Round4(static_cast<uint64_t>(priv_offset) + 38474343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org static_cast<uint64_t>(priv_length)); 385455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org if (block_end > std::numeric_limits<uint32_t>::max()) { 386455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 387455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 388455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org } 38974343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org if (block_end != ots::Round4(length)) { 390455475957de24c9964f45cadf4965c7082d28753bashi@chromium.org return OTS_FAILURE(); 3915089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 3925089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 3936926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org return ProcessGeneric(header, woff_tag, output, data, length, tables, file); 3945089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org} 3955089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 39674343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.orgbool ProcessWOFF2(ots::OpenTypeFile *header, 39774343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org ots::OTSStream *output, const uint8_t *data, size_t length) { 39874343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length); 39974343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org if (decompressed_size == 0) { 40074343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org return OTS_FAILURE(); 40174343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org } 40274343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org // decompressed font must be <= 30MB 40374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org if (decompressed_size > 30 * 1024 * 1024) { 40474343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org return OTS_FAILURE(); 40574343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org } 40674343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org 40774343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org std::vector<uint8_t> decompressed_buffer(decompressed_size); 40874343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size, 40974343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org data, length)) { 41074343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org return OTS_FAILURE(); 41174343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org } 41274343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size); 41374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org} 41474343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org 4156926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.orgbool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, 4166926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org ots::OTSStream *output, 4175089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org const uint8_t *data, size_t length, 4185089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org const std::vector<OpenTypeTable>& tables, 4195089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org ots::Buffer& file) { 420d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const size_t data_offset = file.offset(); 421d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 4225089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uint32_t uncompressed_sum = 0; 4235089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 424d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; i < header->num_tables; ++i) { 425d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // the tables must be sorted by tag (when taken as big-endian numbers). 426d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // This also remove the possibility of duplicate tables. 427d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (i) { 428d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t this_tag = ntohl(tables[i].tag); 429d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t prev_tag = ntohl(tables[i - 1].tag); 430d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (this_tag <= prev_tag) { 431d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 432d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 433d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 434d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 435a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org // all tag names must be built from printable ASCII characters 436d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!CheckTag(tables[i].tag)) { 437d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 438d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 439d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 440d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // tables must be 4-byte aligned 441d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (tables[i].offset & 3) { 442d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 443d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 444d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 445d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // and must be within the file 446d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (tables[i].offset < data_offset || tables[i].offset >= length) { 447d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 448d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 449d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // disallow all tables with a zero length 450d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (tables[i].length < 1) { 451d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // Note: malayalam.ttf has zero length CVT table... 452d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 453d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 454d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // disallow all tables with a length > 1GB 455d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (tables[i].length > 1024 * 1024 * 1024) { 456d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 457d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 4585089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // disallow tables where the uncompressed size is < the compressed size. 4595089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (tables[i].uncompressed_length < tables[i].length) { 4605089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 4615089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 4625089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (tables[i].uncompressed_length > tables[i].length) { 4635089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // We'll probably be decompressing this table. 4645089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 4655089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // disallow all tables which uncompress to > 30 MB 4665089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (tables[i].uncompressed_length > 30 * 1024 * 1024) { 4675089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 4685089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 4695089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) { 4705089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 4715089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 4725089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 4735089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uncompressed_sum += tables[i].uncompressed_length; 4745089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 475d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // since we required that the file be < 1GB in length, and that the table 476d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // length is < 1GB, the following addtion doesn't overflow 4776926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org uint32_t end_byte = tables[i].offset + tables[i].length; 4786926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org // Tables in the WOFF file must be aligned 4-byte boundary. 4796926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org if (signature == Tag("wOFF")) { 48074343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org end_byte = ots::Round4(end_byte); 4816926d5430bbccd1cb4779c495c79707f0daef7c6bashi@chromium.org } 482d892faf3d64fe948e26b273a7a9097c82fe1784bbashi@chromium.org if (!end_byte || end_byte > length) { 483d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 484d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 485d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 486d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 4875089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // All decompressed tables uncompressed must be <= 30MB. 4885089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (uncompressed_sum > 30 * 1024 * 1024) { 4895089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 4905089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 4915089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 492d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::map<uint32_t, OpenTypeTable> table_map; 493d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; i < header->num_tables; ++i) { 494d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org table_map[tables[i].tag] = tables[i]; 495d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 496d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 497d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // check that the tables are not overlapping. 498d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::vector<std::pair<uint32_t, uint8_t> > overlap_checker; 499d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; i < header->num_tables; ++i) { 500d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org overlap_checker.push_back( 50179602bdcdcb2ada735c795fe058fc335d392397fbashi@chromium.org std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */)); 502d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org overlap_checker.push_back( 50379602bdcdcb2ada735c795fe058fc335d392397fbashi@chromium.org std::make_pair(tables[i].offset + tables[i].length, 50479602bdcdcb2ada735c795fe058fc335d392397fbashi@chromium.org static_cast<uint8_t>(0) /* end */)); 505d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 506d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::sort(overlap_checker.begin(), overlap_checker.end()); 507d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org int overlap_count = 0; 508d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; i < overlap_checker.size(); ++i) { 509d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org overlap_count += (overlap_checker[i].second ? 1 : -1); 510d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (overlap_count > 1) { 511d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 512d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 513d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 514d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 5155089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org Arena arena; 5165089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 517d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; ; ++i) { 518d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (table_parsers[i].parse == NULL) break; 519d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 520d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const std::map<uint32_t, OpenTypeTable>::const_iterator it 521a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org = table_map.find(Tag(table_parsers[i].tag)); 522d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 523d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (it == table_map.end()) { 524d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (table_parsers[i].required) { 525d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 526d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 527d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org continue; 528d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 529d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 5305089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org const uint8_t* table_data; 5315089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org size_t table_length; 5325089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 5335089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (it->second.uncompressed_length != it->second.length) { 5345089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // compressed table. Need to uncompress into memory first. 5355089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org table_length = it->second.uncompressed_length; 5365089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org table_data = arena.Allocate(table_length); 5375089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org uLongf dest_len = table_length; 5385089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org int r = uncompress((Bytef*) table_data, &dest_len, 5395089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org data + it->second.offset, it->second.length); 5405089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (r != Z_OK || dest_len != table_length) { 5415089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 5425089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 5435089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } else { 5445089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // uncompressed table. We can process directly from memory. 5455089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org table_data = data + it->second.offset; 5465089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org table_length = it->second.length; 5475089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 5485089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 5495089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (!table_parsers[i].parse(header, table_data, table_length)) { 550d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 551d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 552d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 553d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 554d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (header->cff) { 555d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // font with PostScript glyph 556a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org if (header->version != Tag("OTTO")) { 557d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 558d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 559d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (header->glyf || header->loca) { 5605089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org // mixing outline formats is not recommended 561d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 562d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 563d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } else { 5646462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org if ((!header->glyf || !header->loca) && (!header->cbdt || !header->cblc)) { 5656462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org // No TrueType glyph or color bitmap found. 566d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 567d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 568d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 569d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 570d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org unsigned num_output_tables = 0; 571d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; ; ++i) { 572d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (table_parsers[i].parse == NULL) { 573d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org break; 574d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 575d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 576d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (table_parsers[i].should_serialise(header)) { 577d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org num_output_tables++; 578d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 579d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 580d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 5815089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org unsigned max_pow2 = 0; 582d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org while (1u << (max_pow2 + 1) <= num_output_tables) { 583d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org max_pow2++; 584d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 585d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint16_t output_search_range = (1u << max_pow2) << 4; 586d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 587d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org output->ResetChecksum(); 588d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->WriteTag(header->version) || 589d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !output->WriteU16(num_output_tables) || 590d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !output->WriteU16(output_search_range) || 591d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !output->WriteU16(max_pow2) || 592d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !output->WriteU16((num_output_tables << 4) - output_search_range)) { 593d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 594d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 595d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t offset_table_chksum = output->chksum(); 596d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 597d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const size_t table_record_offset = output->Tell(); 598d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->Pad(16 * num_output_tables)) { 599d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 600d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 601d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 602d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::vector<OutputTable> out_tables; 603d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 604d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org size_t head_table_offset = 0; 605d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; ; ++i) { 606d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (table_parsers[i].parse == NULL) { 607d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org break; 608d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 609d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 610d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!table_parsers[i].should_serialise(header)) { 611d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org continue; 612d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 613d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 614d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org OutputTable out; 615a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org uint32_t tag = Tag(table_parsers[i].tag); 616a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org out.tag = tag; 617d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org out.offset = output->Tell(); 618d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 619d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org output->ResetChecksum(); 620a586240a3330de050e76aef6c2c6f50716f636f5bashi@chromium.org if (tag == Tag("head")) { 621d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org head_table_offset = out.offset; 622d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 623d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!table_parsers[i].serialise(output, header)) { 624d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 625d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 626d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 627d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const size_t end_offset = output->Tell(); 6280881b63704c87303b847e629a06acf0491798624yusukes@chromium.org if (end_offset <= out.offset) { 6290881b63704c87303b847e629a06acf0491798624yusukes@chromium.org // paranoid check. |end_offset| is supposed to be greater than the offset, 6300881b63704c87303b847e629a06acf0491798624yusukes@chromium.org // as long as the Tell() interface is implemented correctly. 6310881b63704c87303b847e629a06acf0491798624yusukes@chromium.org return OTS_FAILURE(); 6320881b63704c87303b847e629a06acf0491798624yusukes@chromium.org } 633d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org out.length = end_offset - out.offset; 634d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 635d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // align tables to four bytes 636d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->Pad((4 - (end_offset & 3)) % 4)) { 637d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 638d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 639d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org out.chksum = output->chksum(); 640d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org out_tables.push_back(out); 641d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 642d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 643d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const size_t end_of_file = output->Tell(); 644d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 645d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // Need to sort the output tables for inclusion in the file 646d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag); 647d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->Seek(table_record_offset)) { 648d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 649d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 650d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 651d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org output->ResetChecksum(); 652d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org uint32_t tables_chksum = 0; 653d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; i < out_tables.size(); ++i) { 654d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->WriteTag(out_tables[i].tag) || 655d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !output->WriteU32(out_tables[i].chksum) || 656d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !output->WriteU32(out_tables[i].offset) || 657d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org !output->WriteU32(out_tables[i].length)) { 658d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 659d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 660d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org tables_chksum += out_tables[i].chksum; 661d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 662d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t table_record_chksum = output->chksum(); 663d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 664d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // http://www.microsoft.com/typography/otspec/otff.htm 665d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t file_chksum 666d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org = offset_table_chksum + tables_chksum + table_record_chksum; 667d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum; 668d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 669d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org // seek into the 'head' table and write in the checksum magic value 670a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org if (!head_table_offset) { 671a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org return OTS_FAILURE(); // not reached. 672a4099a3bb81adafc5593090c1185ec82933a3d6eyusukes@chromium.org } 673d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->Seek(head_table_offset + 8)) { 674d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 675d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 676d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->WriteU32(chksum_magic)) { 677d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 678d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 679d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 680d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (!output->Seek(end_of_file)) { 681d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return OTS_FAILURE(); 682d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 683d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 684d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return true; 685d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 686d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 687d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} // namespace 688d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 689d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgnamespace ots { 690d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 6916462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.orgbool g_drop_color_bitmap_tables = true; 6926462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org 69374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.orgbool IsValidVersionTag(uint32_t tag) { 69474343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org return tag == Tag("\x00\x01\x00\x00") || 69574343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org // OpenType fonts with CFF data have 'OTTO' tag. 69674343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org tag == Tag("OTTO") || 69774343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org // Older Mac fonts might have 'true' or 'typ1' tag. 69874343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org tag == Tag("true") || 69974343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org tag == Tag("typ1"); 70074343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org} 70174343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org 702d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgvoid DisableDebugOutput() { 703d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org g_debug_output = false; 704d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 705d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 70674343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.orgvoid EnableWOFF2() { 70774343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org g_enable_woff2 = true; 70874343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org} 70974343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org 7106462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.orgvoid DoNotDropColorBitmapTables() { 7116462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org g_drop_color_bitmap_tables = false; 7126462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org} 7136462c58fa123bb89baf1ec4b7538d8f2c682dc8bbashi@chromium.org 714d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgbool Process(OTSStream *output, const uint8_t *data, size_t length) { 715d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org OpenTypeFile header; 7165089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (length < 4) { 7175089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org return OTS_FAILURE(); 7185089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 7195089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org 7205089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org bool result; 7215089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { 7225089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org result = ProcessWOFF(&header, output, data, length); 72374343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org } else if (g_enable_woff2 && 72474343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && 72574343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org data[3] == '2') { 72674343ba7bd420519a9a4f7b22977d7771286f6f8ksakamoto@chromium.org result = ProcessWOFF2(&header, output, data, length); 7275089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } else { 7285089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org result = ProcessTTF(&header, output, data, length); 7295089f9c6ecd9b0802f1cf456b69350255a93ae09agl@chromium.org } 730d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 731d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org for (unsigned i = 0; ; ++i) { 732d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (table_parsers[i].parse == NULL) break; 733d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org table_parsers[i].free(&header); 734d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 735d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return result; 736d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 737d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 738d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#if !defined(_MSC_VER) && defined(OTS_DEBUG) 739d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgbool Failure(const char *f, int l, const char *fn) { 740d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (g_debug_output) { 741d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn); 742d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fflush(stderr); 743d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 744d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org return false; 745d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 746d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 747d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.orgvoid Warning(const char *f, int l, const char *format, ...) { 748d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org if (g_debug_output) { 749d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, "WARNING at %s:%d: ", f, l); 750d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::va_list va; 751d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org va_start(va, format); 752d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::vfprintf(stderr, format, va); 753d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org va_end(va); 754d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fprintf(stderr, "\n"); 755d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org std::fflush(stderr); 756d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org } 757d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} 758d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org#endif 759d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org 760d257d186ae2a08042a412824678f98241a1a4f3cyusukes@chromium.org} // namespace ots 761