PageRenderTime 1752ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/gfx/ots/src/ots.cc

https://github.com/marcussaad/firefox
C++ | 772 lines | 598 code | 107 blank | 67 comment | 156 complexity | 79575d543e5ce278d37d97df8c1d6b39 MD5 | raw file
Possible License(s): JSON, LGPL-2.1, AGPL-1.0, MPL-2.0-no-copyleft-exception, MPL-2.0, BSD-3-Clause, LGPL-3.0, BSD-2-Clause, MIT, Apache-2.0, GPL-2.0, 0BSD
  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. #include "ots.h"
  5. #include <sys/types.h>
  6. #include <zlib.h>
  7. #include <algorithm>
  8. #include <cstdlib>
  9. #include <cstring>
  10. #include <limits>
  11. #include <map>
  12. #include <vector>
  13. // The OpenType Font File
  14. // http://www.microsoft.com/typography/otspec/cmap.htm
  15. namespace {
  16. bool g_debug_output = true;
  17. #ifdef MOZ_OTS_REPORT_ERRORS
  18. // Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
  19. #define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_)
  20. #define OTS_FAILURE_MSG_HDR(msg_) OTS_FAILURE_MSG_(header, msg_)
  21. #else
  22. #define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE()
  23. #define OTS_FAILURE_MSG_HDR(msg_) OTS_FAILURE()
  24. #endif
  25. struct OpenTypeTable {
  26. uint32_t tag;
  27. uint32_t chksum;
  28. uint32_t offset;
  29. uint32_t length;
  30. uint32_t uncompressed_length;
  31. };
  32. // Round a value up to the nearest multiple of 4. Don't round the value in the
  33. // case that rounding up overflows.
  34. template<typename T> T Round4(T value) {
  35. if (std::numeric_limits<T>::max() - value < 3) {
  36. return value;
  37. }
  38. return (value + 3) & ~3;
  39. }
  40. bool CheckTag(uint32_t tag_value) {
  41. for (unsigned i = 0; i < 4; ++i) {
  42. const uint32_t check = tag_value & 0xff;
  43. if (check < 32 || check > 126) {
  44. return false; // non-ASCII character found.
  45. }
  46. tag_value >>= 8;
  47. }
  48. return true;
  49. }
  50. uint32_t Tag(const char *tag_str) {
  51. uint32_t ret;
  52. std::memcpy(&ret, tag_str, 4);
  53. return ret;
  54. }
  55. struct OutputTable {
  56. uint32_t tag;
  57. size_t offset;
  58. size_t length;
  59. uint32_t chksum;
  60. static bool SortByTag(const OutputTable& a, const OutputTable& b) {
  61. const uint32_t atag = ntohl(a.tag);
  62. const uint32_t btag = ntohl(b.tag);
  63. return atag < btag;
  64. }
  65. };
  66. struct Arena {
  67. public:
  68. ~Arena() {
  69. for (std::vector<uint8_t*>::iterator
  70. i = hunks_.begin(); i != hunks_.end(); ++i) {
  71. delete[] *i;
  72. }
  73. }
  74. uint8_t* Allocate(size_t length) {
  75. uint8_t* p = new uint8_t[length];
  76. hunks_.push_back(p);
  77. return p;
  78. }
  79. private:
  80. std::vector<uint8_t*> hunks_;
  81. };
  82. const struct {
  83. const char* tag;
  84. bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length);
  85. bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file);
  86. bool (*should_serialise)(ots::OpenTypeFile *file);
  87. void (*free)(ots::OpenTypeFile *file);
  88. bool required;
  89. } table_parsers[] = {
  90. { "maxp", ots::ots_maxp_parse, ots::ots_maxp_serialise,
  91. ots::ots_maxp_should_serialise, ots::ots_maxp_free, true },
  92. { "head", ots::ots_head_parse, ots::ots_head_serialise,
  93. ots::ots_head_should_serialise, ots::ots_head_free, true },
  94. { "OS/2", ots::ots_os2_parse, ots::ots_os2_serialise,
  95. ots::ots_os2_should_serialise, ots::ots_os2_free, true },
  96. { "cmap", ots::ots_cmap_parse, ots::ots_cmap_serialise,
  97. ots::ots_cmap_should_serialise, ots::ots_cmap_free, true },
  98. { "hhea", ots::ots_hhea_parse, ots::ots_hhea_serialise,
  99. ots::ots_hhea_should_serialise, ots::ots_hhea_free, true },
  100. { "hmtx", ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
  101. ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true },
  102. { "name", ots::ots_name_parse, ots::ots_name_serialise,
  103. ots::ots_name_should_serialise, ots::ots_name_free, true },
  104. { "post", ots::ots_post_parse, ots::ots_post_serialise,
  105. ots::ots_post_should_serialise, ots::ots_post_free, true },
  106. { "loca", ots::ots_loca_parse, ots::ots_loca_serialise,
  107. ots::ots_loca_should_serialise, ots::ots_loca_free, false },
  108. { "glyf", ots::ots_glyf_parse, ots::ots_glyf_serialise,
  109. ots::ots_glyf_should_serialise, ots::ots_glyf_free, false },
  110. { "CFF ", ots::ots_cff_parse, ots::ots_cff_serialise,
  111. ots::ots_cff_should_serialise, ots::ots_cff_free, false },
  112. { "VDMX", ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
  113. ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false },
  114. { "hdmx", ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
  115. ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false },
  116. { "gasp", ots::ots_gasp_parse, ots::ots_gasp_serialise,
  117. ots::ots_gasp_should_serialise, ots::ots_gasp_free, false },
  118. { "cvt ", ots::ots_cvt_parse, ots::ots_cvt_serialise,
  119. ots::ots_cvt_should_serialise, ots::ots_cvt_free, false },
  120. { "fpgm", ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
  121. ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false },
  122. { "prep", ots::ots_prep_parse, ots::ots_prep_serialise,
  123. ots::ots_prep_should_serialise, ots::ots_prep_free, false },
  124. { "LTSH", ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
  125. ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false },
  126. { "VORG", ots::ots_vorg_parse, ots::ots_vorg_serialise,
  127. ots::ots_vorg_should_serialise, ots::ots_vorg_free, false },
  128. { "kern", ots::ots_kern_parse, ots::ots_kern_serialise,
  129. ots::ots_kern_should_serialise, ots::ots_kern_free, false },
  130. // We need to parse GDEF table in advance of parsing GSUB/GPOS tables
  131. // because they could refer GDEF table.
  132. { "GDEF", ots::ots_gdef_parse, ots::ots_gdef_serialise,
  133. ots::ots_gdef_should_serialise, ots::ots_gdef_free, false },
  134. { "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise,
  135. ots::ots_gpos_should_serialise, ots::ots_gpos_free, false },
  136. { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise,
  137. ots::ots_gsub_should_serialise, ots::ots_gsub_free, false },
  138. { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise,
  139. ots::ots_vhea_should_serialise, ots::ots_vhea_free, false },
  140. { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
  141. ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false },
  142. // SILGraphite layout tables - not actually parsed, just copied
  143. { "Silf", ots::ots_silf_parse, ots::ots_silf_serialise,
  144. ots::ots_silf_should_serialise, ots::ots_silf_free, false },
  145. { "Sill", ots::ots_sill_parse, ots::ots_sill_serialise,
  146. ots::ots_sill_should_serialise, ots::ots_sill_free, false },
  147. { "Gloc", ots::ots_gloc_parse, ots::ots_gloc_serialise,
  148. ots::ots_gloc_should_serialise, ots::ots_gloc_free, false },
  149. { "Glat", ots::ots_glat_parse, ots::ots_glat_serialise,
  150. ots::ots_glat_should_serialise, ots::ots_glat_free, false },
  151. { "Feat", ots::ots_feat_parse, ots::ots_feat_serialise,
  152. ots::ots_feat_should_serialise, ots::ots_feat_free, false },
  153. // SVG glyph table
  154. { "SVG ", ots::ots_svg_parse, ots::ots_svg_serialise,
  155. ots::ots_svg_should_serialise, ots::ots_svg_free, false},
  156. // TODO(bashi): Support mort, base, and jstf tables.
  157. { 0, NULL, NULL, NULL, NULL, false },
  158. };
  159. bool IsValidVersionTag(uint32_t tag) {
  160. return tag == Tag("\x00\x01\x00\x00") ||
  161. // OpenType fonts with CFF data have 'OTTO' tag.
  162. tag == Tag("OTTO") ||
  163. // Older Mac fonts might have 'true' or 'typ1' tag.
  164. tag == Tag("true") ||
  165. tag == Tag("typ1");
  166. }
  167. bool ProcessGeneric(ots::OpenTypeFile *header,
  168. uint32_t signature,
  169. ots::OTSStream *output,
  170. const uint8_t *data, size_t length,
  171. const std::vector<OpenTypeTable>& tables,
  172. ots::Buffer& file);
  173. bool ProcessTTF(ots::OpenTypeFile *header,
  174. ots::OTSStream *output, const uint8_t *data, size_t length) {
  175. ots::Buffer file(data, length);
  176. // we disallow all files > 1GB in size for sanity.
  177. if (length > 1024 * 1024 * 1024) {
  178. return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
  179. }
  180. if (!file.ReadTag(&header->version)) {
  181. return OTS_FAILURE_MSG_HDR("error reading version tag");
  182. }
  183. if (!IsValidVersionTag(header->version)) {
  184. return OTS_FAILURE_MSG_HDR("invalid version tag");
  185. }
  186. if (!file.ReadU16(&header->num_tables) ||
  187. !file.ReadU16(&header->search_range) ||
  188. !file.ReadU16(&header->entry_selector) ||
  189. !file.ReadU16(&header->range_shift)) {
  190. return OTS_FAILURE_MSG_HDR("error reading table directory search header");
  191. }
  192. // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid
  193. // overflow num_tables is, at most, 2^16 / 16 = 2^12
  194. if (header->num_tables >= 4096 || header->num_tables < 1) {
  195. return OTS_FAILURE_MSG_HDR("excessive (or zero) number of tables");
  196. }
  197. unsigned max_pow2 = 0;
  198. while (1u << (max_pow2 + 1) <= header->num_tables) {
  199. max_pow2++;
  200. }
  201. const uint16_t expected_search_range = (1u << max_pow2) << 4;
  202. // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
  203. // http://www.princexml.com/fonts/ have unexpected search_range value.
  204. if (header->search_range != expected_search_range) {
  205. OTS_WARNING("bad search range");
  206. header->search_range = expected_search_range; // Fix the value.
  207. }
  208. // entry_selector is Log2(maximum power of 2 <= numTables)
  209. if (header->entry_selector != max_pow2) {
  210. return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
  211. }
  212. // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
  213. // doesn't over flow because we range checked it above. Also, we know that
  214. // it's > header->search_range by construction of search_range.
  215. const uint32_t expected_range_shift
  216. = 16 * header->num_tables - header->search_range;
  217. if (header->range_shift != expected_range_shift) {
  218. OTS_WARNING("bad range shift");
  219. header->range_shift = expected_range_shift; // the same as above.
  220. }
  221. // Next up is the list of tables.
  222. std::vector<OpenTypeTable> tables;
  223. for (unsigned i = 0; i < header->num_tables; ++i) {
  224. OpenTypeTable table;
  225. if (!file.ReadTag(&table.tag) ||
  226. !file.ReadU32(&table.chksum) ||
  227. !file.ReadU32(&table.offset) ||
  228. !file.ReadU32(&table.length)) {
  229. return OTS_FAILURE_MSG_HDR("error reading table directory");
  230. }
  231. table.uncompressed_length = table.length;
  232. tables.push_back(table);
  233. }
  234. return ProcessGeneric(header, header->version, output, data, length,
  235. tables, file);
  236. }
  237. bool ProcessWOFF(ots::OpenTypeFile *header,
  238. ots::OTSStream *output, const uint8_t *data, size_t length) {
  239. ots::Buffer file(data, length);
  240. // we disallow all files > 1GB in size for sanity.
  241. if (length > 1024 * 1024 * 1024) {
  242. return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
  243. }
  244. uint32_t woff_tag;
  245. if (!file.ReadTag(&woff_tag)) {
  246. return OTS_FAILURE_MSG_HDR("error reading WOFF marker");
  247. }
  248. if (woff_tag != Tag("wOFF")) {
  249. return OTS_FAILURE_MSG_HDR("invalid WOFF marker");
  250. }
  251. if (!file.ReadTag(&header->version)) {
  252. return OTS_FAILURE_MSG_HDR("error reading version tag");
  253. }
  254. if (!IsValidVersionTag(header->version)) {
  255. return OTS_FAILURE_MSG_HDR("invalid version tag");
  256. }
  257. header->search_range = 0;
  258. header->entry_selector = 0;
  259. header->range_shift = 0;
  260. uint32_t reported_length;
  261. if (!file.ReadU32(&reported_length) || length != reported_length) {
  262. return OTS_FAILURE_MSG_HDR("incorrect file size in WOFF header");
  263. }
  264. if (!file.ReadU16(&header->num_tables) || !header->num_tables) {
  265. return OTS_FAILURE_MSG_HDR("error reading number of tables");
  266. }
  267. uint16_t reserved_value;
  268. if (!file.ReadU16(&reserved_value) || reserved_value) {
  269. return OTS_FAILURE_MSG_HDR("error in reserved field of WOFF header");
  270. }
  271. uint32_t reported_total_sfnt_size;
  272. if (!file.ReadU32(&reported_total_sfnt_size)) {
  273. return OTS_FAILURE_MSG_HDR("error reading total sfnt size");
  274. }
  275. // We don't care about these fields of the header:
  276. // uint16_t major_version, minor_version
  277. if (!file.Skip(2 * 2)) {
  278. return OTS_FAILURE_MSG_HDR("error skipping WOFF header fields");
  279. }
  280. // Checks metadata block size.
  281. uint32_t meta_offset;
  282. uint32_t meta_length;
  283. uint32_t meta_length_orig;
  284. if (!file.ReadU32(&meta_offset) ||
  285. !file.ReadU32(&meta_length) ||
  286. !file.ReadU32(&meta_length_orig)) {
  287. return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
  288. }
  289. if (meta_offset) {
  290. if (meta_offset >= length || length - meta_offset < meta_length) {
  291. return OTS_FAILURE_MSG_HDR("invalid metadata block location/size");
  292. }
  293. }
  294. // Checks private data block size.
  295. uint32_t priv_offset;
  296. uint32_t priv_length;
  297. if (!file.ReadU32(&priv_offset) ||
  298. !file.ReadU32(&priv_length)) {
  299. return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
  300. }
  301. if (priv_offset) {
  302. if (priv_offset >= length || length - priv_offset < priv_length) {
  303. return OTS_FAILURE_MSG_HDR("invalid private block location/size");
  304. }
  305. }
  306. // Next up is the list of tables.
  307. std::vector<OpenTypeTable> tables;
  308. uint32_t first_index = 0;
  309. uint32_t last_index = 0;
  310. // Size of sfnt header plus size of table records.
  311. uint64_t total_sfnt_size = 12 + 16 * header->num_tables;
  312. for (unsigned i = 0; i < header->num_tables; ++i) {
  313. OpenTypeTable table;
  314. if (!file.ReadTag(&table.tag) ||
  315. !file.ReadU32(&table.offset) ||
  316. !file.ReadU32(&table.length) ||
  317. !file.ReadU32(&table.uncompressed_length) ||
  318. !file.ReadU32(&table.chksum)) {
  319. return OTS_FAILURE_MSG_HDR("error reading table directory");
  320. }
  321. total_sfnt_size += Round4(table.uncompressed_length);
  322. if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) {
  323. return OTS_FAILURE_MSG_HDR("sfnt size overflow");
  324. }
  325. tables.push_back(table);
  326. if (i == 0 || tables[first_index].offset > table.offset)
  327. first_index = i;
  328. if (i == 0 || tables[last_index].offset < table.offset)
  329. last_index = i;
  330. }
  331. if (reported_total_sfnt_size != total_sfnt_size) {
  332. return OTS_FAILURE_MSG_HDR("uncompressed sfnt size mismatch");
  333. }
  334. // Table data must follow immediately after the header.
  335. if (tables[first_index].offset != Round4(file.offset())) {
  336. return OTS_FAILURE_MSG_HDR("junk before tables in WOFF file");
  337. }
  338. if (tables[last_index].offset >= length ||
  339. length - tables[last_index].offset < tables[last_index].length) {
  340. return OTS_FAILURE_MSG_HDR("invalid table location/size");
  341. }
  342. // Blocks must follow immediately after the previous block.
  343. // (Except for padding with a maximum of three null bytes)
  344. uint64_t block_end = Round4(
  345. static_cast<uint64_t>(tables[last_index].offset) +
  346. static_cast<uint64_t>(tables[last_index].length));
  347. if (block_end > std::numeric_limits<uint32_t>::max()) {
  348. return OTS_FAILURE_MSG_HDR("invalid table location/size");
  349. }
  350. if (meta_offset) {
  351. if (block_end != meta_offset) {
  352. return OTS_FAILURE_MSG_HDR("invalid metadata block location");
  353. }
  354. block_end = Round4(static_cast<uint64_t>(meta_offset) +
  355. static_cast<uint64_t>(meta_length));
  356. if (block_end > std::numeric_limits<uint32_t>::max()) {
  357. return OTS_FAILURE_MSG_HDR("invalid metadata block size");
  358. }
  359. }
  360. if (priv_offset) {
  361. if (block_end != priv_offset) {
  362. return OTS_FAILURE_MSG_HDR("invalid private block location");
  363. }
  364. block_end = Round4(static_cast<uint64_t>(priv_offset) +
  365. static_cast<uint64_t>(priv_length));
  366. if (block_end > std::numeric_limits<uint32_t>::max()) {
  367. return OTS_FAILURE_MSG_HDR("invalid private block size");
  368. }
  369. }
  370. if (block_end != Round4(length)) {
  371. return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
  372. }
  373. return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
  374. }
  375. bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
  376. ots::OTSStream *output,
  377. const uint8_t *data, size_t length,
  378. const std::vector<OpenTypeTable>& tables,
  379. ots::Buffer& file) {
  380. const size_t data_offset = file.offset();
  381. uint32_t uncompressed_sum = 0;
  382. for (unsigned i = 0; i < header->num_tables; ++i) {
  383. // the tables must be sorted by tag (when taken as big-endian numbers).
  384. // This also remove the possibility of duplicate tables.
  385. if (i) {
  386. const uint32_t this_tag = ntohl(tables[i].tag);
  387. const uint32_t prev_tag = ntohl(tables[i - 1].tag);
  388. if (this_tag <= prev_tag) {
  389. return OTS_FAILURE_MSG_HDR("table directory not correctly ordered");
  390. }
  391. }
  392. // all tag names must be built from printable ASCII characters
  393. if (!CheckTag(tables[i].tag)) {
  394. return OTS_FAILURE_MSG_TAG("invalid table tag", &tables[i].tag);
  395. }
  396. // tables must be 4-byte aligned
  397. if (tables[i].offset & 3) {
  398. return OTS_FAILURE_MSG_TAG("misaligned table", &tables[i].tag);
  399. }
  400. // and must be within the file
  401. if (tables[i].offset < data_offset || tables[i].offset >= length) {
  402. return OTS_FAILURE_MSG_TAG("invalid table offset", &tables[i].tag);
  403. }
  404. // disallow all tables with a zero length
  405. if (tables[i].length < 1) {
  406. // Note: malayalam.ttf has zero length CVT table...
  407. return OTS_FAILURE_MSG_TAG("zero-length table", &tables[i].tag);
  408. }
  409. // disallow all tables with a length > 1GB
  410. if (tables[i].length > 1024 * 1024 * 1024) {
  411. return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", &tables[i].tag);
  412. }
  413. // disallow tables where the uncompressed size is < the compressed size.
  414. if (tables[i].uncompressed_length < tables[i].length) {
  415. return OTS_FAILURE_MSG_TAG("invalid compressed table", &tables[i].tag);
  416. }
  417. if (tables[i].uncompressed_length > tables[i].length) {
  418. // We'll probably be decompressing this table.
  419. // disallow all tables which uncompress to > 30 MB
  420. if (tables[i].uncompressed_length > 30 * 1024 * 1024) {
  421. return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", &tables[i].tag);
  422. }
  423. if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
  424. return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", &tables[i].tag);
  425. }
  426. uncompressed_sum += tables[i].uncompressed_length;
  427. }
  428. // since we required that the file be < 1GB in length, and that the table
  429. // length is < 1GB, the following addtion doesn't overflow
  430. uint32_t end_byte = tables[i].offset + tables[i].length;
  431. // Tables in the WOFF file must be aligned 4-byte boundary.
  432. if (signature == Tag("wOFF")) {
  433. end_byte = Round4(end_byte);
  434. }
  435. if (!end_byte || end_byte > length) {
  436. return OTS_FAILURE_MSG_TAG("table overruns end of file", &tables[i].tag);
  437. }
  438. }
  439. // All decompressed tables uncompressed must be <= 30MB.
  440. if (uncompressed_sum > 30 * 1024 * 1024) {
  441. return OTS_FAILURE_MSG_HDR("uncompressed sum exceeds 30MB");
  442. }
  443. std::map<uint32_t, OpenTypeTable> table_map;
  444. for (unsigned i = 0; i < header->num_tables; ++i) {
  445. table_map[tables[i].tag] = tables[i];
  446. }
  447. // check that the tables are not overlapping.
  448. std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
  449. for (unsigned i = 0; i < header->num_tables; ++i) {
  450. overlap_checker.push_back(
  451. std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */));
  452. overlap_checker.push_back(
  453. std::make_pair(tables[i].offset + tables[i].length,
  454. static_cast<uint8_t>(0) /* end */));
  455. }
  456. std::sort(overlap_checker.begin(), overlap_checker.end());
  457. int overlap_count = 0;
  458. for (unsigned i = 0; i < overlap_checker.size(); ++i) {
  459. overlap_count += (overlap_checker[i].second ? 1 : -1);
  460. if (overlap_count > 1) {
  461. return OTS_FAILURE_MSG_HDR("overlapping tables");
  462. }
  463. }
  464. Arena arena;
  465. for (unsigned i = 0; ; ++i) {
  466. if (table_parsers[i].parse == NULL) break;
  467. const std::map<uint32_t, OpenTypeTable>::const_iterator it
  468. = table_map.find(Tag(table_parsers[i].tag));
  469. if (it == table_map.end()) {
  470. if (table_parsers[i].required) {
  471. return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag);
  472. }
  473. continue;
  474. }
  475. const uint8_t* table_data;
  476. size_t table_length;
  477. if (it->second.uncompressed_length != it->second.length) {
  478. // compressed table. Need to uncompress into memory first.
  479. table_length = it->second.uncompressed_length;
  480. table_data = arena.Allocate(table_length);
  481. uLongf dest_len = table_length;
  482. int r = uncompress((Bytef*) table_data, &dest_len,
  483. data + it->second.offset, it->second.length);
  484. if (r != Z_OK || dest_len != table_length) {
  485. return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
  486. }
  487. } else {
  488. // uncompressed table. We can process directly from memory.
  489. table_data = data + it->second.offset;
  490. table_length = it->second.length;
  491. }
  492. if (!table_parsers[i].parse(header, table_data, table_length)) {
  493. // TODO: parsers should generate specific messages detailing the failure;
  494. // once those are all added, we won't need a generic failure message here
  495. return OTS_FAILURE_MSG_TAG("failed to parse table", table_parsers[i].tag);
  496. }
  497. }
  498. if (header->cff) {
  499. // font with PostScript glyph
  500. if (header->version != Tag("OTTO")) {
  501. return OTS_FAILURE_MSG_HDR("wrong font version for PostScript glyph data");
  502. }
  503. if (header->glyf || header->loca) {
  504. // mixing outline formats is not recommended
  505. return OTS_FAILURE_MSG_HDR("font contains both PS and TT glyphs");
  506. }
  507. } else {
  508. if (!header->glyf || !header->loca) {
  509. // No TrueType glyph found.
  510. // Note: bitmap-only fonts are not supported.
  511. return OTS_FAILURE_MSG_HDR("neither PS nor TT glyphs present");
  512. }
  513. }
  514. unsigned num_output_tables = 0;
  515. for (unsigned i = 0; ; ++i) {
  516. if (table_parsers[i].parse == NULL) {
  517. break;
  518. }
  519. if (table_parsers[i].should_serialise(header)) {
  520. num_output_tables++;
  521. }
  522. }
  523. unsigned max_pow2 = 0;
  524. while (1u << (max_pow2 + 1) <= num_output_tables) {
  525. max_pow2++;
  526. }
  527. const uint16_t output_search_range = (1u << max_pow2) << 4;
  528. // most of the errors here are highly unlikely - they'd only occur if the
  529. // output stream returns a failure, e.g. lack of space to write
  530. output->ResetChecksum();
  531. if (!output->WriteTag(header->version) ||
  532. !output->WriteU16(num_output_tables) ||
  533. !output->WriteU16(output_search_range) ||
  534. !output->WriteU16(max_pow2) ||
  535. !output->WriteU16((num_output_tables << 4) - output_search_range)) {
  536. return OTS_FAILURE_MSG_HDR("error writing output");
  537. }
  538. const uint32_t offset_table_chksum = output->chksum();
  539. const size_t table_record_offset = output->Tell();
  540. if (!output->Pad(16 * num_output_tables)) {
  541. return OTS_FAILURE_MSG_HDR("error writing output");
  542. }
  543. std::vector<OutputTable> out_tables;
  544. size_t head_table_offset = 0;
  545. for (unsigned i = 0; ; ++i) {
  546. if (table_parsers[i].parse == NULL) {
  547. break;
  548. }
  549. if (!table_parsers[i].should_serialise(header)) {
  550. continue;
  551. }
  552. OutputTable out;
  553. uint32_t tag = Tag(table_parsers[i].tag);
  554. out.tag = tag;
  555. out.offset = output->Tell();
  556. output->ResetChecksum();
  557. if (tag == Tag("head")) {
  558. head_table_offset = out.offset;
  559. }
  560. if (!table_parsers[i].serialise(output, header)) {
  561. return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].tag);
  562. }
  563. const size_t end_offset = output->Tell();
  564. if (end_offset <= out.offset) {
  565. // paranoid check. |end_offset| is supposed to be greater than the offset,
  566. // as long as the Tell() interface is implemented correctly.
  567. return OTS_FAILURE_MSG_HDR("error writing output");
  568. }
  569. out.length = end_offset - out.offset;
  570. // align tables to four bytes
  571. if (!output->Pad((4 - (end_offset & 3)) % 4)) {
  572. return OTS_FAILURE_MSG_HDR("error writing output");
  573. }
  574. out.chksum = output->chksum();
  575. out_tables.push_back(out);
  576. }
  577. const size_t end_of_file = output->Tell();
  578. // Need to sort the output tables for inclusion in the file
  579. std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag);
  580. if (!output->Seek(table_record_offset)) {
  581. return OTS_FAILURE_MSG_HDR("error writing output");
  582. }
  583. output->ResetChecksum();
  584. uint32_t tables_chksum = 0;
  585. for (unsigned i = 0; i < out_tables.size(); ++i) {
  586. if (!output->WriteTag(out_tables[i].tag) ||
  587. !output->WriteU32(out_tables[i].chksum) ||
  588. !output->WriteU32(out_tables[i].offset) ||
  589. !output->WriteU32(out_tables[i].length)) {
  590. return OTS_FAILURE_MSG_HDR("error writing output");
  591. }
  592. tables_chksum += out_tables[i].chksum;
  593. }
  594. const uint32_t table_record_chksum = output->chksum();
  595. // http://www.microsoft.com/typography/otspec/otff.htm
  596. const uint32_t file_chksum
  597. = offset_table_chksum + tables_chksum + table_record_chksum;
  598. const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum;
  599. // seek into the 'head' table and write in the checksum magic value
  600. if (!head_table_offset) {
  601. return OTS_FAILURE_MSG_HDR("internal error!");
  602. }
  603. if (!output->Seek(head_table_offset + 8)) {
  604. return OTS_FAILURE_MSG_HDR("error writing output");
  605. }
  606. if (!output->WriteU32(chksum_magic)) {
  607. return OTS_FAILURE_MSG_HDR("error writing output");
  608. }
  609. if (!output->Seek(end_of_file)) {
  610. return OTS_FAILURE_MSG_HDR("error writing output");
  611. }
  612. return true;
  613. }
  614. } // namespace
  615. namespace ots {
  616. void DisableDebugOutput() {
  617. g_debug_output = false;
  618. }
  619. bool OTS_API Process(OTSStream *output, const uint8_t *data, size_t length,
  620. #ifdef MOZ_OTS_REPORT_ERRORS
  621. MessageFunc message_func, void *user_data,
  622. #endif
  623. bool preserveGraphite) {
  624. OpenTypeFile header;
  625. #ifdef MOZ_OTS_REPORT_ERRORS
  626. header.message_func = message_func;
  627. header.user_data = user_data;
  628. #endif
  629. if (length < 4) {
  630. return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
  631. }
  632. header.preserve_graphite = preserveGraphite;
  633. bool result;
  634. if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
  635. result = ProcessWOFF(&header, output, data, length);
  636. } else {
  637. result = ProcessTTF(&header, output, data, length);
  638. }
  639. for (unsigned i = 0; ; ++i) {
  640. if (table_parsers[i].parse == NULL) break;
  641. table_parsers[i].free(&header);
  642. }
  643. return result;
  644. }
  645. #if !defined(_MSC_VER) && defined(OTS_DEBUG)
  646. bool Failure(const char *f, int l, const char *fn) {
  647. if (g_debug_output) {
  648. std::fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
  649. std::fflush(stderr);
  650. }
  651. return false;
  652. }
  653. void Warning(const char *f, int l, const char *format, ...) {
  654. if (g_debug_output) {
  655. std::fprintf(stderr, "WARNING at %s:%d: ", f, l);
  656. std::va_list va;
  657. va_start(va, format);
  658. std::vfprintf(stderr, format, va);
  659. va_end(va);
  660. std::fprintf(stderr, "\n");
  661. std::fflush(stderr);
  662. }
  663. }
  664. #endif
  665. } // namespace ots