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