Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(317)

Side by Side Diff: src/ots.cc

Issue 658573004: Updating to new OTS repo from https://github.com/khaledhosny/ots.git (Closed) Base URL: https://chromium.googlesource.com/external/ots@master
Patch Set: Adding Colored Emoji changes from external/git repo Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« .gitmodules ('K') | « src/ots.h ('k') | src/post.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ots.h" 5 #include "ots.h"
6 6
7 #include <sys/types.h> 7 #include <sys/types.h>
8 #include <zlib.h> 8 #include <zlib.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <cstdlib> 11 #include <cstdlib>
12 #include <cstring> 12 #include <cstring>
13 #include <limits> 13 #include <limits>
14 #include <map> 14 #include <map>
15 #include <vector> 15 #include <vector>
16 16
17 #ifndef OTS_DISABLE_WOFF2
17 #include "woff2.h" 18 #include "woff2.h"
19 #endif
18 20
19 // The OpenType Font File 21 // The OpenType Font File
20 // http://www.microsoft.com/typography/otspec/cmap.htm 22 // http://www.microsoft.com/typography/otspec/cmap.htm
21 23
22 namespace { 24 namespace {
23 25
24 bool g_debug_output = true; 26 bool g_debug_output = true;
25 bool g_enable_woff2 = false; 27 bool g_enable_woff2 = false;
26 28
29 // Generate a message with or without a table tag, when 'header' is the OpenType File pointer
30 #define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_)
31 #define OTS_FAILURE_MSG_HDR(msg_) OTS_FAILURE_MSG_(header, msg_)
32
33
27 struct OpenTypeTable { 34 struct OpenTypeTable {
28 uint32_t tag; 35 uint32_t tag;
29 uint32_t chksum; 36 uint32_t chksum;
30 uint32_t offset; 37 uint32_t offset;
31 uint32_t length; 38 uint32_t length;
32 uint32_t uncompressed_length; 39 uint32_t uncompressed_length;
33 }; 40 };
34 41
35 bool CheckTag(uint32_t tag_value) { 42 bool CheckTag(uint32_t tag_value) {
36 for (unsigned i = 0; i < 4; ++i) { 43 for (unsigned i = 0; i < 4; ++i) {
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
157 const uint8_t *data, size_t length, 164 const uint8_t *data, size_t length,
158 const std::vector<OpenTypeTable>& tables, 165 const std::vector<OpenTypeTable>& tables,
159 ots::Buffer& file); 166 ots::Buffer& file);
160 167
161 bool ProcessTTF(ots::OpenTypeFile *header, 168 bool ProcessTTF(ots::OpenTypeFile *header,
162 ots::OTSStream *output, const uint8_t *data, size_t length) { 169 ots::OTSStream *output, const uint8_t *data, size_t length) {
163 ots::Buffer file(data, length); 170 ots::Buffer file(data, length);
164 171
165 // we disallow all files > 1GB in size for sanity. 172 // we disallow all files > 1GB in size for sanity.
166 if (length > 1024 * 1024 * 1024) { 173 if (length > 1024 * 1024 * 1024) {
167 return OTS_FAILURE(); 174 return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
168 } 175 }
169 176
170 if (!file.ReadTag(&header->version)) { 177 if (!file.ReadTag(&header->version)) {
171 return OTS_FAILURE(); 178 return OTS_FAILURE_MSG_HDR("error reading version tag");
172 } 179 }
173 if (!ots::IsValidVersionTag(header->version)) { 180 if (!ots::IsValidVersionTag(header->version)) {
174 return OTS_FAILURE(); 181 return OTS_FAILURE_MSG_HDR("invalid version tag");
175 } 182 }
176 183
177 if (!file.ReadU16(&header->num_tables) || 184 if (!file.ReadU16(&header->num_tables) ||
178 !file.ReadU16(&header->search_range) || 185 !file.ReadU16(&header->search_range) ||
179 !file.ReadU16(&header->entry_selector) || 186 !file.ReadU16(&header->entry_selector) ||
180 !file.ReadU16(&header->range_shift)) { 187 !file.ReadU16(&header->range_shift)) {
181 return OTS_FAILURE(); 188 return OTS_FAILURE_MSG_HDR("error reading table directory search header");
182 } 189 }
183 190
184 // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid 191 // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid
185 // overflow num_tables is, at most, 2^16 / 16 = 2^12 192 // overflow num_tables is, at most, 2^16 / 16 = 2^12
186 if (header->num_tables >= 4096 || header->num_tables < 1) { 193 if (header->num_tables >= 4096 || header->num_tables < 1) {
187 return OTS_FAILURE(); 194 return OTS_FAILURE_MSG_HDR("excessive (or zero) number of tables");
188 } 195 }
189 196
190 unsigned max_pow2 = 0; 197 unsigned max_pow2 = 0;
191 while (1u << (max_pow2 + 1) <= header->num_tables) { 198 while (1u << (max_pow2 + 1) <= header->num_tables) {
192 max_pow2++; 199 max_pow2++;
193 } 200 }
194 const uint16_t expected_search_range = (1u << max_pow2) << 4; 201 const uint16_t expected_search_range = (1u << max_pow2) << 4;
195 202
196 // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in 203 // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
197 // http://www.princexml.com/fonts/ have unexpected search_range value. 204 // http://www.princexml.com/fonts/ have unexpected search_range value.
198 if (header->search_range != expected_search_range) { 205 if (header->search_range != expected_search_range) {
199 OTS_WARNING("bad search range"); 206 OTS_FAILURE_MSG_HDR("bad search range");
200 header->search_range = expected_search_range; // Fix the value. 207 header->search_range = expected_search_range; // Fix the value.
201 } 208 }
202 209
203 // entry_selector is Log2(maximum power of 2 <= numTables) 210 // entry_selector is Log2(maximum power of 2 <= numTables)
204 if (header->entry_selector != max_pow2) { 211 if (header->entry_selector != max_pow2) {
205 return OTS_FAILURE(); 212 return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
206 } 213 }
207 214
208 // range_shift is NumTables x 16-searchRange. We know that 16*num_tables 215 // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
209 // doesn't over flow because we range checked it above. Also, we know that 216 // doesn't over flow because we range checked it above. Also, we know that
210 // it's > header->search_range by construction of search_range. 217 // it's > header->search_range by construction of search_range.
211 const uint16_t expected_range_shift = 218 const uint16_t expected_range_shift =
212 16 * header->num_tables - header->search_range; 219 16 * header->num_tables - header->search_range;
213 if (header->range_shift != expected_range_shift) { 220 if (header->range_shift != expected_range_shift) {
214 OTS_WARNING("bad range shift"); 221 OTS_FAILURE_MSG_HDR("bad range shift");
215 header->range_shift = expected_range_shift; // the same as above. 222 header->range_shift = expected_range_shift; // the same as above.
216 } 223 }
217 224
218 // Next up is the list of tables. 225 // Next up is the list of tables.
219 std::vector<OpenTypeTable> tables; 226 std::vector<OpenTypeTable> tables;
220 227
221 for (unsigned i = 0; i < header->num_tables; ++i) { 228 for (unsigned i = 0; i < header->num_tables; ++i) {
222 OpenTypeTable table; 229 OpenTypeTable table;
223 if (!file.ReadTag(&table.tag) || 230 if (!file.ReadTag(&table.tag) ||
224 !file.ReadU32(&table.chksum) || 231 !file.ReadU32(&table.chksum) ||
225 !file.ReadU32(&table.offset) || 232 !file.ReadU32(&table.offset) ||
226 !file.ReadU32(&table.length)) { 233 !file.ReadU32(&table.length)) {
227 return OTS_FAILURE(); 234 return OTS_FAILURE_MSG_HDR("error reading table directory");
228 } 235 }
229 236
230 table.uncompressed_length = table.length; 237 table.uncompressed_length = table.length;
231 tables.push_back(table); 238 tables.push_back(table);
232 } 239 }
233 240
234 return ProcessGeneric(header, header->version, output, data, length, 241 return ProcessGeneric(header, header->version, output, data, length,
235 tables, file); 242 tables, file);
236 } 243 }
237 244
238 bool ProcessWOFF(ots::OpenTypeFile *header, 245 bool ProcessWOFF(ots::OpenTypeFile *header,
239 ots::OTSStream *output, const uint8_t *data, size_t length) { 246 ots::OTSStream *output, const uint8_t *data, size_t length) {
240 ots::Buffer file(data, length); 247 ots::Buffer file(data, length);
241 248
242 // we disallow all files > 1GB in size for sanity. 249 // we disallow all files > 1GB in size for sanity.
243 if (length > 1024 * 1024 * 1024) { 250 if (length > 1024 * 1024 * 1024) {
244 return OTS_FAILURE(); 251 return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
245 } 252 }
246 253
247 uint32_t woff_tag; 254 uint32_t woff_tag;
248 if (!file.ReadTag(&woff_tag)) { 255 if (!file.ReadTag(&woff_tag)) {
249 return OTS_FAILURE(); 256 return OTS_FAILURE_MSG_HDR("error reading WOFF marker");
250 } 257 }
251 258
252 if (woff_tag != Tag("wOFF")) { 259 if (woff_tag != Tag("wOFF")) {
253 return OTS_FAILURE(); 260 return OTS_FAILURE_MSG_HDR("invalid WOFF marker");
254 } 261 }
255 262
256 if (!file.ReadTag(&header->version)) { 263 if (!file.ReadTag(&header->version)) {
257 return OTS_FAILURE(); 264 return OTS_FAILURE_MSG_HDR("error reading version tag");
258 } 265 }
259 if (!ots::IsValidVersionTag(header->version)) { 266 if (!ots::IsValidVersionTag(header->version)) {
260 return OTS_FAILURE(); 267 return OTS_FAILURE_MSG_HDR("invalid version tag");
261 } 268 }
262 269
263 header->search_range = 0; 270 header->search_range = 0;
264 header->entry_selector = 0; 271 header->entry_selector = 0;
265 header->range_shift = 0; 272 header->range_shift = 0;
266 273
267 uint32_t reported_length; 274 uint32_t reported_length;
268 if (!file.ReadU32(&reported_length) || length != reported_length) { 275 if (!file.ReadU32(&reported_length) || length != reported_length) {
269 return OTS_FAILURE(); 276 return OTS_FAILURE_MSG_HDR("incorrect file size in WOFF header");
270 } 277 }
271 278
272 if (!file.ReadU16(&header->num_tables) || !header->num_tables) { 279 if (!file.ReadU16(&header->num_tables) || !header->num_tables) {
273 return OTS_FAILURE(); 280 return OTS_FAILURE_MSG_HDR("error reading number of tables");
274 } 281 }
275 282
276 uint16_t reserved_value; 283 uint16_t reserved_value;
277 if (!file.ReadU16(&reserved_value) || reserved_value) { 284 if (!file.ReadU16(&reserved_value) || reserved_value) {
278 return OTS_FAILURE(); 285 return OTS_FAILURE_MSG_HDR("error in reserved field of WOFF header");
279 } 286 }
280 287
281 uint32_t reported_total_sfnt_size; 288 uint32_t reported_total_sfnt_size;
282 if (!file.ReadU32(&reported_total_sfnt_size)) { 289 if (!file.ReadU32(&reported_total_sfnt_size)) {
283 return OTS_FAILURE(); 290 return OTS_FAILURE_MSG_HDR("error reading total sfnt size");
284 } 291 }
285 292
286 // We don't care about these fields of the header: 293 // We don't care about these fields of the header:
287 // uint16_t major_version, minor_version 294 // uint16_t major_version, minor_version
288 if (!file.Skip(2 * 2)) { 295 if (!file.Skip(2 * 2)) {
289 return OTS_FAILURE(); 296 return OTS_FAILURE_MSG_HDR("error skipping WOFF header fields");
290 } 297 }
291 298
292 // Checks metadata block size. 299 // Checks metadata block size.
293 uint32_t meta_offset; 300 uint32_t meta_offset;
294 uint32_t meta_length; 301 uint32_t meta_length;
295 uint32_t meta_length_orig; 302 uint32_t meta_length_orig;
296 if (!file.ReadU32(&meta_offset) || 303 if (!file.ReadU32(&meta_offset) ||
297 !file.ReadU32(&meta_length) || 304 !file.ReadU32(&meta_length) ||
298 !file.ReadU32(&meta_length_orig)) { 305 !file.ReadU32(&meta_length_orig)) {
299 return OTS_FAILURE(); 306 return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
300 } 307 }
301 if (meta_offset) { 308 if (meta_offset) {
302 if (meta_offset >= length || length - meta_offset < meta_length) { 309 if (meta_offset >= length || length - meta_offset < meta_length) {
303 return OTS_FAILURE(); 310 return OTS_FAILURE_MSG_HDR("invalid metadata block location/size");
304 } 311 }
305 } 312 }
306 313
307 // Checks private data block size. 314 // Checks private data block size.
308 uint32_t priv_offset; 315 uint32_t priv_offset;
309 uint32_t priv_length; 316 uint32_t priv_length;
310 if (!file.ReadU32(&priv_offset) || 317 if (!file.ReadU32(&priv_offset) ||
311 !file.ReadU32(&priv_length)) { 318 !file.ReadU32(&priv_length)) {
312 return OTS_FAILURE(); 319 return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
313 } 320 }
314 if (priv_offset) { 321 if (priv_offset) {
315 if (priv_offset >= length || length - priv_offset < priv_length) { 322 if (priv_offset >= length || length - priv_offset < priv_length) {
316 return OTS_FAILURE(); 323 return OTS_FAILURE_MSG_HDR("invalid private block location/size");
317 } 324 }
318 } 325 }
319 326
320 // Next up is the list of tables. 327 // Next up is the list of tables.
321 std::vector<OpenTypeTable> tables; 328 std::vector<OpenTypeTable> tables;
322 329
323 uint32_t first_index = 0; 330 uint32_t first_index = 0;
324 uint32_t last_index = 0; 331 uint32_t last_index = 0;
325 // Size of sfnt header plus size of table records. 332 // Size of sfnt header plus size of table records.
326 uint64_t total_sfnt_size = 12 + 16 * header->num_tables; 333 uint64_t total_sfnt_size = 12 + 16 * header->num_tables;
327 for (unsigned i = 0; i < header->num_tables; ++i) { 334 for (unsigned i = 0; i < header->num_tables; ++i) {
328 OpenTypeTable table; 335 OpenTypeTable table;
329 if (!file.ReadTag(&table.tag) || 336 if (!file.ReadTag(&table.tag) ||
330 !file.ReadU32(&table.offset) || 337 !file.ReadU32(&table.offset) ||
331 !file.ReadU32(&table.length) || 338 !file.ReadU32(&table.length) ||
332 !file.ReadU32(&table.uncompressed_length) || 339 !file.ReadU32(&table.uncompressed_length) ||
333 !file.ReadU32(&table.chksum)) { 340 !file.ReadU32(&table.chksum)) {
334 return OTS_FAILURE(); 341 return OTS_FAILURE_MSG_HDR("error reading table directory");
335 } 342 }
336 343
337 total_sfnt_size += ots::Round4(table.uncompressed_length); 344 total_sfnt_size += ots::Round4(table.uncompressed_length);
338 if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) { 345 if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) {
339 return OTS_FAILURE(); 346 return OTS_FAILURE_MSG_HDR("sfnt size overflow");
340 } 347 }
341 tables.push_back(table); 348 tables.push_back(table);
342 if (i == 0 || tables[first_index].offset > table.offset) 349 if (i == 0 || tables[first_index].offset > table.offset)
343 first_index = i; 350 first_index = i;
344 if (i == 0 || tables[last_index].offset < table.offset) 351 if (i == 0 || tables[last_index].offset < table.offset)
345 last_index = i; 352 last_index = i;
346 } 353 }
347 354
348 if (reported_total_sfnt_size != total_sfnt_size) { 355 if (reported_total_sfnt_size != total_sfnt_size) {
349 return OTS_FAILURE(); 356 return OTS_FAILURE_MSG_HDR("uncompressed sfnt size mismatch");
350 } 357 }
351 358
352 // Table data must follow immediately after the header. 359 // Table data must follow immediately after the header.
353 if (tables[first_index].offset != ots::Round4(file.offset())) { 360 if (tables[first_index].offset != ots::Round4(file.offset())) {
354 return OTS_FAILURE(); 361 return OTS_FAILURE_MSG_HDR("junk before tables in WOFF file");
355 } 362 }
356 363
357 if (tables[last_index].offset >= length || 364 if (tables[last_index].offset >= length ||
358 length - tables[last_index].offset < tables[last_index].length) { 365 length - tables[last_index].offset < tables[last_index].length) {
359 return OTS_FAILURE(); 366 return OTS_FAILURE_MSG_HDR("invalid table location/size");
360 } 367 }
361 // Blocks must follow immediately after the previous block. 368 // Blocks must follow immediately after the previous block.
362 // (Except for padding with a maximum of three null bytes) 369 // (Except for padding with a maximum of three null bytes)
363 uint64_t block_end = ots::Round4( 370 uint64_t block_end = ots::Round4(
364 static_cast<uint64_t>(tables[last_index].offset) + 371 static_cast<uint64_t>(tables[last_index].offset) +
365 static_cast<uint64_t>(tables[last_index].length)); 372 static_cast<uint64_t>(tables[last_index].length));
366 if (block_end > std::numeric_limits<uint32_t>::max()) { 373 if (block_end > std::numeric_limits<uint32_t>::max()) {
367 return OTS_FAILURE(); 374 return OTS_FAILURE_MSG_HDR("invalid table location/size");
368 } 375 }
369 if (meta_offset) { 376 if (meta_offset) {
370 if (block_end != meta_offset) { 377 if (block_end != meta_offset) {
371 return OTS_FAILURE(); 378 return OTS_FAILURE_MSG_HDR("invalid metadata block location");
372 } 379 }
373 block_end = ots::Round4(static_cast<uint64_t>(meta_offset) + 380 block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
374 static_cast<uint64_t>(meta_length)); 381 static_cast<uint64_t>(meta_length));
375 if (block_end > std::numeric_limits<uint32_t>::max()) { 382 if (block_end > std::numeric_limits<uint32_t>::max()) {
376 return OTS_FAILURE(); 383 return OTS_FAILURE_MSG_HDR("invalid metadata block size");
377 } 384 }
378 } 385 }
379 if (priv_offset) { 386 if (priv_offset) {
380 if (block_end != priv_offset) { 387 if (block_end != priv_offset) {
381 return OTS_FAILURE(); 388 return OTS_FAILURE_MSG_HDR("invalid private block location");
382 } 389 }
383 block_end = ots::Round4(static_cast<uint64_t>(priv_offset) + 390 block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
384 static_cast<uint64_t>(priv_length)); 391 static_cast<uint64_t>(priv_length));
385 if (block_end > std::numeric_limits<uint32_t>::max()) { 392 if (block_end > std::numeric_limits<uint32_t>::max()) {
386 return OTS_FAILURE(); 393 return OTS_FAILURE_MSG_HDR("invalid private block size");
387 } 394 }
388 } 395 }
389 if (block_end != ots::Round4(length)) { 396 if (block_end != ots::Round4(length)) {
390 return OTS_FAILURE(); 397 return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
391 } 398 }
392 399
393 return ProcessGeneric(header, woff_tag, output, data, length, tables, file); 400 return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
394 } 401 }
395 402
403 #ifndef OTS_DISABLE_WOFF2
396 bool ProcessWOFF2(ots::OpenTypeFile *header, 404 bool ProcessWOFF2(ots::OpenTypeFile *header,
397 ots::OTSStream *output, const uint8_t *data, size_t length) { 405 ots::OTSStream *output, const uint8_t *data, size_t length) {
398 size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length); 406 size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
399 if (decompressed_size == 0) { 407 if (decompressed_size == 0) {
400 return OTS_FAILURE(); 408 return OTS_FAILURE();
401 } 409 }
402 // decompressed font must be <= 30MB 410 // decompressed font must be <= 30MB
403 if (decompressed_size > 30 * 1024 * 1024) { 411 if (decompressed_size > 30 * 1024 * 1024) {
404 return OTS_FAILURE(); 412 return OTS_FAILURE();
405 } 413 }
406 414
407 std::vector<uint8_t> decompressed_buffer(decompressed_size); 415 std::vector<uint8_t> decompressed_buffer(decompressed_size);
408 if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size, 416 if (!ots::ConvertWOFF2ToTTF(&decompressed_buffer[0], decompressed_size,
409 data, length)) { 417 data, length)) {
410 return OTS_FAILURE(); 418 return OTS_FAILURE();
411 } 419 }
412 return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size); 420 return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
413 } 421 }
422 #endif
423
424 ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
425 ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
426
427 action = header->context->GetTableAction(htonl(tag));
428
429 if (action == ots::TABLE_ACTION_DEFAULT) {
430 action = ots::TABLE_ACTION_DROP;
431
432 for (unsigned i = 0; ; ++i) {
433 if (table_parsers[i].parse == NULL) break;
434
435 if (Tag(table_parsers[i].tag) == tag) {
436 action = ots::TABLE_ACTION_SANITIZE;
437 break;
438 }
439 }
440 }
441
442 assert(action != ots::TABLE_ACTION_DEFAULT); // Should never return this.
443 return action;
444 }
445
446 bool GetTableData(const uint8_t *data,
447 const OpenTypeTable table,
448 Arena *arena,
449 size_t *table_length,
450 const uint8_t **table_data) {
451 if (table.uncompressed_length != table.length) {
452 // Compressed table. Need to uncompress into memory first.
453 *table_length = table.uncompressed_length;
454 *table_data = (*arena).Allocate(*table_length);
455 uLongf dest_len = *table_length;
456 int r = uncompress((Bytef*) *table_data, &dest_len,
457 data + table.offset, table.length);
458 if (r != Z_OK || dest_len != *table_length) {
459 return false;
460 }
461 } else {
462 // Uncompressed table. We can process directly from memory.
463 *table_data = data + table.offset;
464 *table_length = table.length;
465 }
466
467 return true;
468 }
414 469
415 bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature, 470 bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
416 ots::OTSStream *output, 471 ots::OTSStream *output,
417 const uint8_t *data, size_t length, 472 const uint8_t *data, size_t length,
418 const std::vector<OpenTypeTable>& tables, 473 const std::vector<OpenTypeTable>& tables,
419 ots::Buffer& file) { 474 ots::Buffer& file) {
420 const size_t data_offset = file.offset(); 475 const size_t data_offset = file.offset();
421 476
422 uint32_t uncompressed_sum = 0; 477 uint32_t uncompressed_sum = 0;
423 478
424 for (unsigned i = 0; i < header->num_tables; ++i) { 479 for (unsigned i = 0; i < header->num_tables; ++i) {
425 // the tables must be sorted by tag (when taken as big-endian numbers). 480 // the tables must be sorted by tag (when taken as big-endian numbers).
426 // This also remove the possibility of duplicate tables. 481 // This also remove the possibility of duplicate tables.
427 if (i) { 482 if (i) {
428 const uint32_t this_tag = ntohl(tables[i].tag); 483 const uint32_t this_tag = ntohl(tables[i].tag);
429 const uint32_t prev_tag = ntohl(tables[i - 1].tag); 484 const uint32_t prev_tag = ntohl(tables[i - 1].tag);
430 if (this_tag <= prev_tag) { 485 if (this_tag <= prev_tag) {
431 return OTS_FAILURE(); 486 return OTS_FAILURE_MSG_HDR("table directory not correctly ordered");
432 } 487 }
433 } 488 }
434 489
435 // all tag names must be built from printable ASCII characters 490 // all tag names must be built from printable ASCII characters
436 if (!CheckTag(tables[i].tag)) { 491 if (!CheckTag(tables[i].tag)) {
437 return OTS_FAILURE(); 492 return OTS_FAILURE_MSG_TAG("invalid table tag", &tables[i].tag);
438 } 493 }
439 494
440 // tables must be 4-byte aligned 495 // tables must be 4-byte aligned
441 if (tables[i].offset & 3) { 496 if (tables[i].offset & 3) {
442 return OTS_FAILURE(); 497 return OTS_FAILURE_MSG_TAG("misaligned table", &tables[i].tag);
443 } 498 }
444 499
445 // and must be within the file 500 // and must be within the file
446 if (tables[i].offset < data_offset || tables[i].offset >= length) { 501 if (tables[i].offset < data_offset || tables[i].offset >= length) {
447 return OTS_FAILURE(); 502 return OTS_FAILURE_MSG_TAG("invalid table offset", &tables[i].tag);
448 } 503 }
449 // disallow all tables with a zero length 504 // disallow all tables with a zero length
450 if (tables[i].length < 1) { 505 if (tables[i].length < 1) {
451 // Note: malayalam.ttf has zero length CVT table... 506 // Note: malayalam.ttf has zero length CVT table...
452 return OTS_FAILURE(); 507 return OTS_FAILURE_MSG_TAG("zero-length table", &tables[i].tag);
453 } 508 }
454 // disallow all tables with a length > 1GB 509 // disallow all tables with a length > 1GB
455 if (tables[i].length > 1024 * 1024 * 1024) { 510 if (tables[i].length > 1024 * 1024 * 1024) {
456 return OTS_FAILURE(); 511 return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", &tables[i].tag);
457 } 512 }
458 // disallow tables where the uncompressed size is < the compressed size. 513 // disallow tables where the uncompressed size is < the compressed size.
459 if (tables[i].uncompressed_length < tables[i].length) { 514 if (tables[i].uncompressed_length < tables[i].length) {
460 return OTS_FAILURE(); 515 return OTS_FAILURE_MSG_TAG("invalid compressed table", &tables[i].tag);
461 } 516 }
462 if (tables[i].uncompressed_length > tables[i].length) { 517 if (tables[i].uncompressed_length > tables[i].length) {
463 // We'll probably be decompressing this table. 518 // We'll probably be decompressing this table.
464 519
465 // disallow all tables which uncompress to > 30 MB 520 // disallow all tables which uncompress to > 30 MB
466 if (tables[i].uncompressed_length > 30 * 1024 * 1024) { 521 if (tables[i].uncompressed_length > 30 * 1024 * 1024) {
467 return OTS_FAILURE(); 522 return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", &tables[i ].tag);
468 } 523 }
469 if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) { 524 if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
470 return OTS_FAILURE(); 525 return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", &tables[i].ta g);
471 } 526 }
472 527
473 uncompressed_sum += tables[i].uncompressed_length; 528 uncompressed_sum += tables[i].uncompressed_length;
474 } 529 }
475 // since we required that the file be < 1GB in length, and that the table 530 // since we required that the file be < 1GB in length, and that the table
476 // length is < 1GB, the following addtion doesn't overflow 531 // length is < 1GB, the following addtion doesn't overflow
477 uint32_t end_byte = tables[i].offset + tables[i].length; 532 uint32_t end_byte = tables[i].offset + tables[i].length;
478 // Tables in the WOFF file must be aligned 4-byte boundary. 533 // Tables in the WOFF file must be aligned 4-byte boundary.
479 if (signature == Tag("wOFF")) { 534 if (signature == Tag("wOFF")) {
480 end_byte = ots::Round4(end_byte); 535 end_byte = ots::Round4(end_byte);
481 } 536 }
482 if (!end_byte || end_byte > length) { 537 if (!end_byte || end_byte > length) {
483 return OTS_FAILURE(); 538 return OTS_FAILURE_MSG_TAG("table overruns end of file", &tables[i].tag);
484 } 539 }
485 } 540 }
486 541
487 // All decompressed tables uncompressed must be <= 30MB. 542 // All decompressed tables uncompressed must be <= 30MB.
488 if (uncompressed_sum > 30 * 1024 * 1024) { 543 if (uncompressed_sum > 30 * 1024 * 1024) {
489 return OTS_FAILURE(); 544 return OTS_FAILURE_MSG_HDR("uncompressed sum exceeds 30MB");
490 } 545 }
491 546
492 std::map<uint32_t, OpenTypeTable> table_map; 547 std::map<uint32_t, OpenTypeTable> table_map;
493 for (unsigned i = 0; i < header->num_tables; ++i) { 548 for (unsigned i = 0; i < header->num_tables; ++i) {
494 table_map[tables[i].tag] = tables[i]; 549 table_map[tables[i].tag] = tables[i];
495 } 550 }
496 551
497 // check that the tables are not overlapping. 552 // check that the tables are not overlapping.
498 std::vector<std::pair<uint32_t, uint8_t> > overlap_checker; 553 std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
499 for (unsigned i = 0; i < header->num_tables; ++i) { 554 for (unsigned i = 0; i < header->num_tables; ++i) {
500 overlap_checker.push_back( 555 overlap_checker.push_back(
501 std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */)); 556 std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */));
502 overlap_checker.push_back( 557 overlap_checker.push_back(
503 std::make_pair(tables[i].offset + tables[i].length, 558 std::make_pair(tables[i].offset + tables[i].length,
504 static_cast<uint8_t>(0) /* end */)); 559 static_cast<uint8_t>(0) /* end */));
505 } 560 }
506 std::sort(overlap_checker.begin(), overlap_checker.end()); 561 std::sort(overlap_checker.begin(), overlap_checker.end());
507 int overlap_count = 0; 562 int overlap_count = 0;
508 for (unsigned i = 0; i < overlap_checker.size(); ++i) { 563 for (unsigned i = 0; i < overlap_checker.size(); ++i) {
509 overlap_count += (overlap_checker[i].second ? 1 : -1); 564 overlap_count += (overlap_checker[i].second ? 1 : -1);
510 if (overlap_count > 1) { 565 if (overlap_count > 1) {
511 return OTS_FAILURE(); 566 return OTS_FAILURE_MSG_HDR("overlapping tables");
512 } 567 }
513 } 568 }
514 569
515 Arena arena; 570 Arena arena;
516 571
517 for (unsigned i = 0; ; ++i) { 572 for (unsigned i = 0; ; ++i) {
518 if (table_parsers[i].parse == NULL) break; 573 if (table_parsers[i].parse == NULL) break;
519 574
520 const std::map<uint32_t, OpenTypeTable>::const_iterator it 575 uint32_t tag = Tag(table_parsers[i].tag);
521 = table_map.find(Tag(table_parsers[i].tag)); 576 const std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.find( tag);
522 577
578 ots::TableAction action = GetTableAction(header, tag);
523 if (it == table_map.end()) { 579 if (it == table_map.end()) {
524 if (table_parsers[i].required) { 580 if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) {
525 return OTS_FAILURE(); 581 return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].ta g);
526 } 582 }
527 continue; 583 continue;
528 } 584 }
529 585
530 const uint8_t* table_data; 586 const uint8_t* table_data;
531 size_t table_length; 587 size_t table_length;
532 588
533 if (it->second.uncompressed_length != it->second.length) { 589 if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
534 // compressed table. Need to uncompress into memory first. 590 return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
535 table_length = it->second.uncompressed_length;
536 table_data = arena.Allocate(table_length);
537 uLongf dest_len = table_length;
538 int r = uncompress((Bytef*) table_data, &dest_len,
539 data + it->second.offset, it->second.length);
540 if (r != Z_OK || dest_len != table_length) {
541 return OTS_FAILURE();
542 }
543 } else {
544 // uncompressed table. We can process directly from memory.
545 table_data = data + it->second.offset;
546 table_length = it->second.length;
547 } 591 }
548 592
549 if (!table_parsers[i].parse(header, table_data, table_length)) { 593 if (action == ots::TABLE_ACTION_SANITIZE &&
550 return OTS_FAILURE(); 594 !table_parsers[i].parse(header, table_data, table_length)) {
595 // TODO: parsers should generate specific messages detailing the failure;
596 // once those are all added, we won't need a generic failure message here
597 return OTS_FAILURE_MSG_TAG("failed to parse table", table_parsers[i].tag);
551 } 598 }
552 } 599 }
553 600
554 if (header->cff) { 601 if (header->cff) {
555 // font with PostScript glyph 602 // font with PostScript glyph
556 if (header->version != Tag("OTTO")) { 603 if (header->version != Tag("OTTO")) {
557 return OTS_FAILURE(); 604 return OTS_FAILURE_MSG_HDR("wrong font version for PostScript glyph data") ;
558 } 605 }
559 if (header->glyf || header->loca) { 606 if (header->glyf || header->loca) {
560 // mixing outline formats is not recommended 607 // mixing outline formats is not recommended
561 return OTS_FAILURE(); 608 return OTS_FAILURE_MSG_HDR("font contains both PS and TT glyphs");
562 } 609 }
563 } else { 610 } else {
564 if ((!header->glyf || !header->loca) && (!header->cbdt || !header->cblc)) { 611 if ((!header->glyf || !header->loca) && (!header->cbdt || !header->cblc)) {
565 // No TrueType glyph or color bitmap found. 612 // No TrueType glyph or color bitmap found.
566 return OTS_FAILURE(); 613 return OTS_FAILURE();
567 } 614 }
568 } 615 }
569 616
570 uint16_t num_output_tables = 0; 617 uint16_t num_output_tables = 0;
571 for (unsigned i = 0; ; ++i) { 618 for (unsigned i = 0; ; ++i) {
572 if (table_parsers[i].parse == NULL) { 619 if (table_parsers[i].parse == NULL) {
573 break; 620 break;
574 } 621 }
575 622
576 if (table_parsers[i].should_serialise(header)) { 623 if (table_parsers[i].should_serialise(header)) {
577 num_output_tables++; 624 num_output_tables++;
578 } 625 }
579 } 626 }
580 627
628 for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
629 it != table_map.end(); ++it) {
630 ots::TableAction action = GetTableAction(header, it->first);
631 if (action == ots::TABLE_ACTION_PASSTHRU) {
632 num_output_tables++;
633 }
634 }
635
581 uint16_t max_pow2 = 0; 636 uint16_t max_pow2 = 0;
582 while (1u << (max_pow2 + 1) <= num_output_tables) { 637 while (1u << (max_pow2 + 1) <= num_output_tables) {
583 max_pow2++; 638 max_pow2++;
584 } 639 }
585 const uint16_t output_search_range = (1u << max_pow2) << 4; 640 const uint16_t output_search_range = (1u << max_pow2) << 4;
586 641
642 // most of the errors here are highly unlikely - they'd only occur if the
643 // output stream returns a failure, e.g. lack of space to write
587 output->ResetChecksum(); 644 output->ResetChecksum();
588 if (!output->WriteTag(header->version) || 645 if (!output->WriteTag(header->version) ||
589 !output->WriteU16(num_output_tables) || 646 !output->WriteU16(num_output_tables) ||
590 !output->WriteU16(output_search_range) || 647 !output->WriteU16(output_search_range) ||
591 !output->WriteU16(max_pow2) || 648 !output->WriteU16(max_pow2) ||
592 !output->WriteU16((num_output_tables << 4) - output_search_range)) { 649 !output->WriteU16((num_output_tables << 4) - output_search_range)) {
593 return OTS_FAILURE(); 650 return OTS_FAILURE_MSG_HDR("error writing output");
594 } 651 }
595 const uint32_t offset_table_chksum = output->chksum(); 652 const uint32_t offset_table_chksum = output->chksum();
596 653
597 const size_t table_record_offset = output->Tell(); 654 const size_t table_record_offset = output->Tell();
598 if (!output->Pad(16 * num_output_tables)) { 655 if (!output->Pad(16 * num_output_tables)) {
599 return OTS_FAILURE(); 656 return OTS_FAILURE_MSG_HDR("error writing output");
600 } 657 }
601 658
602 std::vector<OutputTable> out_tables; 659 std::vector<OutputTable> out_tables;
603 660
604 size_t head_table_offset = 0; 661 size_t head_table_offset = 0;
605 for (unsigned i = 0; ; ++i) { 662 for (unsigned i = 0; ; ++i) {
606 if (table_parsers[i].parse == NULL) { 663 if (table_parsers[i].parse == NULL) {
607 break; 664 break;
608 } 665 }
609 666
610 if (!table_parsers[i].should_serialise(header)) { 667 if (!table_parsers[i].should_serialise(header)) {
611 continue; 668 continue;
612 } 669 }
613 670
614 OutputTable out; 671 OutputTable out;
615 uint32_t tag = Tag(table_parsers[i].tag); 672 uint32_t tag = Tag(table_parsers[i].tag);
616 out.tag = tag; 673 out.tag = tag;
617 out.offset = output->Tell(); 674 out.offset = output->Tell();
618 675
619 output->ResetChecksum(); 676 output->ResetChecksum();
620 if (tag == Tag("head")) { 677 if (tag == Tag("head")) {
621 head_table_offset = out.offset; 678 head_table_offset = out.offset;
622 } 679 }
623 if (!table_parsers[i].serialise(output, header)) { 680 if (!table_parsers[i].serialise(output, header)) {
624 return OTS_FAILURE(); 681 return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].t ag);
625 } 682 }
626 683
627 const size_t end_offset = output->Tell(); 684 const size_t end_offset = output->Tell();
628 if (end_offset <= out.offset) { 685 if (end_offset <= out.offset) {
629 // paranoid check. |end_offset| is supposed to be greater than the offset, 686 // paranoid check. |end_offset| is supposed to be greater than the offset,
630 // as long as the Tell() interface is implemented correctly. 687 // as long as the Tell() interface is implemented correctly.
631 return OTS_FAILURE(); 688 return OTS_FAILURE_MSG_HDR("error writing output");
632 } 689 }
633 out.length = end_offset - out.offset; 690 out.length = end_offset - out.offset;
634 691
635 // align tables to four bytes 692 // align tables to four bytes
636 if (!output->Pad((4 - (end_offset & 3)) % 4)) { 693 if (!output->Pad((4 - (end_offset & 3)) % 4)) {
637 return OTS_FAILURE(); 694 return OTS_FAILURE_MSG_HDR("error writing output");
638 } 695 }
639 out.chksum = output->chksum(); 696 out.chksum = output->chksum();
640 out_tables.push_back(out); 697 out_tables.push_back(out);
641 } 698 }
642 699
700 for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
701 it != table_map.end(); ++it) {
702 ots::TableAction action = GetTableAction(header, it->first);
703 if (action == ots::TABLE_ACTION_PASSTHRU) {
704 OutputTable out;
705 out.tag = it->second.tag;
706 out.offset = output->Tell();
707
708 output->ResetChecksum();
709 if (it->second.tag == Tag("head")) {
710 head_table_offset = out.offset;
711 }
712
713 const uint8_t* table_data;
714 size_t table_length;
715
716 if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
717 return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
718 }
719
720 if (!output->Write(table_data, table_length)) {
721 return OTS_FAILURE_MSG_HDR("Failed to serialize table");
722 }
723
724 const size_t end_offset = output->Tell();
725 if (end_offset <= out.offset) {
726 // paranoid check. |end_offset| is supposed to be greater than the offse t,
727 // as long as the Tell() interface is implemented correctly.
728 return OTS_FAILURE_MSG_HDR("error writing output");
729 }
730 out.length = end_offset - out.offset;
731
732 // align tables to four bytes
733 if (!output->Pad((4 - (end_offset & 3)) % 4)) {
734 return OTS_FAILURE_MSG_HDR("error writing output");
735 }
736 out.chksum = output->chksum();
737 out_tables.push_back(out);
738 }
739 }
740
643 const size_t end_of_file = output->Tell(); 741 const size_t end_of_file = output->Tell();
644 742
645 // Need to sort the output tables for inclusion in the file 743 // Need to sort the output tables for inclusion in the file
646 std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag); 744 std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag);
647 if (!output->Seek(table_record_offset)) { 745 if (!output->Seek(table_record_offset)) {
648 return OTS_FAILURE(); 746 return OTS_FAILURE_MSG_HDR("error writing output");
649 } 747 }
650 748
651 output->ResetChecksum(); 749 output->ResetChecksum();
652 uint32_t tables_chksum = 0; 750 uint32_t tables_chksum = 0;
653 for (unsigned i = 0; i < out_tables.size(); ++i) { 751 for (unsigned i = 0; i < out_tables.size(); ++i) {
654 if (!output->WriteTag(out_tables[i].tag) || 752 if (!output->WriteTag(out_tables[i].tag) ||
655 !output->WriteU32(out_tables[i].chksum) || 753 !output->WriteU32(out_tables[i].chksum) ||
656 !output->WriteU32(out_tables[i].offset) || 754 !output->WriteU32(out_tables[i].offset) ||
657 !output->WriteU32(out_tables[i].length)) { 755 !output->WriteU32(out_tables[i].length)) {
658 return OTS_FAILURE(); 756 return OTS_FAILURE_MSG_HDR("error writing output");
659 } 757 }
660 tables_chksum += out_tables[i].chksum; 758 tables_chksum += out_tables[i].chksum;
661 } 759 }
662 const uint32_t table_record_chksum = output->chksum(); 760 const uint32_t table_record_chksum = output->chksum();
663 761
664 // http://www.microsoft.com/typography/otspec/otff.htm 762 // http://www.microsoft.com/typography/otspec/otff.htm
665 const uint32_t file_chksum 763 const uint32_t file_chksum
666 = offset_table_chksum + tables_chksum + table_record_chksum; 764 = offset_table_chksum + tables_chksum + table_record_chksum;
667 const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum; 765 const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum;
668 766
669 // seek into the 'head' table and write in the checksum magic value 767 // seek into the 'head' table and write in the checksum magic value
670 if (!head_table_offset) { 768 if (!head_table_offset) {
671 return OTS_FAILURE(); // not reached. 769 return OTS_FAILURE_MSG_HDR("internal error!");
672 } 770 }
673 if (!output->Seek(head_table_offset + 8)) { 771 if (!output->Seek(head_table_offset + 8)) {
674 return OTS_FAILURE(); 772 return OTS_FAILURE_MSG_HDR("error writing output");
675 } 773 }
676 if (!output->WriteU32(chksum_magic)) { 774 if (!output->WriteU32(chksum_magic)) {
677 return OTS_FAILURE(); 775 return OTS_FAILURE_MSG_HDR("error writing output");
678 } 776 }
679 777
680 if (!output->Seek(end_of_file)) { 778 if (!output->Seek(end_of_file)) {
681 return OTS_FAILURE(); 779 return OTS_FAILURE_MSG_HDR("error writing output");
682 } 780 }
683 781
684 return true; 782 return true;
685 } 783 }
686 784
687 } // namespace 785 } // namespace
688 786
689 namespace ots { 787 namespace ots {
690 788
691 bool g_drop_color_bitmap_tables = true;
692
693 bool IsValidVersionTag(uint32_t tag) { 789 bool IsValidVersionTag(uint32_t tag) {
694 return tag == Tag("\x00\x01\x00\x00") || 790 return tag == Tag("\x00\x01\x00\x00") ||
695 // OpenType fonts with CFF data have 'OTTO' tag. 791 // OpenType fonts with CFF data have 'OTTO' tag.
696 tag == Tag("OTTO") || 792 tag == Tag("OTTO") ||
697 // Older Mac fonts might have 'true' or 'typ1' tag. 793 // Older Mac fonts might have 'true' or 'typ1' tag.
698 tag == Tag("true") || 794 tag == Tag("true") ||
699 tag == Tag("typ1"); 795 tag == Tag("typ1");
700 } 796 }
701 797
702 void DisableDebugOutput() { 798 void DisableDebugOutput() {
703 g_debug_output = false; 799 g_debug_output = false;
704 } 800 }
705 801
706 void EnableWOFF2() { 802 void EnableWOFF2() {
707 g_enable_woff2 = true; 803 g_enable_woff2 = true;
708 } 804 }
709 805
710 void DoNotDropColorBitmapTables() { 806 bool OTSContext::Process(OTSStream *output,
711 g_drop_color_bitmap_tables = false; 807 const uint8_t *data,
712 } 808 size_t length) {
809 OpenTypeFile header;
713 810
714 bool Process(OTSStream *output, const uint8_t *data, size_t length) { 811 header.context = this;
715 OpenTypeFile header; 812
716 if (length < 4) { 813 if (length < 4) {
717 return OTS_FAILURE(); 814 return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
718 } 815 }
719 816
720 bool result; 817 bool result;
721 if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') { 818 if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
722 result = ProcessWOFF(&header, output, data, length); 819 result = ProcessWOFF(&header, output, data, length);
820 #ifndef OTS_DISABLE_WOFF2
723 } else if (g_enable_woff2 && 821 } else if (g_enable_woff2 &&
724 data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && 822 data[0] == 'w' && data[1] == 'O' && data[2] == 'F' &&
725 data[3] == '2') { 823 data[3] == '2') {
726 result = ProcessWOFF2(&header, output, data, length); 824 result = ProcessWOFF2(&header, output, data, length);
825 #endif
727 } else { 826 } else {
728 result = ProcessTTF(&header, output, data, length); 827 result = ProcessTTF(&header, output, data, length);
729 } 828 }
730 829
731 for (unsigned i = 0; ; ++i) { 830 for (unsigned i = 0; ; ++i) {
732 if (table_parsers[i].parse == NULL) break; 831 if (table_parsers[i].parse == NULL) break;
733 table_parsers[i].free(&header); 832 table_parsers[i].free(&header);
734 } 833 }
735 return result; 834 return result;
736 } 835 }
737 836
837 // For backward compatibility
838 bool Process(OTSStream *output, const uint8_t *data, size_t length) {
839 static OTSContext context;
840 return context.Process(output, data, length);
841 }
842
738 #if !defined(_MSC_VER) && defined(OTS_DEBUG) 843 #if !defined(_MSC_VER) && defined(OTS_DEBUG)
739 bool Failure(const char *f, int l, const char *fn) { 844 bool Failure(const char *f, int l, const char *fn) {
740 if (g_debug_output) { 845 if (g_debug_output) {
741 std::fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn); 846 std::fprintf(stderr, "ERROR at %s:%d (%s)\n", f, l, fn);
742 std::fflush(stderr); 847 std::fflush(stderr);
743 } 848 }
744 return false; 849 return false;
745 } 850 }
746
747 void Warning(const char *f, int l, const char *format, ...) {
748 if (g_debug_output) {
749 std::fprintf(stderr, "WARNING at %s:%d: ", f, l);
750 std::va_list va;
751 va_start(va, format);
752 std::vfprintf(stderr, format, va);
753 va_end(va);
754 std::fprintf(stderr, "\n");
755 std::fflush(stderr);
756 }
757 }
758 #endif 851 #endif
759 852
760 } // namespace ots 853 } // namespace ots
OLDNEW
« .gitmodules ('K') | « src/ots.h ('k') | src/post.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698