| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 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 | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 // This is the implementation of decompression of the proposed WOFF Ultra | 
|  | 6 // Condensed file format. | 
|  | 7 | 
|  | 8 #include <cassert> | 
|  | 9 #include <cstdlib> | 
|  | 10 #include <vector> | 
|  | 11 | 
|  | 12 #include "third_party/brotli/src/brotli/dec/decode.h" | 
|  | 13 | 
|  | 14 #include "opentype-sanitiser.h" | 
|  | 15 #include "ots-memory-stream.h" | 
|  | 16 #include "ots.h" | 
|  | 17 #include "woff2.h" | 
|  | 18 | 
|  | 19 #define TABLE_NAME "WOFF2" | 
|  | 20 | 
|  | 21 namespace { | 
|  | 22 | 
|  | 23 // simple glyph flags | 
|  | 24 const uint8_t kGlyfOnCurve = 1 << 0; | 
|  | 25 const uint8_t kGlyfXShort = 1 << 1; | 
|  | 26 const uint8_t kGlyfYShort = 1 << 2; | 
|  | 27 const uint8_t kGlyfRepeat = 1 << 3; | 
|  | 28 const uint8_t kGlyfThisXIsSame = 1 << 4; | 
|  | 29 const uint8_t kGlyfThisYIsSame = 1 << 5; | 
|  | 30 | 
|  | 31 // composite glyph flags | 
|  | 32 const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0; | 
|  | 33 const int FLAG_WE_HAVE_A_SCALE = 1 << 3; | 
|  | 34 const int FLAG_MORE_COMPONENTS = 1 << 5; | 
|  | 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; | 
|  | 37 const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8; | 
|  | 38 | 
|  | 39 const size_t kSfntHeaderSize = 12; | 
|  | 40 const size_t kSfntEntrySize = 16; | 
|  | 41 const size_t kCheckSumAdjustmentOffset = 8; | 
|  | 42 | 
|  | 43 const size_t kEndPtsOfContoursOffset = 10; | 
|  | 44 const size_t kCompositeGlyphBegin = 10; | 
|  | 45 | 
|  | 46 // Note that the byte order is big-endian, not the same as ots.cc | 
|  | 47 #define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d) | 
|  | 48 | 
|  | 49 const unsigned int kWoff2FlagsTransform = 1 << 5; | 
|  | 50 | 
|  | 51 const uint32_t kKnownTags[] = { | 
|  | 52   TAG('c', 'm', 'a', 'p'),  // 0 | 
|  | 53   TAG('h', 'e', 'a', 'd'),  // 1 | 
|  | 54   TAG('h', 'h', 'e', 'a'),  // 2 | 
|  | 55   TAG('h', 'm', 't', 'x'),  // 3 | 
|  | 56   TAG('m', 'a', 'x', 'p'),  // 4 | 
|  | 57   TAG('n', 'a', 'm', 'e'),  // 5 | 
|  | 58   TAG('O', 'S', '/', '2'),  // 6 | 
|  | 59   TAG('p', 'o', 's', 't'),  // 7 | 
|  | 60   TAG('c', 'v', 't', ' '),  // 8 | 
|  | 61   TAG('f', 'p', 'g', 'm'),  // 9 | 
|  | 62   TAG('g', 'l', 'y', 'f'),  // 10 | 
|  | 63   TAG('l', 'o', 'c', 'a'),  // 11 | 
|  | 64   TAG('p', 'r', 'e', 'p'),  // 12 | 
|  | 65   TAG('C', 'F', 'F', ' '),  // 13 | 
|  | 66   TAG('V', 'O', 'R', 'G'),  // 14 | 
|  | 67   TAG('E', 'B', 'D', 'T'),  // 15 | 
|  | 68   TAG('E', 'B', 'L', 'C'),  // 16 | 
|  | 69   TAG('g', 'a', 's', 'p'),  // 17 | 
|  | 70   TAG('h', 'd', 'm', 'x'),  // 18 | 
|  | 71   TAG('k', 'e', 'r', 'n'),  // 19 | 
|  | 72   TAG('L', 'T', 'S', 'H'),  // 20 | 
|  | 73   TAG('P', 'C', 'L', 'T'),  // 21 | 
|  | 74   TAG('V', 'D', 'M', 'X'),  // 22 | 
|  | 75   TAG('v', 'h', 'e', 'a'),  // 23 | 
|  | 76   TAG('v', 'm', 't', 'x'),  // 24 | 
|  | 77   TAG('B', 'A', 'S', 'E'),  // 25 | 
|  | 78   TAG('G', 'D', 'E', 'F'),  // 26 | 
|  | 79   TAG('G', 'P', 'O', 'S'),  // 27 | 
|  | 80   TAG('G', 'S', 'U', 'B'),  // 28 | 
|  | 81   TAG('E', 'B', 'S', 'C'),  // 29 | 
|  | 82   TAG('J', 'S', 'T', 'F'),  // 30 | 
|  | 83   TAG('M', 'A', 'T', 'H'),  // 31 | 
|  | 84   TAG('C', 'B', 'D', 'T'),  // 32 | 
|  | 85   TAG('C', 'B', 'L', 'C'),  // 33 | 
|  | 86   TAG('C', 'O', 'L', 'R'),  // 34 | 
|  | 87   TAG('C', 'P', 'A', 'L'),  // 35 | 
|  | 88   TAG('S', 'V', 'G', ' '),  // 36 | 
|  | 89   TAG('s', 'b', 'i', 'x'),  // 37 | 
|  | 90   TAG('a', 'c', 'n', 't'),  // 38 | 
|  | 91   TAG('a', 'v', 'a', 'r'),  // 39 | 
|  | 92   TAG('b', 'd', 'a', 't'),  // 40 | 
|  | 93   TAG('b', 'l', 'o', 'c'),  // 41 | 
|  | 94   TAG('b', 's', 'l', 'n'),  // 42 | 
|  | 95   TAG('c', 'v', 'a', 'r'),  // 43 | 
|  | 96   TAG('f', 'd', 's', 'c'),  // 44 | 
|  | 97   TAG('f', 'e', 'a', 't'),  // 45 | 
|  | 98   TAG('f', 'm', 't', 'x'),  // 46 | 
|  | 99   TAG('f', 'v', 'a', 'r'),  // 47 | 
|  | 100   TAG('g', 'v', 'a', 'r'),  // 48 | 
|  | 101   TAG('h', 's', 't', 'y'),  // 49 | 
|  | 102   TAG('j', 'u', 's', 't'),  // 50 | 
|  | 103   TAG('l', 'c', 'a', 'r'),  // 51 | 
|  | 104   TAG('m', 'o', 'r', 't'),  // 52 | 
|  | 105   TAG('m', 'o', 'r', 'x'),  // 53 | 
|  | 106   TAG('o', 'p', 'b', 'd'),  // 54 | 
|  | 107   TAG('p', 'r', 'o', 'p'),  // 55 | 
|  | 108   TAG('t', 'r', 'a', 'k'),  // 56 | 
|  | 109   TAG('Z', 'a', 'p', 'f'),  // 57 | 
|  | 110   TAG('S', 'i', 'l', 'f'),  // 58 | 
|  | 111   TAG('G', 'l', 'a', 't'),  // 59 | 
|  | 112   TAG('G', 'l', 'o', 'c'),  // 60 | 
|  | 113   TAG('F', 'e', 'a', 't'),  // 61 | 
|  | 114   TAG('S', 'i', 'l', 'l'),  // 62 | 
|  | 115 }; | 
|  | 116 | 
|  | 117 struct Point { | 
|  | 118   int16_t x; | 
|  | 119   int16_t y; | 
|  | 120   bool on_curve; | 
|  | 121 }; | 
|  | 122 | 
|  | 123 struct Table { | 
|  | 124   uint32_t tag; | 
|  | 125   uint32_t flags; | 
|  | 126 | 
|  | 127   uint32_t transform_length; | 
|  | 128 | 
|  | 129   uint32_t dst_offset; | 
|  | 130   uint32_t dst_length; | 
|  | 131 | 
|  | 132   Table() | 
|  | 133       : tag(0), | 
|  | 134         flags(0), | 
|  | 135         transform_length(0), | 
|  | 136         dst_offset(0), | 
|  | 137         dst_length(0) {} | 
|  | 138 }; | 
|  | 139 | 
|  | 140 // Based on section 6.1.1 of MicroType Express draft spec | 
|  | 141 bool Read255UShort(ots::Buffer* buf, uint16_t* value) { | 
|  | 142   static const uint8_t kWordCode = 253; | 
|  | 143   static const uint8_t kOneMoreByteCode2 = 254; | 
|  | 144   static const uint8_t kOneMoreByteCode1 = 255; | 
|  | 145   static const uint8_t kLowestUCode = 253; | 
|  | 146   uint8_t code = 0; | 
|  | 147   if (!buf->ReadU8(&code)) { | 
|  | 148     return OTS_FAILURE(); | 
|  | 149   } | 
|  | 150   if (code == kWordCode) { | 
|  | 151     uint16_t result = 0; | 
|  | 152     if (!buf->ReadU16(&result)) { | 
|  | 153       return OTS_FAILURE(); | 
|  | 154     } | 
|  | 155     *value = result; | 
|  | 156     return true; | 
|  | 157   } else if (code == kOneMoreByteCode1) { | 
|  | 158     uint8_t result = 0; | 
|  | 159     if (!buf->ReadU8(&result)) { | 
|  | 160       return OTS_FAILURE(); | 
|  | 161     } | 
|  | 162     *value = result + kLowestUCode; | 
|  | 163     return true; | 
|  | 164   } else if (code == kOneMoreByteCode2) { | 
|  | 165     uint8_t result = 0; | 
|  | 166     if (!buf->ReadU8(&result)) { | 
|  | 167       return OTS_FAILURE(); | 
|  | 168     } | 
|  | 169     *value = result + kLowestUCode * 2; | 
|  | 170     return true; | 
|  | 171   } else { | 
|  | 172     *value = code; | 
|  | 173     return true; | 
|  | 174   } | 
|  | 175 } | 
|  | 176 | 
|  | 177 bool ReadBase128(ots::Buffer* buf, uint32_t* value) { | 
|  | 178   uint32_t result = 0; | 
|  | 179   for (size_t i = 0; i < 5; ++i) { | 
|  | 180     uint8_t code = 0; | 
|  | 181     if (!buf->ReadU8(&code)) { | 
|  | 182       return OTS_FAILURE(); | 
|  | 183     } | 
|  | 184     // If any of the top seven bits are set then we're about to overflow. | 
|  | 185     if (result & 0xfe000000U) { | 
|  | 186       return OTS_FAILURE(); | 
|  | 187     } | 
|  | 188     result = (result << 7) | (code & 0x7f); | 
|  | 189     if ((code & 0x80) == 0) { | 
|  | 190       *value = result; | 
|  | 191       return true; | 
|  | 192     } | 
|  | 193   } | 
|  | 194   // Make sure not to exceed the size bound | 
|  | 195   return OTS_FAILURE(); | 
|  | 196 } | 
|  | 197 | 
|  | 198 // Caller must ensure that buffer overrun won't happen. | 
|  | 199 // TODO(ksakamaoto): Consider creating 'writer' version of the Buffer class | 
|  | 200 // and use it across the code. | 
|  | 201 size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) { | 
|  | 202   dst[offset] = x >> 24; | 
|  | 203   dst[offset + 1] = (x >> 16) & 0xff; | 
|  | 204   dst[offset + 2] = (x >> 8) & 0xff; | 
|  | 205   dst[offset + 3] = x & 0xff; | 
|  | 206   return offset + 4; | 
|  | 207 } | 
|  | 208 | 
|  | 209 size_t StoreU16(uint8_t* dst, size_t offset, uint16_t x) { | 
|  | 210   dst[offset] = x >> 8; | 
|  | 211   dst[offset + 1] = x & 0xff; | 
|  | 212   return offset + 2; | 
|  | 213 } | 
|  | 214 | 
|  | 215 int WithSign(int flag, int baseval) { | 
|  | 216   assert(0 <= baseval && baseval < 65536); | 
|  | 217   return (flag & 1) ? baseval : -baseval; | 
|  | 218 } | 
|  | 219 | 
|  | 220 bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size, | 
|  | 221     unsigned int n_points, std::vector<Point>* result, | 
|  | 222     size_t* in_bytes_consumed) { | 
|  | 223   int x = 0; | 
|  | 224   int y = 0; | 
|  | 225 | 
|  | 226   // Early return if |in| buffer is too small. Each point consumes 1-4 bytes. | 
|  | 227   if (n_points > in_size) { | 
|  | 228     return OTS_FAILURE(); | 
|  | 229   } | 
|  | 230   unsigned int triplet_index = 0; | 
|  | 231 | 
|  | 232   for (unsigned int i = 0; i < n_points; ++i) { | 
|  | 233     uint8_t flag = flags_in[i]; | 
|  | 234     bool on_curve = !(flag >> 7); | 
|  | 235     flag &= 0x7f; | 
|  | 236     unsigned int n_data_bytes; | 
|  | 237     if (flag < 84) { | 
|  | 238       n_data_bytes = 1; | 
|  | 239     } else if (flag < 120) { | 
|  | 240       n_data_bytes = 2; | 
|  | 241     } else if (flag < 124) { | 
|  | 242       n_data_bytes = 3; | 
|  | 243     } else { | 
|  | 244       n_data_bytes = 4; | 
|  | 245     } | 
|  | 246     if (triplet_index + n_data_bytes > in_size || | 
|  | 247         triplet_index + n_data_bytes < triplet_index) { | 
|  | 248       return OTS_FAILURE(); | 
|  | 249     } | 
|  | 250     int dx, dy; | 
|  | 251     if (flag < 10) { | 
|  | 252       dx = 0; | 
|  | 253       dy = WithSign(flag, ((flag & 14) << 7) + in[triplet_index]); | 
|  | 254     } else if (flag < 20) { | 
|  | 255       dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]); | 
|  | 256       dy = 0; | 
|  | 257     } else if (flag < 84) { | 
|  | 258       int b0 = flag - 20; | 
|  | 259       int b1 = in[triplet_index]; | 
|  | 260       dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4)); | 
|  | 261       dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f)); | 
|  | 262     } else if (flag < 120) { | 
|  | 263       int b0 = flag - 84; | 
|  | 264       dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]); | 
|  | 265       dy = WithSign(flag >> 1, | 
|  | 266                     1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]); | 
|  | 267     } else if (flag < 124) { | 
|  | 268       int b2 = in[triplet_index + 1]; | 
|  | 269       dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4)); | 
|  | 270       dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]); | 
|  | 271     } else { | 
|  | 272       dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]); | 
|  | 273       dy = WithSign(flag >> 1, | 
|  | 274           (in[triplet_index + 2] << 8) + in[triplet_index + 3]); | 
|  | 275     } | 
|  | 276     triplet_index += n_data_bytes; | 
|  | 277     // Possible overflow but coordinate values are not security sensitive | 
|  | 278     x += dx; | 
|  | 279     y += dy; | 
|  | 280     result->push_back(Point()); | 
|  | 281     Point& back = result->back(); | 
|  | 282     back.x = static_cast<int16_t>(x); | 
|  | 283     back.y = static_cast<int16_t>(y); | 
|  | 284     back.on_curve = on_curve; | 
|  | 285   } | 
|  | 286   *in_bytes_consumed = triplet_index; | 
|  | 287   return true; | 
|  | 288 } | 
|  | 289 | 
|  | 290 // This function stores just the point data. On entry, dst points to the | 
|  | 291 // beginning of a simple glyph. Returns true on success. | 
|  | 292 bool StorePoints(const std::vector<Point>& points, | 
|  | 293     unsigned int n_contours, unsigned int instruction_length, | 
|  | 294     uint8_t* dst, size_t dst_size, size_t* glyph_size) { | 
|  | 295   // I believe that n_contours < 65536, in which case this is safe. However, a | 
|  | 296   // comment and/or an assert would be good. | 
|  | 297   unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 + | 
|  | 298     instruction_length; | 
|  | 299   uint8_t last_flag = 0xff; | 
|  | 300   uint8_t repeat_count = 0; | 
|  | 301   int last_x = 0; | 
|  | 302   int last_y = 0; | 
|  | 303   unsigned int x_bytes = 0; | 
|  | 304   unsigned int y_bytes = 0; | 
|  | 305 | 
|  | 306   for (size_t i = 0; i < points.size(); ++i) { | 
|  | 307     const Point& point = points.at(i); | 
|  | 308     uint8_t flag = point.on_curve ? kGlyfOnCurve : 0; | 
|  | 309     int dx = point.x - last_x; | 
|  | 310     int dy = point.y - last_y; | 
|  | 311     if (dx == 0) { | 
|  | 312       flag |= kGlyfThisXIsSame; | 
|  | 313     } else if (dx > -256 && dx < 256) { | 
|  | 314       flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0); | 
|  | 315       x_bytes += 1; | 
|  | 316     } else { | 
|  | 317       x_bytes += 2; | 
|  | 318     } | 
|  | 319     if (dy == 0) { | 
|  | 320       flag |= kGlyfThisYIsSame; | 
|  | 321     } else if (dy > -256 && dy < 256) { | 
|  | 322       flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0); | 
|  | 323       y_bytes += 1; | 
|  | 324     } else { | 
|  | 325       y_bytes += 2; | 
|  | 326     } | 
|  | 327 | 
|  | 328     if (flag == last_flag && repeat_count != 255) { | 
|  | 329       dst[flag_offset - 1] |= kGlyfRepeat; | 
|  | 330       repeat_count++; | 
|  | 331     } else { | 
|  | 332       if (repeat_count != 0) { | 
|  | 333         if (flag_offset >= dst_size) { | 
|  | 334           return OTS_FAILURE(); | 
|  | 335         } | 
|  | 336         dst[flag_offset++] = repeat_count; | 
|  | 337       } | 
|  | 338       if (flag_offset >= dst_size) { | 
|  | 339         return OTS_FAILURE(); | 
|  | 340       } | 
|  | 341       dst[flag_offset++] = flag; | 
|  | 342       repeat_count = 0; | 
|  | 343     } | 
|  | 344     last_x = point.x; | 
|  | 345     last_y = point.y; | 
|  | 346     last_flag = flag; | 
|  | 347   } | 
|  | 348 | 
|  | 349   if (repeat_count != 0) { | 
|  | 350     if (flag_offset >= dst_size) { | 
|  | 351       return OTS_FAILURE(); | 
|  | 352     } | 
|  | 353     dst[flag_offset++] = repeat_count; | 
|  | 354   } | 
|  | 355   unsigned int xy_bytes = x_bytes + y_bytes; | 
|  | 356   if (xy_bytes < x_bytes || | 
|  | 357       flag_offset + xy_bytes < flag_offset || | 
|  | 358       flag_offset + xy_bytes > dst_size) { | 
|  | 359     return OTS_FAILURE(); | 
|  | 360   } | 
|  | 361 | 
|  | 362   int x_offset = flag_offset; | 
|  | 363   int y_offset = flag_offset + x_bytes; | 
|  | 364   last_x = 0; | 
|  | 365   last_y = 0; | 
|  | 366   for (size_t i = 0; i < points.size(); ++i) { | 
|  | 367     int dx = points.at(i).x - last_x; | 
|  | 368     if (dx == 0) { | 
|  | 369       // pass | 
|  | 370     } else if (dx > -256 && dx < 256) { | 
|  | 371       dst[x_offset++] = static_cast<uint8_t>(std::abs(dx)); | 
|  | 372     } else { | 
|  | 373       // will always fit for valid input, but overflow is harmless | 
|  | 374       x_offset = StoreU16(dst, x_offset, static_cast<uint16_t>(dx)); | 
|  | 375     } | 
|  | 376     last_x += dx; | 
|  | 377     int dy = points.at(i).y - last_y; | 
|  | 378     if (dy == 0) { | 
|  | 379       // pass | 
|  | 380     } else if (dy > -256 && dy < 256) { | 
|  | 381       dst[y_offset++] = static_cast<uint8_t>(std::abs(dy)); | 
|  | 382     } else { | 
|  | 383       y_offset = StoreU16(dst, y_offset, static_cast<uint16_t>(dy)); | 
|  | 384     } | 
|  | 385     last_y += dy; | 
|  | 386   } | 
|  | 387   *glyph_size = y_offset; | 
|  | 388   return true; | 
|  | 389 } | 
|  | 390 | 
|  | 391 // Compute the bounding box of the coordinates, and store into a glyf buffer. | 
|  | 392 // A precondition is that there are at least 10 bytes available. | 
|  | 393 void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) { | 
|  | 394   int16_t x_min = 0; | 
|  | 395   int16_t y_min = 0; | 
|  | 396   int16_t x_max = 0; | 
|  | 397   int16_t y_max = 0; | 
|  | 398 | 
|  | 399   for (size_t i = 0; i < points.size(); ++i) { | 
|  | 400     int16_t x = points.at(i).x; | 
|  | 401     int16_t y = points.at(i).y; | 
|  | 402     if (i == 0 || x < x_min) x_min = x; | 
|  | 403     if (i == 0 || x > x_max) x_max = x; | 
|  | 404     if (i == 0 || y < y_min) y_min = y; | 
|  | 405     if (i == 0 || y > y_max) y_max = y; | 
|  | 406   } | 
|  | 407   size_t offset = 2; | 
|  | 408   offset = StoreU16(dst, offset, x_min); | 
|  | 409   offset = StoreU16(dst, offset, y_min); | 
|  | 410   offset = StoreU16(dst, offset, x_max); | 
|  | 411   offset = StoreU16(dst, offset, y_max); | 
|  | 412 } | 
|  | 413 | 
|  | 414 // Process entire bbox stream. This is done as a separate pass to allow for | 
|  | 415 // composite bbox computations (an optional more aggressive transform). | 
|  | 416 bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs, | 
|  | 417     const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf, | 
|  | 418     size_t glyf_buf_length) { | 
|  | 419   const uint8_t* buf = bbox_stream->buffer(); | 
|  | 420   if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) { | 
|  | 421     return OTS_FAILURE(); | 
|  | 422   } | 
|  | 423   // Safe because n_glyphs is bounded | 
|  | 424   unsigned int bitmap_length = ((n_glyphs + 31) >> 5) << 2; | 
|  | 425   if (!bbox_stream->Skip(bitmap_length)) { | 
|  | 426     return OTS_FAILURE(); | 
|  | 427   } | 
|  | 428   for (unsigned int i = 0; i < n_glyphs; ++i) { | 
|  | 429     if (buf[i >> 3] & (0x80 >> (i & 7))) { | 
|  | 430       uint32_t loca_offset = loca_values.at(i); | 
|  | 431       if (loca_values.at(i + 1) - loca_offset < kEndPtsOfContoursOffset) { | 
|  | 432         return OTS_FAILURE(); | 
|  | 433       } | 
|  | 434       if (glyf_buf_length < 2 + 10 || | 
|  | 435           loca_offset > glyf_buf_length - 2 - 10) { | 
|  | 436         return OTS_FAILURE(); | 
|  | 437       } | 
|  | 438       if (!bbox_stream->Read(glyf_buf + loca_offset + 2, 8)) { | 
|  | 439         return OTS_FAILURE(); | 
|  | 440       } | 
|  | 441     } | 
|  | 442   } | 
|  | 443   return true; | 
|  | 444 } | 
|  | 445 | 
|  | 446 bool ProcessComposite(ots::Buffer* composite_stream, uint8_t* dst, | 
|  | 447     size_t dst_size, size_t* glyph_size, bool* have_instructions) { | 
|  | 448   size_t start_offset = composite_stream->offset(); | 
|  | 449   bool we_have_instructions = false; | 
|  | 450 | 
|  | 451   uint16_t flags = FLAG_MORE_COMPONENTS; | 
|  | 452   while (flags & FLAG_MORE_COMPONENTS) { | 
|  | 453     if (!composite_stream->ReadU16(&flags)) { | 
|  | 454       return OTS_FAILURE(); | 
|  | 455     } | 
|  | 456     we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0; | 
|  | 457     size_t arg_size = 2;  // glyph index | 
|  | 458     if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) { | 
|  | 459       arg_size += 4; | 
|  | 460     } else { | 
|  | 461       arg_size += 2; | 
|  | 462     } | 
|  | 463     if (flags & FLAG_WE_HAVE_A_SCALE) { | 
|  | 464       arg_size += 2; | 
|  | 465     } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) { | 
|  | 466       arg_size += 4; | 
|  | 467     } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) { | 
|  | 468       arg_size += 8; | 
|  | 469     } | 
|  | 470     if (!composite_stream->Skip(arg_size)) { | 
|  | 471       return OTS_FAILURE(); | 
|  | 472     } | 
|  | 473   } | 
|  | 474   size_t composite_glyph_size = composite_stream->offset() - start_offset; | 
|  | 475   if (composite_glyph_size + kCompositeGlyphBegin > dst_size) { | 
|  | 476     return OTS_FAILURE(); | 
|  | 477   } | 
|  | 478   StoreU16(dst, 0, 0xffff);  // nContours = -1 for composite glyph | 
|  | 479   std::memcpy(dst + kCompositeGlyphBegin, | 
|  | 480       composite_stream->buffer() + start_offset, | 
|  | 481       composite_glyph_size); | 
|  | 482   *glyph_size = kCompositeGlyphBegin + composite_glyph_size; | 
|  | 483   *have_instructions = we_have_instructions; | 
|  | 484   return true; | 
|  | 485 } | 
|  | 486 | 
|  | 487 // Build TrueType loca table | 
|  | 488 bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format, | 
|  | 489     uint8_t* dst, size_t dst_size) { | 
|  | 490   const uint64_t loca_size = loca_values.size(); | 
|  | 491   const uint64_t offset_size = index_format ? 4 : 2; | 
|  | 492   if ((loca_size << 2) >> 2 != loca_size) { | 
|  | 493     return OTS_FAILURE(); | 
|  | 494   } | 
|  | 495   // No integer overflow here (loca_size <= 2^16). | 
|  | 496   if (offset_size * loca_size > dst_size) { | 
|  | 497     return OTS_FAILURE(); | 
|  | 498   } | 
|  | 499   size_t offset = 0; | 
|  | 500   for (size_t i = 0; i < loca_values.size(); ++i) { | 
|  | 501     uint32_t value = loca_values.at(i); | 
|  | 502     if (index_format) { | 
|  | 503       offset = StoreU32(dst, offset, value); | 
|  | 504     } else { | 
|  | 505       offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1)); | 
|  | 506     } | 
|  | 507   } | 
|  | 508   return true; | 
|  | 509 } | 
|  | 510 | 
|  | 511 // Reconstruct entire glyf table based on transformed original | 
|  | 512 bool ReconstructGlyf(const uint8_t* data, size_t data_size, | 
|  | 513     uint8_t* dst, size_t dst_size, | 
|  | 514     uint8_t* loca_buf, size_t loca_size) { | 
|  | 515   static const int kNumSubStreams = 7; | 
|  | 516   ots::Buffer file(data, data_size); | 
|  | 517   uint32_t version; | 
|  | 518   std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams); | 
|  | 519 | 
|  | 520   if (!file.ReadU32(&version)) { | 
|  | 521     return OTS_FAILURE(); | 
|  | 522   } | 
|  | 523   uint16_t num_glyphs; | 
|  | 524   uint16_t index_format; | 
|  | 525   if (!file.ReadU16(&num_glyphs) || | 
|  | 526       !file.ReadU16(&index_format)) { | 
|  | 527     return OTS_FAILURE(); | 
|  | 528   } | 
|  | 529   unsigned int offset = (2 + kNumSubStreams) * 4; | 
|  | 530   if (offset > data_size) { | 
|  | 531     return OTS_FAILURE(); | 
|  | 532   } | 
|  | 533   // Invariant from here on: data_size >= offset | 
|  | 534   for (int i = 0; i < kNumSubStreams; ++i) { | 
|  | 535     uint32_t substream_size; | 
|  | 536     if (!file.ReadU32(&substream_size)) { | 
|  | 537       return OTS_FAILURE(); | 
|  | 538     } | 
|  | 539     if (substream_size > data_size - offset) { | 
|  | 540       return OTS_FAILURE(); | 
|  | 541     } | 
|  | 542     substreams.at(i) = std::make_pair(data + offset, substream_size); | 
|  | 543     offset += substream_size; | 
|  | 544   } | 
|  | 545   ots::Buffer n_contour_stream(substreams.at(0).first, substreams.at(0).second); | 
|  | 546   ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second); | 
|  | 547   ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second); | 
|  | 548   ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second); | 
|  | 549   ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second); | 
|  | 550   ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second); | 
|  | 551   ots::Buffer instruction_stream(substreams.at(6).first, | 
|  | 552                                  substreams.at(6).second); | 
|  | 553 | 
|  | 554   std::vector<uint32_t> loca_values; | 
|  | 555   loca_values.reserve(num_glyphs + 1); | 
|  | 556   std::vector<uint16_t> n_points_vec; | 
|  | 557   std::vector<Point> points; | 
|  | 558   uint32_t loca_offset = 0; | 
|  | 559   for (unsigned int i = 0; i < num_glyphs; ++i) { | 
|  | 560     size_t glyph_size = 0; | 
|  | 561     uint16_t n_contours = 0; | 
|  | 562     if (!n_contour_stream.ReadU16(&n_contours)) { | 
|  | 563       return OTS_FAILURE(); | 
|  | 564     } | 
|  | 565     uint8_t* glyf_dst = dst + loca_offset; | 
|  | 566     size_t glyf_dst_size = dst_size - loca_offset; | 
|  | 567     if (n_contours == 0xffff) { | 
|  | 568       // composite glyph | 
|  | 569       bool have_instructions = false; | 
|  | 570       uint16_t instruction_size = 0; | 
|  | 571       if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size, | 
|  | 572             &glyph_size, &have_instructions)) { | 
|  | 573         return OTS_FAILURE(); | 
|  | 574       } | 
|  | 575       if (have_instructions) { | 
|  | 576         if (!Read255UShort(&glyph_stream, &instruction_size)) { | 
|  | 577           return OTS_FAILURE(); | 
|  | 578         } | 
|  | 579         // No integer overflow here (instruction_size < 2^16). | 
|  | 580         if (instruction_size + 2U > glyf_dst_size - glyph_size) { | 
|  | 581           return OTS_FAILURE(); | 
|  | 582         } | 
|  | 583         StoreU16(glyf_dst, glyph_size, instruction_size); | 
|  | 584         if (!instruction_stream.Read(glyf_dst + glyph_size + 2, | 
|  | 585               instruction_size)) { | 
|  | 586           return OTS_FAILURE(); | 
|  | 587         } | 
|  | 588         glyph_size += instruction_size + 2; | 
|  | 589       } | 
|  | 590     } else if (n_contours > 0) { | 
|  | 591       // simple glyph | 
|  | 592       n_points_vec.clear(); | 
|  | 593       points.clear(); | 
|  | 594       uint32_t total_n_points = 0; | 
|  | 595       uint16_t n_points_contour; | 
|  | 596       for (uint32_t j = 0; j < n_contours; ++j) { | 
|  | 597         if (!Read255UShort(&n_points_stream, &n_points_contour)) { | 
|  | 598           return OTS_FAILURE(); | 
|  | 599         } | 
|  | 600         n_points_vec.push_back(n_points_contour); | 
|  | 601         if (total_n_points + n_points_contour < total_n_points) { | 
|  | 602           return OTS_FAILURE(); | 
|  | 603         } | 
|  | 604         total_n_points += n_points_contour; | 
|  | 605       } | 
|  | 606       uint32_t flag_size = total_n_points; | 
|  | 607       if (flag_size > flag_stream.length() - flag_stream.offset()) { | 
|  | 608         return OTS_FAILURE(); | 
|  | 609       } | 
|  | 610       const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset(); | 
|  | 611       const uint8_t* triplet_buf = glyph_stream.buffer() + | 
|  | 612         glyph_stream.offset(); | 
|  | 613       size_t triplet_size = glyph_stream.length() - glyph_stream.offset(); | 
|  | 614       size_t triplet_bytes_consumed = 0; | 
|  | 615       if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points, | 
|  | 616             &points, &triplet_bytes_consumed)) { | 
|  | 617         return OTS_FAILURE(); | 
|  | 618       } | 
|  | 619       const uint32_t header_and_endpts_contours_size = | 
|  | 620           kEndPtsOfContoursOffset + 2 * n_contours; | 
|  | 621       if (glyf_dst_size < header_and_endpts_contours_size) { | 
|  | 622         return OTS_FAILURE(); | 
|  | 623       } | 
|  | 624       StoreU16(glyf_dst, 0, n_contours); | 
|  | 625       ComputeBbox(points, glyf_dst); | 
|  | 626       size_t endpts_offset = kEndPtsOfContoursOffset; | 
|  | 627       int end_point = -1; | 
|  | 628       for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) { | 
|  | 629         end_point += n_points_vec.at(contour_ix); | 
|  | 630         if (end_point >= 65536) { | 
|  | 631           return OTS_FAILURE(); | 
|  | 632         } | 
|  | 633         endpts_offset = StoreU16(glyf_dst, endpts_offset, static_cast<uint16_t>(
     end_point)); | 
|  | 634       } | 
|  | 635       if (!flag_stream.Skip(flag_size)) { | 
|  | 636         return OTS_FAILURE(); | 
|  | 637       } | 
|  | 638       if (!glyph_stream.Skip(triplet_bytes_consumed)) { | 
|  | 639         return OTS_FAILURE(); | 
|  | 640       } | 
|  | 641       uint16_t instruction_size; | 
|  | 642       if (!Read255UShort(&glyph_stream, &instruction_size)) { | 
|  | 643         return OTS_FAILURE(); | 
|  | 644       } | 
|  | 645       // No integer overflow here (instruction_size < 2^16). | 
|  | 646       if (glyf_dst_size - header_and_endpts_contours_size < | 
|  | 647           instruction_size + 2U) { | 
|  | 648         return OTS_FAILURE(); | 
|  | 649       } | 
|  | 650       uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size; | 
|  | 651       StoreU16(instruction_dst, 0, instruction_size); | 
|  | 652       if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) { | 
|  | 653         return OTS_FAILURE(); | 
|  | 654       } | 
|  | 655       if (!StorePoints(points, n_contours, instruction_size, | 
|  | 656             glyf_dst, glyf_dst_size, &glyph_size)) { | 
|  | 657         return OTS_FAILURE(); | 
|  | 658       } | 
|  | 659     } else { | 
|  | 660       glyph_size = 0; | 
|  | 661     } | 
|  | 662     loca_values.push_back(loca_offset); | 
|  | 663     if (glyph_size + 3 < glyph_size) { | 
|  | 664       return OTS_FAILURE(); | 
|  | 665     } | 
|  | 666     glyph_size = ots::Round2(glyph_size); | 
|  | 667     if (glyph_size > dst_size - loca_offset) { | 
|  | 668       // This shouldn't happen, but this test defensively maintains the | 
|  | 669       // invariant that loca_offset <= dst_size. | 
|  | 670       return OTS_FAILURE(); | 
|  | 671     } | 
|  | 672     loca_offset += glyph_size; | 
|  | 673   } | 
|  | 674   loca_values.push_back(loca_offset); | 
|  | 675   assert(loca_values.size() == static_cast<size_t>(num_glyphs + 1)); | 
|  | 676   if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values, | 
|  | 677           dst, dst_size)) { | 
|  | 678     return OTS_FAILURE(); | 
|  | 679   } | 
|  | 680   return StoreLoca(loca_values, index_format, loca_buf, loca_size); | 
|  | 681 } | 
|  | 682 | 
|  | 683 // This is linear search, but could be changed to binary because we | 
|  | 684 // do have a guarantee that the tables are sorted by tag. But the total | 
|  | 685 // cpu time is expected to be very small in any case. | 
|  | 686 const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) { | 
|  | 687   size_t n_tables = tables.size(); | 
|  | 688   for (size_t i = 0; i < n_tables; ++i) { | 
|  | 689     if (tables.at(i).tag == tag) { | 
|  | 690       return &tables.at(i); | 
|  | 691     } | 
|  | 692   } | 
|  | 693   return NULL; | 
|  | 694 } | 
|  | 695 | 
|  | 696 bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag, | 
|  | 697     const uint8_t* transformed_buf, size_t transformed_size, | 
|  | 698     uint8_t* dst, size_t dst_length) { | 
|  | 699   if (tag == TAG('g', 'l', 'y', 'f')) { | 
|  | 700     const Table* glyf_table = FindTable(tables, tag); | 
|  | 701     const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a')); | 
|  | 702     if (glyf_table == NULL || loca_table == NULL) { | 
|  | 703       return OTS_FAILURE(); | 
|  | 704     } | 
|  | 705     if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length > | 
|  | 706         dst_length) { | 
|  | 707       return OTS_FAILURE(); | 
|  | 708     } | 
|  | 709     if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length > | 
|  | 710         dst_length) { | 
|  | 711       return OTS_FAILURE(); | 
|  | 712     } | 
|  | 713     return ReconstructGlyf(transformed_buf, transformed_size, | 
|  | 714         dst + glyf_table->dst_offset, glyf_table->dst_length, | 
|  | 715         dst + loca_table->dst_offset, loca_table->dst_length); | 
|  | 716   } else if (tag == TAG('l', 'o', 'c', 'a')) { | 
|  | 717     // processing was already done by glyf table, but validate | 
|  | 718     if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) { | 
|  | 719       return OTS_FAILURE(); | 
|  | 720     } | 
|  | 721   } else { | 
|  | 722     // transform for the tag is not known | 
|  | 723     return OTS_FAILURE(); | 
|  | 724   } | 
|  | 725   return true; | 
|  | 726 } | 
|  | 727 | 
|  | 728 uint32_t ComputeChecksum(const uint8_t* buf, size_t size) { | 
|  | 729   uint32_t checksum = 0; | 
|  | 730   for (size_t i = 0; i < size; i += 4) { | 
|  | 731     // We assume the addition is mod 2^32, which is valid because unsigned | 
|  | 732     checksum += (buf[i] << 24) | (buf[i + 1] << 16) | | 
|  | 733       (buf[i + 2] << 8) | buf[i + 3]; | 
|  | 734   } | 
|  | 735   return checksum; | 
|  | 736 } | 
|  | 737 | 
|  | 738 bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) { | 
|  | 739   const Table* head_table = FindTable(tables, TAG('h', 'e', 'a', 'd')); | 
|  | 740   if (head_table == NULL || | 
|  | 741       head_table->dst_length < kCheckSumAdjustmentOffset + 4) { | 
|  | 742     return OTS_FAILURE(); | 
|  | 743   } | 
|  | 744   size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset; | 
|  | 745   if (adjustment_offset < head_table->dst_offset) { | 
|  | 746     return OTS_FAILURE(); | 
|  | 747   } | 
|  | 748   StoreU32(dst, adjustment_offset, 0); | 
|  | 749   size_t n_tables = tables.size(); | 
|  | 750   uint32_t file_checksum = 0; | 
|  | 751   for (size_t i = 0; i < n_tables; ++i) { | 
|  | 752     const Table* table = &tables.at(i); | 
|  | 753     size_t table_length = table->dst_length; | 
|  | 754     uint8_t* table_data = dst + table->dst_offset; | 
|  | 755     uint32_t checksum = ComputeChecksum(table_data, table_length); | 
|  | 756     StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum); | 
|  | 757     file_checksum += checksum;  // The addition is mod 2^32 | 
|  | 758   } | 
|  | 759   file_checksum += ComputeChecksum(dst, | 
|  | 760       kSfntHeaderSize + kSfntEntrySize * n_tables); | 
|  | 761   uint32_t checksum_adjustment = 0xb1b0afba - file_checksum; | 
|  | 762   StoreU32(dst, adjustment_offset, checksum_adjustment); | 
|  | 763   return true; | 
|  | 764 } | 
|  | 765 | 
|  | 766 bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size, | 
|  | 767     const uint8_t* src_buf, size_t src_size) { | 
|  | 768   size_t uncompressed_size = dst_size; | 
|  | 769   int ok = BrotliDecompressBuffer(src_size, src_buf, | 
|  | 770                                   &uncompressed_size, dst_buf); | 
|  | 771   if (!ok || uncompressed_size != dst_size) { | 
|  | 772     return OTS_FAILURE(); | 
|  | 773   } | 
|  | 774   return true; | 
|  | 775 } | 
|  | 776 | 
|  | 777 bool ReadTableDirectory(ots::OpenTypeFile* file, | 
|  | 778     ots::Buffer* buffer, std::vector<Table>* tables, | 
|  | 779     size_t num_tables) { | 
|  | 780   for (size_t i = 0; i < num_tables; ++i) { | 
|  | 781     Table* table = &tables->at(i); | 
|  | 782     uint8_t flag_byte; | 
|  | 783     if (!buffer->ReadU8(&flag_byte)) { | 
|  | 784       return OTS_FAILURE_MSG("Failed to read the flags of table directory entry 
     %d", i); | 
|  | 785     } | 
|  | 786     uint32_t tag; | 
|  | 787     if ((flag_byte & 0x3f) == 0x3f) { | 
|  | 788       if (!buffer->ReadU32(&tag)) { | 
|  | 789         return OTS_FAILURE_MSG("Failed to read the tag of table directory entry 
     %d", i); | 
|  | 790       } | 
|  | 791     } else { | 
|  | 792       tag = kKnownTags[flag_byte & 0x3f]; | 
|  | 793     } | 
|  | 794     // Bits 6 and 7 are reserved and must be 0. | 
|  | 795     if ((flag_byte & 0xc0) != 0) { | 
|  | 796       return OTS_FAILURE_MSG("Bits 6 and 7 are not 0 for table directory entry %
     d", i); | 
|  | 797     } | 
|  | 798     uint32_t flags = 0; | 
|  | 799     // Always transform the glyf and loca tables | 
|  | 800     if (tag == TAG('g', 'l', 'y', 'f') || | 
|  | 801         tag == TAG('l', 'o', 'c', 'a')) { | 
|  | 802       flags |= kWoff2FlagsTransform; | 
|  | 803     } | 
|  | 804     uint32_t dst_length; | 
|  | 805     if (!ReadBase128(buffer, &dst_length)) { | 
|  | 806       return OTS_FAILURE_MSG("Failed to read \"origLength\" for table %4.4s", (c
     har*)&tag); | 
|  | 807     } | 
|  | 808     uint32_t transform_length = dst_length; | 
|  | 809     if ((flags & kWoff2FlagsTransform) != 0) { | 
|  | 810       if (!ReadBase128(buffer, &transform_length)) { | 
|  | 811         return OTS_FAILURE_MSG("Failed to read \"transformLength\" for table %4.
     4s", (char*)&tag); | 
|  | 812       } | 
|  | 813     } | 
|  | 814     // Disallow huge numbers (> 1GB) for sanity. | 
|  | 815     if (transform_length > 1024 * 1024 * 1024 || | 
|  | 816         dst_length > 1024 * 1024 * 1024) { | 
|  | 817       return OTS_FAILURE_MSG("\"origLength\" or \"transformLength\" > 1GB"); | 
|  | 818     } | 
|  | 819     table->tag = tag; | 
|  | 820     table->flags = flags; | 
|  | 821     table->transform_length = transform_length; | 
|  | 822     table->dst_length = dst_length; | 
|  | 823   } | 
|  | 824   return true; | 
|  | 825 } | 
|  | 826 | 
|  | 827 }  // namespace | 
|  | 828 | 
|  | 829 namespace ots { | 
|  | 830 | 
|  | 831 size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) { | 
|  | 832   ots::Buffer file(data, length); | 
|  | 833   uint32_t total_length; | 
|  | 834 | 
|  | 835   if (!file.Skip(16) || | 
|  | 836       !file.ReadU32(&total_length)) { | 
|  | 837     return 0; | 
|  | 838   } | 
|  | 839   return total_length; | 
|  | 840 } | 
|  | 841 | 
|  | 842 bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file, | 
|  | 843                        uint8_t* result, size_t result_length, | 
|  | 844                        const uint8_t* data, size_t length) { | 
|  | 845   static const uint32_t kWoff2Signature = 0x774f4632;  // "wOF2" | 
|  | 846   ots::Buffer buffer(data, length); | 
|  | 847 | 
|  | 848   uint32_t signature; | 
|  | 849   uint32_t flavor = 0; | 
|  | 850   if (!buffer.ReadU32(&signature) || signature != kWoff2Signature || | 
|  | 851       !buffer.ReadU32(&flavor)) { | 
|  | 852     return OTS_FAILURE_MSG("Failed to read \"signature\" or \"flavor\", or not W
     OFF2 signature"); | 
|  | 853   } | 
|  | 854 | 
|  | 855   if (!IsValidVersionTag(ntohl(flavor))) { | 
|  | 856     return OTS_FAILURE_MSG("Invalid \"flavor\""); | 
|  | 857   } | 
|  | 858 | 
|  | 859   uint32_t reported_length; | 
|  | 860   if (!buffer.ReadU32(&reported_length) || length != reported_length) { | 
|  | 861     return OTS_FAILURE_MSG("Failed to read \"length\" or it does not match the a
     ctual file size"); | 
|  | 862   } | 
|  | 863   uint16_t num_tables; | 
|  | 864   if (!buffer.ReadU16(&num_tables) || !num_tables) { | 
|  | 865     return OTS_FAILURE_MSG("Failed to read \"numTables\""); | 
|  | 866   } | 
|  | 867   // We don't care about these fields of the header: | 
|  | 868   //   uint16_t reserved | 
|  | 869   //   uint32_t total_sfnt_size | 
|  | 870   if (!buffer.Skip(6)) { | 
|  | 871     return OTS_FAILURE_MSG("Failed to read \"reserve\" or \"totalSfntSize\""); | 
|  | 872   } | 
|  | 873   uint32_t compressed_length; | 
|  | 874   if (!buffer.ReadU32(&compressed_length)) { | 
|  | 875     return OTS_FAILURE_MSG("Failed to read \"totalCompressedSize\""); | 
|  | 876   } | 
|  | 877   if (compressed_length > std::numeric_limits<uint32_t>::max()) { | 
|  | 878     return OTS_FAILURE(); | 
|  | 879   } | 
|  | 880 | 
|  | 881   // We don't care about these fields of the header: | 
|  | 882   //   uint16_t major_version, minor_version | 
|  | 883   //   uint32_t meta_offset, meta_length, meta_orig_length | 
|  | 884   //   uint32_t priv_offset, priv_length | 
|  | 885   if (!buffer.Skip(24)) { | 
|  | 886     return OTS_FAILURE(); | 
|  | 887   } | 
|  | 888   std::vector<Table> tables(num_tables); | 
|  | 889   if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) { | 
|  | 890     return OTS_FAILURE_MSG("Failed to read table directory"); | 
|  | 891   } | 
|  | 892   uint64_t compressed_offset = buffer.offset(); | 
|  | 893   if (compressed_offset > std::numeric_limits<uint32_t>::max()) { | 
|  | 894     return OTS_FAILURE(); | 
|  | 895   } | 
|  | 896   uint64_t dst_offset = kSfntHeaderSize + | 
|  | 897       kSfntEntrySize * static_cast<uint64_t>(num_tables); | 
|  | 898   for (uint16_t i = 0; i < num_tables; ++i) { | 
|  | 899     Table* table = &tables.at(i); | 
|  | 900     table->dst_offset = static_cast<uint32_t>(dst_offset); | 
|  | 901     dst_offset += table->dst_length; | 
|  | 902     if (dst_offset > std::numeric_limits<uint32_t>::max()) { | 
|  | 903       return OTS_FAILURE(); | 
|  | 904     } | 
|  | 905     dst_offset = ots::Round4(dst_offset); | 
|  | 906   } | 
|  | 907   if (ots::Round4(compressed_offset + compressed_length) > length || dst_offset 
     > result_length) { | 
|  | 908     return OTS_FAILURE(); | 
|  | 909   } | 
|  | 910 | 
|  | 911   const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables; | 
|  | 912   if (sfnt_header_and_table_directory_size > result_length) { | 
|  | 913     return OTS_FAILURE(); | 
|  | 914   } | 
|  | 915 | 
|  | 916   // Start building the font | 
|  | 917   size_t offset = 0; | 
|  | 918   offset = StoreU32(result, offset, flavor); | 
|  | 919   offset = StoreU16(result, offset, num_tables); | 
|  | 920   uint8_t max_pow2 = 0; | 
|  | 921   while (1u << (max_pow2 + 1) <= num_tables) { | 
|  | 922     max_pow2++; | 
|  | 923   } | 
|  | 924   const uint16_t output_search_range = (1u << max_pow2) << 4; | 
|  | 925   offset = StoreU16(result, offset, output_search_range); | 
|  | 926   offset = StoreU16(result, offset, max_pow2); | 
|  | 927   offset = StoreU16(result, offset, (num_tables << 4) - output_search_range); | 
|  | 928   for (uint16_t i = 0; i < num_tables; ++i) { | 
|  | 929     const Table* table = &tables.at(i); | 
|  | 930     offset = StoreU32(result, offset, table->tag); | 
|  | 931     offset = StoreU32(result, offset, 0);  // checksum, to fill in later | 
|  | 932     offset = StoreU32(result, offset, table->dst_offset); | 
|  | 933     offset = StoreU32(result, offset, table->dst_length); | 
|  | 934   } | 
|  | 935   std::vector<uint8_t> uncompressed_buf; | 
|  | 936   const uint8_t* transform_buf = NULL; | 
|  | 937   uint64_t total_size = 0; | 
|  | 938 | 
|  | 939   for (uint16_t i = 0; i < num_tables; ++i) { | 
|  | 940     total_size += tables.at(i).transform_length; | 
|  | 941     if (total_size > std::numeric_limits<uint32_t>::max()) { | 
|  | 942       return OTS_FAILURE(); | 
|  | 943     } | 
|  | 944   } | 
|  | 945   // Enforce same 30M limit on uncompressed tables as OTS | 
|  | 946   if (total_size > 30 * 1024 * 1024) { | 
|  | 947     return OTS_FAILURE(); | 
|  | 948   } | 
|  | 949   const size_t total_size_size_t = static_cast<size_t>(total_size); | 
|  | 950   uncompressed_buf.resize(total_size_size_t); | 
|  | 951   const uint8_t* src_buf = data + compressed_offset; | 
|  | 952   if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t, | 
|  | 953       src_buf, compressed_length)) { | 
|  | 954     return OTS_FAILURE(); | 
|  | 955   } | 
|  | 956   transform_buf = &uncompressed_buf[0]; | 
|  | 957 | 
|  | 958   for (uint16_t i = 0; i < num_tables; ++i) { | 
|  | 959     const Table* table = &tables.at(i); | 
|  | 960     uint32_t flags = table->flags; | 
|  | 961     size_t transform_length = table->transform_length; | 
|  | 962 | 
|  | 963     if ((flags & kWoff2FlagsTransform) == 0) { | 
|  | 964       if (transform_length != table->dst_length) { | 
|  | 965         return OTS_FAILURE(); | 
|  | 966       } | 
|  | 967       if (static_cast<uint64_t>(table->dst_offset) + transform_length > | 
|  | 968           result_length) { | 
|  | 969         return OTS_FAILURE(); | 
|  | 970       } | 
|  | 971       std::memcpy(result + table->dst_offset, transform_buf, | 
|  | 972           transform_length); | 
|  | 973     } else { | 
|  | 974       if (!ReconstructTransformed(tables, table->tag, | 
|  | 975             transform_buf, transform_length, result, result_length)) { | 
|  | 976         return OTS_FAILURE(); | 
|  | 977       } | 
|  | 978     } | 
|  | 979 | 
|  | 980     transform_buf += transform_length; | 
|  | 981     if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) { | 
|  | 982       return OTS_FAILURE(); | 
|  | 983     } | 
|  | 984   } | 
|  | 985 | 
|  | 986   return FixChecksums(tables, result); | 
|  | 987 } | 
|  | 988 | 
|  | 989 }  // namespace ots | 
|  | 990 | 
|  | 991 #undef TABLE_NAME | 
| OLD | NEW | 
|---|