| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 // This is the implementation of decompression of the proposed WOFF Ultra | 5 // This is the implementation of decompression of the proposed WOFF Ultra |
| 6 // Condensed file format. | 6 // Condensed file format. |
| 7 | 7 |
| 8 #include <cassert> | 8 #include <cassert> |
| 9 #include <cstdlib> | 9 #include <cstdlib> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include <zlib.h> | 12 #include <zlib.h> |
| 13 | 13 |
| 14 #include "third_party/brotli/src/brotli/dec/decode.h" | 14 #include "third_party/brotli/src/brotli/dec/decode.h" |
| 15 | 15 |
| 16 #include "opentype-sanitiser.h" | 16 #include "opentype-sanitiser.h" |
| 17 #include "ots-memory-stream.h" | 17 #include "ots-memory-stream.h" |
| 18 #include "ots.h" | 18 #include "ots.h" |
| 19 #include "woff2.h" | 19 #include "woff2.h" |
| 20 | 20 |
| 21 namespace { | 21 namespace { |
| 22 | 22 |
| 23 // simple glyph flags | 23 // simple glyph flags |
| 24 const int kGlyfOnCurve = 1 << 0; | 24 const uint8_t kGlyfOnCurve = 1 << 0; |
| 25 const int kGlyfXShort = 1 << 1; | 25 const uint8_t kGlyfXShort = 1 << 1; |
| 26 const int kGlyfYShort = 1 << 2; | 26 const uint8_t kGlyfYShort = 1 << 2; |
| 27 const int kGlyfRepeat = 1 << 3; | 27 const uint8_t kGlyfRepeat = 1 << 3; |
| 28 const int kGlyfThisXIsSame = 1 << 4; | 28 const uint8_t kGlyfThisXIsSame = 1 << 4; |
| 29 const int kGlyfThisYIsSame = 1 << 5; | 29 const uint8_t kGlyfThisYIsSame = 1 << 5; |
| 30 | 30 |
| 31 // composite glyph flags | 31 // composite glyph flags |
| 32 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; | 32 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; |
| 33 const int FLAG_WE_HAVE_A_SCALE = 1 << 3; | 33 const int FLAG_WE_HAVE_A_SCALE = 1 << 3; |
| 34 const int FLAG_MORE_COMPONENTS = 1 << 5; | 34 const int FLAG_MORE_COMPONENTS = 1 << 5; |
| 35 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; | 35 const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6; |
| 36 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; | 36 const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7; |
| 37 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; | 37 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; |
| 38 | 38 |
| 39 const size_t kSfntHeaderSize = 12; | 39 const size_t kSfntHeaderSize = 12; |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 TAG('t', 'r', 'a', 'k'), // 56 | 115 TAG('t', 'r', 'a', 'k'), // 56 |
| 116 TAG('Z', 'a', 'p', 'f'), // 57 | 116 TAG('Z', 'a', 'p', 'f'), // 57 |
| 117 TAG('S', 'i', 'l', 'f'), // 58 | 117 TAG('S', 'i', 'l', 'f'), // 58 |
| 118 TAG('G', 'l', 'a', 't'), // 59 | 118 TAG('G', 'l', 'a', 't'), // 59 |
| 119 TAG('G', 'l', 'o', 'c'), // 60 | 119 TAG('G', 'l', 'o', 'c'), // 60 |
| 120 TAG('F', 'e', 'a', 't'), // 61 | 120 TAG('F', 'e', 'a', 't'), // 61 |
| 121 TAG('S', 'i', 'l', 'l'), // 62 | 121 TAG('S', 'i', 'l', 'l'), // 62 |
| 122 }; | 122 }; |
| 123 | 123 |
| 124 struct Point { | 124 struct Point { |
| 125 int x; | 125 int16_t x; |
| 126 int y; | 126 int16_t y; |
| 127 bool on_curve; | 127 bool on_curve; |
| 128 }; | 128 }; |
| 129 | 129 |
| 130 struct Table { | 130 struct Table { |
| 131 uint32_t tag; | 131 uint32_t tag; |
| 132 uint32_t flags; | 132 uint32_t flags; |
| 133 uint32_t src_offset; | 133 uint32_t src_offset; |
| 134 uint32_t src_length; | 134 uint32_t src_length; |
| 135 | 135 |
| 136 uint32_t transform_length; | 136 uint32_t transform_length; |
| 137 | 137 |
| 138 uint32_t dst_offset; | 138 uint32_t dst_offset; |
| 139 uint32_t dst_length; | 139 uint32_t dst_length; |
| 140 | 140 |
| 141 Table() | 141 Table() |
| 142 : tag(0), | 142 : tag(0), |
| 143 flags(0), | 143 flags(0), |
| 144 src_offset(0), | 144 src_offset(0), |
| 145 src_length(0), | 145 src_length(0), |
| 146 transform_length(0), | 146 transform_length(0), |
| 147 dst_offset(0), | 147 dst_offset(0), |
| 148 dst_length(0) {} | 148 dst_length(0) {} |
| 149 }; | 149 }; |
| 150 | 150 |
| 151 // Based on section 6.1.1 of MicroType Express draft spec | 151 // Based on section 6.1.1 of MicroType Express draft spec |
| 152 bool Read255UShort(ots::Buffer* buf, unsigned int* value) { | 152 bool Read255UShort(ots::Buffer* buf, uint16_t* value) { |
| 153 static const int kWordCode = 253; | 153 static const uint8_t kWordCode = 253; |
| 154 static const int kOneMoreByteCode2 = 254; | 154 static const uint8_t kOneMoreByteCode2 = 254; |
| 155 static const int kOneMoreByteCode1 = 255; | 155 static const uint8_t kOneMoreByteCode1 = 255; |
| 156 static const int kLowestUCode = 253; | 156 static const uint8_t kLowestUCode = 253; |
| 157 uint8_t code = 0; | 157 uint8_t code = 0; |
| 158 if (!buf->ReadU8(&code)) { | 158 if (!buf->ReadU8(&code)) { |
| 159 return OTS_FAILURE(); | 159 return OTS_FAILURE(); |
| 160 } | 160 } |
| 161 if (code == kWordCode) { | 161 if (code == kWordCode) { |
| 162 uint16_t result = 0; | 162 uint16_t result = 0; |
| 163 if (!buf->ReadU16(&result)) { | 163 if (!buf->ReadU16(&result)) { |
| 164 return OTS_FAILURE(); | 164 return OTS_FAILURE(); |
| 165 } | 165 } |
| 166 *value = result; | 166 *value = result; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 204 } | 204 } |
| 205 // Make sure not to exceed the size bound | 205 // Make sure not to exceed the size bound |
| 206 return OTS_FAILURE(); | 206 return OTS_FAILURE(); |
| 207 } | 207 } |
| 208 | 208 |
| 209 // Caller must ensure that buffer overrun won't happen. | 209 // Caller must ensure that buffer overrun won't happen. |
| 210 // TODO(ksakamaoto): Consider creating 'writer' version of the Buffer class | 210 // TODO(ksakamaoto): Consider creating 'writer' version of the Buffer class |
| 211 // and use it across the code. | 211 // and use it across the code. |
| 212 size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) { | 212 size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) { |
| 213 dst[offset] = x >> 24; | 213 dst[offset] = x >> 24; |
| 214 dst[offset + 1] = x >> 16; | 214 dst[offset + 1] = (x >> 16) & 0xff; |
| 215 dst[offset + 2] = x >> 8; | 215 dst[offset + 2] = (x >> 8) & 0xff; |
| 216 dst[offset + 3] = x; | 216 dst[offset + 3] = x & 0xff; |
| 217 return offset + 4; | 217 return offset + 4; |
| 218 } | 218 } |
| 219 | 219 |
| 220 size_t Store16(uint8_t* dst, size_t offset, int x) { | 220 size_t StoreU16(uint8_t* dst, size_t offset, uint16_t x) { |
| 221 dst[offset] = x >> 8; | 221 dst[offset] = x >> 8; |
| 222 dst[offset + 1] = x; | 222 dst[offset + 1] = x & 0xff; |
| 223 return offset + 2; | 223 return offset + 2; |
| 224 } | 224 } |
| 225 | 225 |
| 226 int WithSign(int flag, int baseval) { | 226 int WithSign(int flag, int baseval) { |
| 227 assert(0 <= baseval && baseval < 65536); | 227 assert(0 <= baseval && baseval < 65536); |
| 228 return (flag & 1) ? baseval : -baseval; | 228 return (flag & 1) ? baseval : -baseval; |
| 229 } | 229 } |
| 230 | 230 |
| 231 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size, | 231 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size, |
| 232 unsigned int n_points, std::vector<Point>* result, | 232 unsigned int n_points, std::vector<Point>* result, |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]); | 283 dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]); |
| 284 dy = WithSign(flag >> 1, | 284 dy = WithSign(flag >> 1, |
| 285 (in[triplet_index + 2] << 8) + in[triplet_index + 3]); | 285 (in[triplet_index + 2] << 8) + in[triplet_index + 3]); |
| 286 } | 286 } |
| 287 triplet_index += n_data_bytes; | 287 triplet_index += n_data_bytes; |
| 288 // Possible overflow but coordinate values are not security sensitive | 288 // Possible overflow but coordinate values are not security sensitive |
| 289 x += dx; | 289 x += dx; |
| 290 y += dy; | 290 y += dy; |
| 291 result->push_back(Point()); | 291 result->push_back(Point()); |
| 292 Point& back = result->back(); | 292 Point& back = result->back(); |
| 293 back.x = x; | 293 back.x = static_cast<int16_t>(x); |
| 294 back.y = y; | 294 back.y = static_cast<int16_t>(y); |
| 295 back.on_curve = on_curve; | 295 back.on_curve = on_curve; |
| 296 } | 296 } |
| 297 *in_bytes_consumed = triplet_index; | 297 *in_bytes_consumed = triplet_index; |
| 298 return true; | 298 return true; |
| 299 } | 299 } |
| 300 | 300 |
| 301 // This function stores just the point data. On entry, dst points to the | 301 // This function stores just the point data. On entry, dst points to the |
| 302 // beginning of a simple glyph. Returns true on success. | 302 // beginning of a simple glyph. Returns true on success. |
| 303 bool StorePoints(const std::vector<Point>& points, | 303 bool StorePoints(const std::vector<Point>& points, |
| 304 unsigned int n_contours, unsigned int instruction_length, | 304 unsigned int n_contours, unsigned int instruction_length, |
| 305 uint8_t* dst, size_t dst_size, size_t* glyph_size) { | 305 uint8_t* dst, size_t dst_size, size_t* glyph_size) { |
| 306 // I believe that n_contours < 65536, in which case this is safe. However, a | 306 // I believe that n_contours < 65536, in which case this is safe. However, a |
| 307 // comment and/or an assert would be good. | 307 // comment and/or an assert would be good. |
| 308 unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 + | 308 unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 + |
| 309 instruction_length; | 309 instruction_length; |
| 310 int last_flag = -1; | 310 uint8_t last_flag = 0xff; |
| 311 int repeat_count = 0; | 311 uint8_t repeat_count = 0; |
| 312 int last_x = 0; | 312 int last_x = 0; |
| 313 int last_y = 0; | 313 int last_y = 0; |
| 314 unsigned int x_bytes = 0; | 314 unsigned int x_bytes = 0; |
| 315 unsigned int y_bytes = 0; | 315 unsigned int y_bytes = 0; |
| 316 | 316 |
| 317 for (size_t i = 0; i < points.size(); ++i) { | 317 for (size_t i = 0; i < points.size(); ++i) { |
| 318 const Point& point = points.at(i); | 318 const Point& point = points.at(i); |
| 319 int flag = point.on_curve ? kGlyfOnCurve : 0; | 319 uint8_t flag = point.on_curve ? kGlyfOnCurve : 0; |
| 320 int dx = point.x - last_x; | 320 int dx = point.x - last_x; |
| 321 int dy = point.y - last_y; | 321 int dy = point.y - last_y; |
| 322 if (dx == 0) { | 322 if (dx == 0) { |
| 323 flag |= kGlyfThisXIsSame; | 323 flag |= kGlyfThisXIsSame; |
| 324 } else if (dx > -256 && dx < 256) { | 324 } else if (dx > -256 && dx < 256) { |
| 325 flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0); | 325 flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0); |
| 326 x_bytes += 1; | 326 x_bytes += 1; |
| 327 } else { | 327 } else { |
| 328 x_bytes += 2; | 328 x_bytes += 2; |
| 329 } | 329 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 | 372 |
| 373 int x_offset = flag_offset; | 373 int x_offset = flag_offset; |
| 374 int y_offset = flag_offset + x_bytes; | 374 int y_offset = flag_offset + x_bytes; |
| 375 last_x = 0; | 375 last_x = 0; |
| 376 last_y = 0; | 376 last_y = 0; |
| 377 for (size_t i = 0; i < points.size(); ++i) { | 377 for (size_t i = 0; i < points.size(); ++i) { |
| 378 int dx = points.at(i).x - last_x; | 378 int dx = points.at(i).x - last_x; |
| 379 if (dx == 0) { | 379 if (dx == 0) { |
| 380 // pass | 380 // pass |
| 381 } else if (dx > -256 && dx < 256) { | 381 } else if (dx > -256 && dx < 256) { |
| 382 dst[x_offset++] = std::abs(dx); | 382 dst[x_offset++] = static_cast<uint8_t>(std::abs(dx)); |
| 383 } else { | 383 } else { |
| 384 // will always fit for valid input, but overflow is harmless | 384 // will always fit for valid input, but overflow is harmless |
| 385 x_offset = Store16(dst, x_offset, dx); | 385 x_offset = StoreU16(dst, x_offset, static_cast<uint16_t>(dx)); |
| 386 } | 386 } |
| 387 last_x += dx; | 387 last_x += dx; |
| 388 int dy = points.at(i).y - last_y; | 388 int dy = points.at(i).y - last_y; |
| 389 if (dy == 0) { | 389 if (dy == 0) { |
| 390 // pass | 390 // pass |
| 391 } else if (dy > -256 && dy < 256) { | 391 } else if (dy > -256 && dy < 256) { |
| 392 dst[y_offset++] = std::abs(dy); | 392 dst[y_offset++] = static_cast<uint8_t>(std::abs(dy)); |
| 393 } else { | 393 } else { |
| 394 y_offset = Store16(dst, y_offset, dy); | 394 y_offset = StoreU16(dst, y_offset, static_cast<uint16_t>(dy)); |
| 395 } | 395 } |
| 396 last_y += dy; | 396 last_y += dy; |
| 397 } | 397 } |
| 398 *glyph_size = y_offset; | 398 *glyph_size = y_offset; |
| 399 return true; | 399 return true; |
| 400 } | 400 } |
| 401 | 401 |
| 402 // Compute the bounding box of the coordinates, and store into a glyf buffer. | 402 // Compute the bounding box of the coordinates, and store into a glyf buffer. |
| 403 // A precondition is that there are at least 10 bytes available. | 403 // A precondition is that there are at least 10 bytes available. |
| 404 void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) { | 404 void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) { |
| 405 int x_min = 0; | 405 int16_t x_min = 0; |
| 406 int y_min = 0; | 406 int16_t y_min = 0; |
| 407 int x_max = 0; | 407 int16_t x_max = 0; |
| 408 int y_max = 0; | 408 int16_t y_max = 0; |
| 409 | 409 |
| 410 for (size_t i = 0; i < points.size(); ++i) { | 410 for (size_t i = 0; i < points.size(); ++i) { |
| 411 int x = points.at(i).x; | 411 int16_t x = points.at(i).x; |
| 412 int y = points.at(i).y; | 412 int16_t y = points.at(i).y; |
| 413 if (i == 0 || x < x_min) x_min = x; | 413 if (i == 0 || x < x_min) x_min = x; |
| 414 if (i == 0 || x > x_max) x_max = x; | 414 if (i == 0 || x > x_max) x_max = x; |
| 415 if (i == 0 || y < y_min) y_min = y; | 415 if (i == 0 || y < y_min) y_min = y; |
| 416 if (i == 0 || y > y_max) y_max = y; | 416 if (i == 0 || y > y_max) y_max = y; |
| 417 } | 417 } |
| 418 size_t offset = 2; | 418 size_t offset = 2; |
| 419 offset = Store16(dst, offset, x_min); | 419 offset = StoreU16(dst, offset, x_min); |
| 420 offset = Store16(dst, offset, y_min); | 420 offset = StoreU16(dst, offset, y_min); |
| 421 offset = Store16(dst, offset, x_max); | 421 offset = StoreU16(dst, offset, x_max); |
| 422 offset = Store16(dst, offset, y_max); | 422 offset = StoreU16(dst, offset, y_max); |
| 423 } | 423 } |
| 424 | 424 |
| 425 // Process entire bbox stream. This is done as a separate pass to allow for | 425 // Process entire bbox stream. This is done as a separate pass to allow for |
| 426 // composite bbox computations (an optional more aggressive transform). | 426 // composite bbox computations (an optional more aggressive transform). |
| 427 bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs, | 427 bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs, |
| 428 const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf, | 428 const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf, |
| 429 size_t glyf_buf_length) { | 429 size_t glyf_buf_length) { |
| 430 const uint8_t* buf = bbox_stream->buffer(); | 430 const uint8_t* buf = bbox_stream->buffer(); |
| 431 if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) { | 431 if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) { |
| 432 return OTS_FAILURE(); | 432 return OTS_FAILURE(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 arg_size += 8; | 479 arg_size += 8; |
| 480 } | 480 } |
| 481 if (!composite_stream->Skip(arg_size)) { | 481 if (!composite_stream->Skip(arg_size)) { |
| 482 return OTS_FAILURE(); | 482 return OTS_FAILURE(); |
| 483 } | 483 } |
| 484 } | 484 } |
| 485 size_t composite_glyph_size = composite_stream->offset() - start_offset; | 485 size_t composite_glyph_size = composite_stream->offset() - start_offset; |
| 486 if (composite_glyph_size + kCompositeGlyphBegin > dst_size) { | 486 if (composite_glyph_size + kCompositeGlyphBegin > dst_size) { |
| 487 return OTS_FAILURE(); | 487 return OTS_FAILURE(); |
| 488 } | 488 } |
| 489 Store16(dst, 0, 0xffff); // nContours = -1 for composite glyph | 489 StoreU16(dst, 0, 0xffff); // nContours = -1 for composite glyph |
| 490 std::memcpy(dst + kCompositeGlyphBegin, | 490 std::memcpy(dst + kCompositeGlyphBegin, |
| 491 composite_stream->buffer() + start_offset, | 491 composite_stream->buffer() + start_offset, |
| 492 composite_glyph_size); | 492 composite_glyph_size); |
| 493 *glyph_size = kCompositeGlyphBegin + composite_glyph_size; | 493 *glyph_size = kCompositeGlyphBegin + composite_glyph_size; |
| 494 *have_instructions = we_have_instructions; | 494 *have_instructions = we_have_instructions; |
| 495 return true; | 495 return true; |
| 496 } | 496 } |
| 497 | 497 |
| 498 // Build TrueType loca table | 498 // Build TrueType loca table |
| 499 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format, | 499 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format, |
| 500 uint8_t* dst, size_t dst_size) { | 500 uint8_t* dst, size_t dst_size) { |
| 501 const uint64_t loca_size = loca_values.size(); | 501 const uint64_t loca_size = loca_values.size(); |
| 502 const uint64_t offset_size = index_format ? 4 : 2; | 502 const uint64_t offset_size = index_format ? 4 : 2; |
| 503 if ((loca_size << 2) >> 2 != loca_size) { | 503 if ((loca_size << 2) >> 2 != loca_size) { |
| 504 return OTS_FAILURE(); | 504 return OTS_FAILURE(); |
| 505 } | 505 } |
| 506 // No integer overflow here (loca_size <= 2^16). | 506 // No integer overflow here (loca_size <= 2^16). |
| 507 if (offset_size * loca_size > dst_size) { | 507 if (offset_size * loca_size > dst_size) { |
| 508 return OTS_FAILURE(); | 508 return OTS_FAILURE(); |
| 509 } | 509 } |
| 510 size_t offset = 0; | 510 size_t offset = 0; |
| 511 for (size_t i = 0; i < loca_values.size(); ++i) { | 511 for (size_t i = 0; i < loca_values.size(); ++i) { |
| 512 uint32_t value = loca_values.at(i); | 512 uint32_t value = loca_values.at(i); |
| 513 if (index_format) { | 513 if (index_format) { |
| 514 offset = StoreU32(dst, offset, value); | 514 offset = StoreU32(dst, offset, value); |
| 515 } else { | 515 } else { |
| 516 offset = Store16(dst, offset, value >> 1); | 516 offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1)); |
| 517 } | 517 } |
| 518 } | 518 } |
| 519 return true; | 519 return true; |
| 520 } | 520 } |
| 521 | 521 |
| 522 // Reconstruct entire glyf table based on transformed original | 522 // Reconstruct entire glyf table based on transformed original |
| 523 bool ReconstructGlyf(const uint8_t* data, size_t data_size, | 523 bool ReconstructGlyf(const uint8_t* data, size_t data_size, |
| 524 uint8_t* dst, size_t dst_size, | 524 uint8_t* dst, size_t dst_size, |
| 525 uint8_t* loca_buf, size_t loca_size) { | 525 uint8_t* loca_buf, size_t loca_size) { |
| 526 static const int kNumSubStreams = 7; | 526 static const int kNumSubStreams = 7; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 557 ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second); | 557 ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second); |
| 558 ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second); | 558 ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second); |
| 559 ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second); | 559 ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second); |
| 560 ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); | 560 ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); |
| 561 ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); | 561 ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); |
| 562 ots::Buffer instruction_stream(substreams.at(6).first, | 562 ots::Buffer instruction_stream(substreams.at(6).first, |
| 563 substreams.at(6).second); | 563 substreams.at(6).second); |
| 564 | 564 |
| 565 std::vector<uint32_t> loca_values; | 565 std::vector<uint32_t> loca_values; |
| 566 loca_values.reserve(num_glyphs + 1); | 566 loca_values.reserve(num_glyphs + 1); |
| 567 std::vector<unsigned int> n_points_vec; | 567 std::vector<uint16_t> n_points_vec; |
| 568 std::vector<Point> points; | 568 std::vector<Point> points; |
| 569 uint32_t loca_offset = 0; | 569 uint32_t loca_offset = 0; |
| 570 for (unsigned int i = 0; i < num_glyphs; ++i) { | 570 for (unsigned int i = 0; i < num_glyphs; ++i) { |
| 571 size_t glyph_size = 0; | 571 size_t glyph_size = 0; |
| 572 uint16_t n_contours = 0; | 572 uint16_t n_contours = 0; |
| 573 if (!n_contour_stream.ReadU16(&n_contours)) { | 573 if (!n_contour_stream.ReadU16(&n_contours)) { |
| 574 return OTS_FAILURE(); | 574 return OTS_FAILURE(); |
| 575 } | 575 } |
| 576 uint8_t* glyf_dst = dst + loca_offset; | 576 uint8_t* glyf_dst = dst + loca_offset; |
| 577 size_t glyf_dst_size = dst_size - loca_offset; | 577 size_t glyf_dst_size = dst_size - loca_offset; |
| 578 if (n_contours == 0xffff) { | 578 if (n_contours == 0xffff) { |
| 579 // composite glyph | 579 // composite glyph |
| 580 bool have_instructions = false; | 580 bool have_instructions = false; |
| 581 unsigned int instruction_size = 0; | 581 uint16_t instruction_size = 0; |
| 582 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, | 582 if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, |
| 583 &glyph_size, &have_instructions)) { | 583 &glyph_size, &have_instructions)) { |
| 584 return OTS_FAILURE(); | 584 return OTS_FAILURE(); |
| 585 } | 585 } |
| 586 if (have_instructions) { | 586 if (have_instructions) { |
| 587 if (!Read255UShort(&glyph_stream, &instruction_size)) { | 587 if (!Read255UShort(&glyph_stream, &instruction_size)) { |
| 588 return OTS_FAILURE(); | 588 return OTS_FAILURE(); |
| 589 } | 589 } |
| 590 // No integer overflow here (instruction_size < 2^16). | 590 // No integer overflow here (instruction_size < 2^16). |
| 591 if (instruction_size + 2 > glyf_dst_size - glyph_size) { | 591 if (instruction_size + 2U > glyf_dst_size - glyph_size) { |
| 592 return OTS_FAILURE(); | 592 return OTS_FAILURE(); |
| 593 } | 593 } |
| 594 Store16(glyf_dst, glyph_size, instruction_size); | 594 StoreU16(glyf_dst, glyph_size, instruction_size); |
| 595 if (!instruction_stream.Read(glyf_dst + glyph_size + 2, | 595 if (!instruction_stream.Read(glyf_dst + glyph_size + 2, |
| 596 instruction_size)) { | 596 instruction_size)) { |
| 597 return OTS_FAILURE(); | 597 return OTS_FAILURE(); |
| 598 } | 598 } |
| 599 glyph_size += instruction_size + 2; | 599 glyph_size += instruction_size + 2; |
| 600 } | 600 } |
| 601 } else if (n_contours > 0) { | 601 } else if (n_contours > 0) { |
| 602 // simple glyph | 602 // simple glyph |
| 603 n_points_vec.clear(); | 603 n_points_vec.clear(); |
| 604 points.clear(); | 604 points.clear(); |
| 605 unsigned int total_n_points = 0; | 605 uint32_t total_n_points = 0; |
| 606 unsigned int n_points_contour; | 606 uint16_t n_points_contour; |
| 607 for (unsigned int j = 0; j < n_contours; ++j) { | 607 for (uint32_t j = 0; j < n_contours; ++j) { |
| 608 if (!Read255UShort(&n_points_stream, &n_points_contour)) { | 608 if (!Read255UShort(&n_points_stream, &n_points_contour)) { |
| 609 return OTS_FAILURE(); | 609 return OTS_FAILURE(); |
| 610 } | 610 } |
| 611 n_points_vec.push_back(n_points_contour); | 611 n_points_vec.push_back(n_points_contour); |
| 612 if (total_n_points + n_points_contour < total_n_points) { | 612 if (total_n_points + n_points_contour < total_n_points) { |
| 613 return OTS_FAILURE(); | 613 return OTS_FAILURE(); |
| 614 } | 614 } |
| 615 total_n_points += n_points_contour; | 615 total_n_points += n_points_contour; |
| 616 } | 616 } |
| 617 unsigned int flag_size = total_n_points; | 617 uint32_t flag_size = total_n_points; |
| 618 if (flag_size > flag_stream.length() - flag_stream.offset()) { | 618 if (flag_size > flag_stream.length() - flag_stream.offset()) { |
| 619 return OTS_FAILURE(); | 619 return OTS_FAILURE(); |
| 620 } | 620 } |
| 621 const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset(); | 621 const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset(); |
| 622 const uint8_t* triplet_buf = glyph_stream.buffer() + | 622 const uint8_t* triplet_buf = glyph_stream.buffer() + |
| 623 glyph_stream.offset(); | 623 glyph_stream.offset(); |
| 624 size_t triplet_size = glyph_stream.length() - glyph_stream.offset(); | 624 size_t triplet_size = glyph_stream.length() - glyph_stream.offset(); |
| 625 size_t triplet_bytes_consumed = 0; | 625 size_t triplet_bytes_consumed = 0; |
| 626 if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points, | 626 if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points, |
| 627 &points, &triplet_bytes_consumed)) { | 627 &points, &triplet_bytes_consumed)) { |
| 628 return OTS_FAILURE(); | 628 return OTS_FAILURE(); |
| 629 } | 629 } |
| 630 const uint32_t header_and_endpts_contours_size = | 630 const uint32_t header_and_endpts_contours_size = |
| 631 kEndPtsOfContoursOffset + 2 * n_contours; | 631 kEndPtsOfContoursOffset + 2 * n_contours; |
| 632 if (glyf_dst_size < header_and_endpts_contours_size) { | 632 if (glyf_dst_size < header_and_endpts_contours_size) { |
| 633 return OTS_FAILURE(); | 633 return OTS_FAILURE(); |
| 634 } | 634 } |
| 635 Store16(glyf_dst, 0, n_contours); | 635 StoreU16(glyf_dst, 0, n_contours); |
| 636 ComputeBbox(points, glyf_dst); | 636 ComputeBbox(points, glyf_dst); |
| 637 size_t offset = kEndPtsOfContoursOffset; | 637 size_t offset = kEndPtsOfContoursOffset; |
| 638 int end_point = -1; | 638 int end_point = -1; |
| 639 for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) { | 639 for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) { |
| 640 end_point += n_points_vec.at(contour_ix); | 640 end_point += n_points_vec.at(contour_ix); |
| 641 if (end_point >= 65536) { | 641 if (end_point >= 65536) { |
| 642 return OTS_FAILURE(); | 642 return OTS_FAILURE(); |
| 643 } | 643 } |
| 644 offset = Store16(glyf_dst, offset, end_point); | 644 offset = StoreU16(glyf_dst, offset, static_cast<uint16_t>(end_point)); |
| 645 } | 645 } |
| 646 if (!flag_stream.Skip(flag_size)) { | 646 if (!flag_stream.Skip(flag_size)) { |
| 647 return OTS_FAILURE(); | 647 return OTS_FAILURE(); |
| 648 } | 648 } |
| 649 if (!glyph_stream.Skip(triplet_bytes_consumed)) { | 649 if (!glyph_stream.Skip(triplet_bytes_consumed)) { |
| 650 return OTS_FAILURE(); | 650 return OTS_FAILURE(); |
| 651 } | 651 } |
| 652 unsigned int instruction_size; | 652 uint16_t instruction_size; |
| 653 if (!Read255UShort(&glyph_stream, &instruction_size)) { | 653 if (!Read255UShort(&glyph_stream, &instruction_size)) { |
| 654 return OTS_FAILURE(); | 654 return OTS_FAILURE(); |
| 655 } | 655 } |
| 656 // No integer overflow here (instruction_size < 2^16). | 656 // No integer overflow here (instruction_size < 2^16). |
| 657 if (glyf_dst_size - header_and_endpts_contours_size < | 657 if (glyf_dst_size - header_and_endpts_contours_size < |
| 658 instruction_size + 2) { | 658 instruction_size + 2U) { |
| 659 return OTS_FAILURE(); | 659 return OTS_FAILURE(); |
| 660 } | 660 } |
| 661 uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size; | 661 uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size; |
| 662 Store16(instruction_dst, 0, instruction_size); | 662 StoreU16(instruction_dst, 0, instruction_size); |
| 663 if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) { | 663 if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) { |
| 664 return OTS_FAILURE(); | 664 return OTS_FAILURE(); |
| 665 } | 665 } |
| 666 if (!StorePoints(points, n_contours, instruction_size, | 666 if (!StorePoints(points, n_contours, instruction_size, |
| 667 glyf_dst, glyf_dst_size, &glyph_size)) { | 667 glyf_dst, glyf_dst_size, &glyph_size)) { |
| 668 return OTS_FAILURE(); | 668 return OTS_FAILURE(); |
| 669 } | 669 } |
| 670 } else { | 670 } else { |
| 671 glyph_size = 0; | 671 glyph_size = 0; |
| 672 } | 672 } |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 908 std::vector<Table> tables(num_tables); | 908 std::vector<Table> tables(num_tables); |
| 909 if (!ReadShortDirectory(&file, &tables, num_tables)) { | 909 if (!ReadShortDirectory(&file, &tables, num_tables)) { |
| 910 return OTS_FAILURE(); | 910 return OTS_FAILURE(); |
| 911 } | 911 } |
| 912 uint64_t src_offset = file.offset(); | 912 uint64_t src_offset = file.offset(); |
| 913 uint64_t dst_offset = kSfntHeaderSize + | 913 uint64_t dst_offset = kSfntHeaderSize + |
| 914 kSfntEntrySize * static_cast<uint64_t>(num_tables); | 914 kSfntEntrySize * static_cast<uint64_t>(num_tables); |
| 915 uint64_t uncompressed_sum = 0; | 915 uint64_t uncompressed_sum = 0; |
| 916 for (uint16_t i = 0; i < num_tables; ++i) { | 916 for (uint16_t i = 0; i < num_tables; ++i) { |
| 917 Table* table = &tables.at(i); | 917 Table* table = &tables.at(i); |
| 918 table->src_offset = src_offset; | 918 table->src_offset = static_cast<uint32_t>(src_offset); |
| 919 table->src_length = (i == 0 ? compressed_length : 0); | 919 table->src_length = (i == 0 ? compressed_length : 0); |
| 920 src_offset += table->src_length; | 920 src_offset += table->src_length; |
| 921 if (src_offset > std::numeric_limits<uint32_t>::max()) { | 921 if (src_offset > std::numeric_limits<uint32_t>::max()) { |
| 922 return OTS_FAILURE(); | 922 return OTS_FAILURE(); |
| 923 } | 923 } |
| 924 src_offset = ots::Round4(src_offset); | 924 src_offset = ots::Round4(src_offset); |
| 925 table->dst_offset = dst_offset; | 925 table->dst_offset = static_cast<uint32_t>(dst_offset); |
| 926 dst_offset += table->dst_length; | 926 dst_offset += table->dst_length; |
| 927 if (dst_offset > std::numeric_limits<uint32_t>::max()) { | 927 if (dst_offset > std::numeric_limits<uint32_t>::max()) { |
| 928 return OTS_FAILURE(); | 928 return OTS_FAILURE(); |
| 929 } | 929 } |
| 930 dst_offset = ots::Round4(dst_offset); | 930 dst_offset = ots::Round4(dst_offset); |
| 931 if ((table->flags & kCompressionTypeMask) != kCompressionTypeNone) { | 931 if ((table->flags & kCompressionTypeMask) != kCompressionTypeNone) { |
| 932 uncompressed_sum += table->src_length; | 932 uncompressed_sum += table->src_length; |
| 933 if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) { | 933 if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) { |
| 934 return OTS_FAILURE(); | 934 return OTS_FAILURE(); |
| 935 } | 935 } |
| 936 } | 936 } |
| 937 } | 937 } |
| 938 // Enforce same 30M limit on uncompressed tables as OTS | 938 // Enforce same 30M limit on uncompressed tables as OTS |
| 939 if (uncompressed_sum > 30 * 1024 * 1024) { | 939 if (uncompressed_sum > 30 * 1024 * 1024) { |
| 940 return OTS_FAILURE(); | 940 return OTS_FAILURE(); |
| 941 } | 941 } |
| 942 if (src_offset > length || dst_offset > result_length) { | 942 if (src_offset > length || dst_offset > result_length) { |
| 943 return OTS_FAILURE(); | 943 return OTS_FAILURE(); |
| 944 } | 944 } |
| 945 | 945 |
| 946 const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables; | 946 const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables; |
| 947 if (sfnt_header_and_table_directory_size > result_length) { | 947 if (sfnt_header_and_table_directory_size > result_length) { |
| 948 return OTS_FAILURE(); | 948 return OTS_FAILURE(); |
| 949 } | 949 } |
| 950 | 950 |
| 951 // Start building the font | 951 // Start building the font |
| 952 size_t offset = 0; | 952 size_t offset = 0; |
| 953 offset = StoreU32(result, offset, flavor); | 953 offset = StoreU32(result, offset, flavor); |
| 954 offset = Store16(result, offset, num_tables); | 954 offset = StoreU16(result, offset, num_tables); |
| 955 unsigned max_pow2 = 0; | 955 uint8_t max_pow2 = 0; |
| 956 while (1u << (max_pow2 + 1) <= num_tables) { | 956 while (1u << (max_pow2 + 1) <= num_tables) { |
| 957 max_pow2++; | 957 max_pow2++; |
| 958 } | 958 } |
| 959 const uint16_t output_search_range = (1u << max_pow2) << 4; | 959 const uint16_t output_search_range = (1u << max_pow2) << 4; |
| 960 offset = Store16(result, offset, output_search_range); | 960 offset = StoreU16(result, offset, output_search_range); |
| 961 offset = Store16(result, offset, max_pow2); | 961 offset = StoreU16(result, offset, max_pow2); |
| 962 offset = Store16(result, offset, (num_tables << 4) - output_search_range); | 962 offset = StoreU16(result, offset, (num_tables << 4) - output_search_range); |
| 963 for (uint16_t i = 0; i < num_tables; ++i) { | 963 for (uint16_t i = 0; i < num_tables; ++i) { |
| 964 const Table* table = &tables.at(i); | 964 const Table* table = &tables.at(i); |
| 965 offset = StoreU32(result, offset, table->tag); | 965 offset = StoreU32(result, offset, table->tag); |
| 966 offset = StoreU32(result, offset, 0); // checksum, to fill in later | 966 offset = StoreU32(result, offset, 0); // checksum, to fill in later |
| 967 offset = StoreU32(result, offset, table->dst_offset); | 967 offset = StoreU32(result, offset, table->dst_offset); |
| 968 offset = StoreU32(result, offset, table->dst_length); | 968 offset = StoreU32(result, offset, table->dst_length); |
| 969 } | 969 } |
| 970 std::vector<uint8_t> uncompressed_buf; | 970 std::vector<uint8_t> uncompressed_buf; |
| 971 bool continue_valid = false; | 971 bool continue_valid = false; |
| 972 const uint8_t* transform_buf = NULL; | 972 const uint8_t* transform_buf = NULL; |
| (...skipping 21 matching lines...) Expand all Loading... |
| 994 } | 994 } |
| 995 total_size += tables.at(j).transform_length; | 995 total_size += tables.at(j).transform_length; |
| 996 if (total_size > std::numeric_limits<uint32_t>::max()) { | 996 if (total_size > std::numeric_limits<uint32_t>::max()) { |
| 997 return OTS_FAILURE(); | 997 return OTS_FAILURE(); |
| 998 } | 998 } |
| 999 } | 999 } |
| 1000 // Enforce same 30M limit on uncompressed tables as OTS | 1000 // Enforce same 30M limit on uncompressed tables as OTS |
| 1001 if (total_size > 30 * 1024 * 1024) { | 1001 if (total_size > 30 * 1024 * 1024) { |
| 1002 return OTS_FAILURE(); | 1002 return OTS_FAILURE(); |
| 1003 } | 1003 } |
| 1004 uncompressed_buf.resize(total_size); | 1004 const size_t total_size_size_t = static_cast<size_t>(total_size); |
| 1005 if (!Woff2Uncompress(&uncompressed_buf[0], total_size, | 1005 uncompressed_buf.resize(total_size_size_t); |
| 1006 if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t, |
| 1006 src_buf, compressed_length, compression_type)) { | 1007 src_buf, compressed_length, compression_type)) { |
| 1007 return OTS_FAILURE(); | 1008 return OTS_FAILURE(); |
| 1008 } | 1009 } |
| 1009 transform_buf = &uncompressed_buf[0]; | 1010 transform_buf = &uncompressed_buf[0]; |
| 1010 continue_valid = true; | 1011 continue_valid = true; |
| 1011 } else { | 1012 } else { |
| 1012 return OTS_FAILURE(); | 1013 return OTS_FAILURE(); |
| 1013 } | 1014 } |
| 1014 | 1015 |
| 1015 if ((flags & kWoff2FlagsTransform) == 0) { | 1016 if ((flags & kWoff2FlagsTransform) == 0) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1033 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { | 1034 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { |
| 1034 return OTS_FAILURE(); | 1035 return OTS_FAILURE(); |
| 1035 } | 1036 } |
| 1036 } | 1037 } |
| 1037 } | 1038 } |
| 1038 | 1039 |
| 1039 return FixChecksums(tables, result); | 1040 return FixChecksums(tables, result); |
| 1040 } | 1041 } |
| 1041 | 1042 |
| 1042 } // namespace ots | 1043 } // namespace ots |
| OLD | NEW |