LCOV - code coverage report
Current view: top level - modules/woff2/src - woff2_dec.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 689 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 33 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 <algorithm>
      21             : #include <complex>
      22             : #include <cstring>
      23             : #include <limits>
      24             : #include <string>
      25             : #include <vector>
      26             : #include <map>
      27             : #include <memory>
      28             : #include <utility>
      29             : 
      30             : #include "mozilla/UniquePtr.h"
      31             : namespace std
      32             : {
      33             :   using mozilla::DefaultDelete;
      34             :   using mozilla::UniquePtr;
      35             :   #define default_delete DefaultDelete
      36             :   #define unique_ptr UniquePtr
      37             : }
      38             : 
      39             : #include "./decode.h"
      40             : #include "./buffer.h"
      41             : #include "./port.h"
      42             : #include "./round.h"
      43             : #include "./store_bytes.h"
      44             : #include "./table_tags.h"
      45             : #include "./variable_length.h"
      46             : #include "./woff2_common.h"
      47             : 
      48             : namespace woff2 {
      49             : 
      50             : namespace {
      51             : 
      52             : using std::string;
      53             : using std::vector;
      54             : 
      55             : 
      56             : // simple glyph flags
      57             : const int kGlyfOnCurve = 1 << 0;
      58             : const int kGlyfXShort = 1 << 1;
      59             : const int kGlyfYShort = 1 << 2;
      60             : const int kGlyfRepeat = 1 << 3;
      61             : const int kGlyfThisXIsSame = 1 << 4;
      62             : const int kGlyfThisYIsSame = 1 << 5;
      63             : 
      64             : // composite glyph flags
      65             : // See CompositeGlyph.java in sfntly for full definitions
      66             : const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
      67             : const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
      68             : const int FLAG_MORE_COMPONENTS = 1 << 5;
      69             : const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
      70             : const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
      71             : const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
      72             : 
      73             : const size_t kCheckSumAdjustmentOffset = 8;
      74             : 
      75             : const size_t kEndPtsOfContoursOffset = 10;
      76             : const size_t kCompositeGlyphBegin = 10;
      77             : 
      78             : // 98% of Google Fonts have no glyph above 5k bytes
      79             : // Largest glyph ever observed was 72k bytes
      80             : const size_t kDefaultGlyphBuf = 5120;
      81             : 
      82             : // Over 14k test fonts the max compression ratio seen to date was ~20.
      83             : // >100 suggests you wrote a bad uncompressed size.
      84             : const float kMaxPlausibleCompressionRatio = 100.0;
      85             : 
      86             : // metadata for a TTC font entry
      87           0 : struct TtcFont {
      88             :   uint32_t flavor;
      89             :   uint32_t dst_offset;
      90             :   uint32_t header_checksum;
      91             :   std::vector<uint16_t> table_indices;
      92             : };
      93             : 
      94           0 : struct WOFF2Header {
      95             :   uint32_t flavor;
      96             :   uint32_t header_version;
      97             :   uint16_t num_tables;
      98             :   uint64_t compressed_offset;
      99             :   uint32_t compressed_length;
     100             :   uint32_t uncompressed_size;
     101             :   std::vector<Table> tables;  // num_tables unique tables
     102             :   std::vector<TtcFont> ttc_fonts;  // metadata to help rebuild font
     103             : };
     104             : 
     105             : /**
     106             :  * Accumulates data we may need to reconstruct a single font. One per font
     107             :  * created for a TTC.
     108             :  */
     109           0 : struct WOFF2FontInfo {
     110             :   uint16_t num_glyphs;
     111             :   uint16_t index_format;
     112             :   uint16_t num_hmetrics;
     113             :   std::vector<int16_t> x_mins;
     114             :   std::map<uint32_t, uint32_t> table_entry_by_tag;
     115             : };
     116             : 
     117             : // Accumulates metadata as we rebuild the font
     118           0 : struct RebuildMetadata {
     119             :   uint32_t header_checksum;  // set by WriteHeaders
     120             :   std::vector<WOFF2FontInfo> font_infos;
     121             :   // checksums for tables that have been written.
     122             :   // (tag, src_offset) => checksum. Need both because 0-length loca.
     123             :   std::map<std::pair<uint32_t, uint32_t>, uint32_t> checksums;
     124             : };
     125             : 
     126           0 : int WithSign(int flag, int baseval) {
     127             :   // Precondition: 0 <= baseval < 65536 (to avoid integer overflow)
     128           0 :   return (flag & 1) ? baseval : -baseval;
     129             : }
     130             : 
     131           0 : bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
     132             :     unsigned int n_points, Point* result, size_t* in_bytes_consumed) {
     133           0 :   int x = 0;
     134           0 :   int y = 0;
     135             : 
     136           0 :   if (PREDICT_FALSE(n_points > in_size)) {
     137           0 :     return FONT_COMPRESSION_FAILURE();
     138             :   }
     139           0 :   unsigned int triplet_index = 0;
     140             : 
     141           0 :   for (unsigned int i = 0; i < n_points; ++i) {
     142           0 :     uint8_t flag = flags_in[i];
     143           0 :     bool on_curve = !(flag >> 7);
     144           0 :     flag &= 0x7f;
     145             :     unsigned int n_data_bytes;
     146           0 :     if (flag < 84) {
     147           0 :       n_data_bytes = 1;
     148           0 :     } else if (flag < 120) {
     149           0 :       n_data_bytes = 2;
     150           0 :     } else if (flag < 124) {
     151           0 :       n_data_bytes = 3;
     152             :     } else {
     153           0 :       n_data_bytes = 4;
     154             :     }
     155           0 :     if (PREDICT_FALSE(triplet_index + n_data_bytes > in_size ||
     156             :         triplet_index + n_data_bytes < triplet_index)) {
     157           0 :       return FONT_COMPRESSION_FAILURE();
     158             :     }
     159             :     int dx, dy;
     160           0 :     if (flag < 10) {
     161           0 :       dx = 0;
     162           0 :       dy = WithSign(flag, ((flag & 14) << 7) + in[triplet_index]);
     163           0 :     } else if (flag < 20) {
     164           0 :       dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]);
     165           0 :       dy = 0;
     166           0 :     } else if (flag < 84) {
     167           0 :       int b0 = flag - 20;
     168           0 :       int b1 = in[triplet_index];
     169           0 :       dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4));
     170           0 :       dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f));
     171           0 :     } else if (flag < 120) {
     172           0 :       int b0 = flag - 84;
     173           0 :       dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]);
     174           0 :       dy = WithSign(flag >> 1,
     175           0 :                     1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]);
     176           0 :     } else if (flag < 124) {
     177           0 :       int b2 = in[triplet_index + 1];
     178           0 :       dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4));
     179           0 :       dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]);
     180             :     } else {
     181           0 :       dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]);
     182           0 :       dy = WithSign(flag >> 1,
     183           0 :           (in[triplet_index + 2] << 8) + in[triplet_index + 3]);
     184             :     }
     185           0 :     triplet_index += n_data_bytes;
     186             :     // Possible overflow but coordinate values are not security sensitive
     187           0 :     x += dx;
     188           0 :     y += dy;
     189           0 :     *result++ = {x, y, on_curve};
     190             :   }
     191           0 :   *in_bytes_consumed = triplet_index;
     192           0 :   return true;
     193             : }
     194             : 
     195             : // This function stores just the point data. On entry, dst points to the
     196             : // beginning of a simple glyph. Returns true on success.
     197           0 : bool StorePoints(unsigned int n_points, const Point* points,
     198             :     unsigned int n_contours, unsigned int instruction_length,
     199             :     uint8_t* dst, size_t dst_size, size_t* glyph_size) {
     200             :   // I believe that n_contours < 65536, in which case this is safe. However, a
     201             :   // comment and/or an assert would be good.
     202           0 :   unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
     203           0 :     instruction_length;
     204           0 :   int last_flag = -1;
     205           0 :   int repeat_count = 0;
     206           0 :   int last_x = 0;
     207           0 :   int last_y = 0;
     208           0 :   unsigned int x_bytes = 0;
     209           0 :   unsigned int y_bytes = 0;
     210             : 
     211           0 :   for (unsigned int i = 0; i < n_points; ++i) {
     212           0 :     const Point& point = points[i];
     213           0 :     int flag = point.on_curve ? kGlyfOnCurve : 0;
     214           0 :     int dx = point.x - last_x;
     215           0 :     int dy = point.y - last_y;
     216           0 :     if (dx == 0) {
     217           0 :       flag |= kGlyfThisXIsSame;
     218           0 :     } else if (dx > -256 && dx < 256) {
     219           0 :       flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0);
     220           0 :       x_bytes += 1;
     221             :     } else {
     222           0 :       x_bytes += 2;
     223             :     }
     224           0 :     if (dy == 0) {
     225           0 :       flag |= kGlyfThisYIsSame;
     226           0 :     } else if (dy > -256 && dy < 256) {
     227           0 :       flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0);
     228           0 :       y_bytes += 1;
     229             :     } else {
     230           0 :       y_bytes += 2;
     231             :     }
     232             : 
     233           0 :     if (flag == last_flag && repeat_count != 255) {
     234           0 :       dst[flag_offset - 1] |= kGlyfRepeat;
     235           0 :       repeat_count++;
     236             :     } else {
     237           0 :       if (repeat_count != 0) {
     238           0 :         if (PREDICT_FALSE(flag_offset >= dst_size)) {
     239           0 :           return FONT_COMPRESSION_FAILURE();
     240             :         }
     241           0 :         dst[flag_offset++] = repeat_count;
     242             :       }
     243           0 :       if (PREDICT_FALSE(flag_offset >= dst_size)) {
     244           0 :         return FONT_COMPRESSION_FAILURE();
     245             :       }
     246           0 :       dst[flag_offset++] = flag;
     247           0 :       repeat_count = 0;
     248             :     }
     249           0 :     last_x = point.x;
     250           0 :     last_y = point.y;
     251           0 :     last_flag = flag;
     252             :   }
     253             : 
     254           0 :   if (repeat_count != 0) {
     255           0 :     if (PREDICT_FALSE(flag_offset >= dst_size)) {
     256           0 :       return FONT_COMPRESSION_FAILURE();
     257             :     }
     258           0 :     dst[flag_offset++] = repeat_count;
     259             :   }
     260           0 :   unsigned int xy_bytes = x_bytes + y_bytes;
     261           0 :   if (PREDICT_FALSE(xy_bytes < x_bytes ||
     262             :       flag_offset + xy_bytes < flag_offset ||
     263             :       flag_offset + xy_bytes > dst_size)) {
     264           0 :     return FONT_COMPRESSION_FAILURE();
     265             :   }
     266             : 
     267           0 :   int x_offset = flag_offset;
     268           0 :   int y_offset = flag_offset + x_bytes;
     269           0 :   last_x = 0;
     270           0 :   last_y = 0;
     271           0 :   for (unsigned int i = 0; i < n_points; ++i) {
     272           0 :     int dx = points[i].x - last_x;
     273           0 :     if (dx == 0) {
     274             :       // pass
     275           0 :     } else if (dx > -256 && dx < 256) {
     276           0 :       dst[x_offset++] = std::abs(dx);
     277             :     } else {
     278             :       // will always fit for valid input, but overflow is harmless
     279           0 :       x_offset = Store16(dst, x_offset, dx);
     280             :     }
     281           0 :     last_x += dx;
     282           0 :     int dy = points[i].y - last_y;
     283           0 :     if (dy == 0) {
     284             :       // pass
     285           0 :     } else if (dy > -256 && dy < 256) {
     286           0 :       dst[y_offset++] = std::abs(dy);
     287             :     } else {
     288           0 :       y_offset = Store16(dst, y_offset, dy);
     289             :     }
     290           0 :     last_y += dy;
     291             :   }
     292           0 :   *glyph_size = y_offset;
     293           0 :   return true;
     294             : }
     295             : 
     296             : // Compute the bounding box of the coordinates, and store into a glyf buffer.
     297             : // A precondition is that there are at least 10 bytes available.
     298             : // dst should point to the beginning of a 'glyf' record.
     299           0 : void ComputeBbox(unsigned int n_points, const Point* points, uint8_t* dst) {
     300           0 :   int x_min = 0;
     301           0 :   int y_min = 0;
     302           0 :   int x_max = 0;
     303           0 :   int y_max = 0;
     304             : 
     305           0 :   if (n_points > 0) {
     306           0 :     x_min = points[0].x;
     307           0 :     x_max = points[0].x;
     308           0 :     y_min = points[0].y;
     309           0 :     y_max = points[0].y;
     310             :   }
     311           0 :   for (unsigned int i = 1; i < n_points; ++i) {
     312           0 :     int x = points[i].x;
     313           0 :     int y = points[i].y;
     314           0 :     x_min = std::min(x, x_min);
     315           0 :     x_max = std::max(x, x_max);
     316           0 :     y_min = std::min(y, y_min);
     317           0 :     y_max = std::max(y, y_max);
     318             :   }
     319           0 :   size_t offset = 2;
     320           0 :   offset = Store16(dst, offset, x_min);
     321           0 :   offset = Store16(dst, offset, y_min);
     322           0 :   offset = Store16(dst, offset, x_max);
     323           0 :   offset = Store16(dst, offset, y_max);
     324           0 : }
     325             : 
     326             : 
     327           0 : bool SizeOfComposite(Buffer composite_stream, size_t* size,
     328             :                      bool* have_instructions) {
     329           0 :   size_t start_offset = composite_stream.offset();
     330           0 :   bool we_have_instructions = false;
     331             : 
     332           0 :   uint16_t flags = FLAG_MORE_COMPONENTS;
     333           0 :   while (flags & FLAG_MORE_COMPONENTS) {
     334           0 :     if (PREDICT_FALSE(!composite_stream.ReadU16(&flags))) {
     335           0 :       return FONT_COMPRESSION_FAILURE();
     336             :     }
     337           0 :     we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0;
     338           0 :     size_t arg_size = 2;  // glyph index
     339           0 :     if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
     340           0 :       arg_size += 4;
     341             :     } else {
     342           0 :       arg_size += 2;
     343             :     }
     344           0 :     if (flags & FLAG_WE_HAVE_A_SCALE) {
     345           0 :       arg_size += 2;
     346           0 :     } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
     347           0 :       arg_size += 4;
     348           0 :     } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
     349           0 :       arg_size += 8;
     350             :     }
     351           0 :     if (PREDICT_FALSE(!composite_stream.Skip(arg_size))) {
     352           0 :       return FONT_COMPRESSION_FAILURE();
     353             :     }
     354             :   }
     355             : 
     356           0 :   *size = composite_stream.offset() - start_offset;
     357           0 :   *have_instructions = we_have_instructions;
     358             : 
     359           0 :   return true;
     360             : }
     361             : 
     362           0 : bool Pad4(WOFF2Out* out) {
     363           0 :   uint8_t zeroes[] = {0, 0, 0};
     364           0 :   if (PREDICT_FALSE(out->Size() + 3 < out->Size())) {
     365           0 :     return FONT_COMPRESSION_FAILURE();
     366             :   }
     367           0 :   uint32_t pad_bytes = Round4(out->Size()) - out->Size();
     368           0 :   if (pad_bytes > 0) {
     369           0 :     if (PREDICT_FALSE(!out->Write(&zeroes, pad_bytes))) {
     370           0 :       return FONT_COMPRESSION_FAILURE();
     371             :     }
     372             :   }
     373           0 :   return true;
     374             : }
     375             : 
     376             : // Build TrueType loca table
     377           0 : bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
     378             :                uint32_t* checksum, WOFF2Out* out) {
     379             :   // TODO(user) figure out what index format to use based on whether max
     380             :   // offset fits into uint16_t or not
     381           0 :   const uint64_t loca_size = loca_values.size();
     382           0 :   const uint64_t offset_size = index_format ? 4 : 2;
     383           0 :   if (PREDICT_FALSE((loca_size << 2) >> 2 != loca_size)) {
     384           0 :     return FONT_COMPRESSION_FAILURE();
     385             :   }
     386           0 :   std::vector<uint8_t> loca_content(loca_size * offset_size);
     387           0 :   uint8_t* dst = &loca_content[0];
     388           0 :   size_t offset = 0;
     389           0 :   for (size_t i = 0; i < loca_values.size(); ++i) {
     390           0 :     uint32_t value = loca_values[i];
     391           0 :     if (index_format) {
     392           0 :       offset = StoreU32(dst, offset, value);
     393             :     } else {
     394           0 :       offset = Store16(dst, offset, value >> 1);
     395             :     }
     396             :   }
     397           0 :   *checksum = ComputeULongSum(&loca_content[0], loca_content.size());
     398           0 :   if (PREDICT_FALSE(!out->Write(&loca_content[0], loca_content.size()))) {
     399           0 :     return FONT_COMPRESSION_FAILURE();
     400             :   }
     401           0 :   return true;
     402             : }
     403             : 
     404             : // Reconstruct entire glyf table based on transformed original
     405           0 : bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
     406             :                      uint32_t* glyf_checksum, Table * loca_table,
     407             :                      uint32_t* loca_checksum, WOFF2FontInfo* info,
     408             :                      WOFF2Out* out) {
     409             :   static const int kNumSubStreams = 7;
     410           0 :   Buffer file(data, glyf_table->transform_length);
     411             :   uint32_t version;
     412           0 :   std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
     413           0 :   const size_t glyf_start = out->Size();
     414             : 
     415           0 :   if (PREDICT_FALSE(!file.ReadU32(&version))) {
     416           0 :     return FONT_COMPRESSION_FAILURE();
     417             :   }
     418           0 :   if (PREDICT_FALSE(!file.ReadU16(&info->num_glyphs) ||
     419             :       !file.ReadU16(&info->index_format))) {
     420           0 :     return FONT_COMPRESSION_FAILURE();
     421             :   }
     422             : 
     423           0 :   unsigned int offset = (2 + kNumSubStreams) * 4;
     424           0 :   if (PREDICT_FALSE(offset > glyf_table->transform_length)) {
     425           0 :     return FONT_COMPRESSION_FAILURE();
     426             :   }
     427             :   // Invariant from here on: data_size >= offset
     428           0 :   for (int i = 0; i < kNumSubStreams; ++i) {
     429             :     uint32_t substream_size;
     430           0 :     if (PREDICT_FALSE(!file.ReadU32(&substream_size))) {
     431           0 :       return FONT_COMPRESSION_FAILURE();
     432             :     }
     433           0 :     if (PREDICT_FALSE(substream_size > glyf_table->transform_length - offset)) {
     434           0 :       return FONT_COMPRESSION_FAILURE();
     435             :     }
     436           0 :     substreams[i] = std::make_pair(data + offset, substream_size);
     437           0 :     offset += substream_size;
     438             :   }
     439           0 :   Buffer n_contour_stream(substreams[0].first, substreams[0].second);
     440           0 :   Buffer n_points_stream(substreams[1].first, substreams[1].second);
     441           0 :   Buffer flag_stream(substreams[2].first, substreams[2].second);
     442           0 :   Buffer glyph_stream(substreams[3].first, substreams[3].second);
     443           0 :   Buffer composite_stream(substreams[4].first, substreams[4].second);
     444           0 :   Buffer bbox_stream(substreams[5].first, substreams[5].second);
     445           0 :   Buffer instruction_stream(substreams[6].first, substreams[6].second);
     446             : 
     447           0 :   std::vector<uint32_t> loca_values(info->num_glyphs + 1);
     448           0 :   std::vector<unsigned int> n_points_vec;
     449           0 :   std::unique_ptr<Point[]> points;
     450           0 :   size_t points_size = 0;
     451           0 :   const uint8_t* bbox_bitmap = bbox_stream.buffer();
     452             :   // Safe because num_glyphs is bounded
     453           0 :   unsigned int bitmap_length = ((info->num_glyphs + 31) >> 5) << 2;
     454           0 :   if (!bbox_stream.Skip(bitmap_length)) {
     455           0 :     return FONT_COMPRESSION_FAILURE();
     456             :   }
     457             : 
     458             :   // Temp buffer for glyph's.
     459           0 :   size_t glyph_buf_size = kDefaultGlyphBuf;
     460           0 :   std::unique_ptr<uint8_t[]> glyph_buf(new uint8_t[glyph_buf_size]);
     461             : 
     462           0 :   info->x_mins.resize(info->num_glyphs);
     463           0 :   for (unsigned int i = 0; i < info->num_glyphs; ++i) {
     464           0 :     size_t glyph_size = 0;
     465           0 :     uint16_t n_contours = 0;
     466           0 :     bool have_bbox = false;
     467           0 :     if (bbox_bitmap[i >> 3] & (0x80 >> (i & 7))) {
     468           0 :       have_bbox = true;
     469             :     }
     470           0 :     if (PREDICT_FALSE(!n_contour_stream.ReadU16(&n_contours))) {
     471           0 :       return FONT_COMPRESSION_FAILURE();
     472             :     }
     473             : 
     474           0 :     if (n_contours == 0xffff) {
     475             :       // composite glyph
     476           0 :       bool have_instructions = false;
     477           0 :       unsigned int instruction_size = 0;
     478           0 :       if (PREDICT_FALSE(!have_bbox)) {
     479             :         // composite glyphs must have an explicit bbox
     480           0 :         return FONT_COMPRESSION_FAILURE();
     481             :       }
     482             : 
     483             :       size_t composite_size;
     484           0 :       if (PREDICT_FALSE(!SizeOfComposite(composite_stream, &composite_size,
     485             :                                          &have_instructions))) {
     486           0 :         return FONT_COMPRESSION_FAILURE();
     487             :       }
     488           0 :       if (have_instructions) {
     489           0 :         if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) {
     490           0 :           return FONT_COMPRESSION_FAILURE();
     491             :         }
     492             :       }
     493             : 
     494           0 :       size_t size_needed = 12 + composite_size + instruction_size;
     495           0 :       if (PREDICT_FALSE(glyph_buf_size < size_needed)) {
     496           0 :         glyph_buf.reset(new uint8_t[size_needed]);
     497           0 :         glyph_buf_size = size_needed;
     498             :       }
     499             : 
     500           0 :       glyph_size = Store16(glyph_buf.get(), glyph_size, n_contours);
     501           0 :       if (PREDICT_FALSE(!bbox_stream.Read(glyph_buf.get() + glyph_size, 8))) {
     502           0 :         return FONT_COMPRESSION_FAILURE();
     503             :       }
     504           0 :       glyph_size += 8;
     505             : 
     506           0 :       if (PREDICT_FALSE(!composite_stream.Read(glyph_buf.get() + glyph_size,
     507             :             composite_size))) {
     508           0 :         return FONT_COMPRESSION_FAILURE();
     509             :       }
     510           0 :       glyph_size += composite_size;
     511           0 :       if (have_instructions) {
     512           0 :         glyph_size = Store16(glyph_buf.get(), glyph_size, instruction_size);
     513           0 :         if (PREDICT_FALSE(!instruction_stream.Read(glyph_buf.get() + glyph_size,
     514             :               instruction_size))) {
     515           0 :           return FONT_COMPRESSION_FAILURE();
     516             :         }
     517           0 :         glyph_size += instruction_size;
     518             :       }
     519           0 :     } else if (n_contours > 0) {
     520             :       // simple glyph
     521           0 :       n_points_vec.clear();
     522           0 :       unsigned int total_n_points = 0;
     523             :       unsigned int n_points_contour;
     524           0 :       for (unsigned int j = 0; j < n_contours; ++j) {
     525           0 :         if (PREDICT_FALSE(
     526             :             !Read255UShort(&n_points_stream, &n_points_contour))) {
     527           0 :           return FONT_COMPRESSION_FAILURE();
     528             :         }
     529           0 :         n_points_vec.push_back(n_points_contour);
     530           0 :         if (PREDICT_FALSE(total_n_points + n_points_contour < total_n_points)) {
     531           0 :           return FONT_COMPRESSION_FAILURE();
     532             :         }
     533           0 :         total_n_points += n_points_contour;
     534             :       }
     535           0 :       unsigned int flag_size = total_n_points;
     536           0 :       if (PREDICT_FALSE(
     537             :           flag_size > flag_stream.length() - flag_stream.offset())) {
     538           0 :         return FONT_COMPRESSION_FAILURE();
     539             :       }
     540           0 :       const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset();
     541           0 :       const uint8_t* triplet_buf = glyph_stream.buffer() +
     542           0 :         glyph_stream.offset();
     543           0 :       size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
     544           0 :       size_t triplet_bytes_consumed = 0;
     545           0 :       if (points_size < total_n_points) {
     546           0 :         points_size = total_n_points;
     547           0 :         points.reset(new Point[points_size]);
     548             :       }
     549           0 :       if (PREDICT_FALSE(!TripletDecode(flags_buf, triplet_buf, triplet_size,
     550             :           total_n_points, points.get(), &triplet_bytes_consumed))) {
     551           0 :         return FONT_COMPRESSION_FAILURE();
     552             :       }
     553           0 :       if (PREDICT_FALSE(!flag_stream.Skip(flag_size))) {
     554           0 :         return FONT_COMPRESSION_FAILURE();
     555             :       }
     556           0 :       if (PREDICT_FALSE(!glyph_stream.Skip(triplet_bytes_consumed))) {
     557           0 :         return FONT_COMPRESSION_FAILURE();
     558             :       }
     559             :       unsigned int instruction_size;
     560           0 :       if (PREDICT_FALSE(!Read255UShort(&glyph_stream, &instruction_size))) {
     561           0 :         return FONT_COMPRESSION_FAILURE();
     562             :       }
     563             : 
     564           0 :       if (PREDICT_FALSE(total_n_points >= (1 << 27)
     565             :                         || instruction_size >= (1 << 30))) {
     566           0 :         return FONT_COMPRESSION_FAILURE();
     567             :       }
     568           0 :       size_t size_needed = 12 + 2 * n_contours + 5 * total_n_points
     569           0 :                            + instruction_size;
     570           0 :       if (PREDICT_FALSE(glyph_buf_size < size_needed)) {
     571           0 :         glyph_buf.reset(new uint8_t[size_needed]);
     572           0 :         glyph_buf_size = size_needed;
     573             :       }
     574             : 
     575           0 :       glyph_size = Store16(glyph_buf.get(), glyph_size, n_contours);
     576           0 :       if (have_bbox) {
     577           0 :         if (PREDICT_FALSE(!bbox_stream.Read(glyph_buf.get() + glyph_size, 8))) {
     578           0 :           return FONT_COMPRESSION_FAILURE();
     579             :         }
     580             :       } else {
     581           0 :         ComputeBbox(total_n_points, points.get(), glyph_buf.get());
     582             :       }
     583           0 :       glyph_size = kEndPtsOfContoursOffset;
     584           0 :       int end_point = -1;
     585           0 :       for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
     586           0 :         end_point += n_points_vec[contour_ix];
     587           0 :         if (PREDICT_FALSE(end_point >= 65536)) {
     588           0 :           return FONT_COMPRESSION_FAILURE();
     589             :         }
     590           0 :         glyph_size = Store16(glyph_buf.get(), glyph_size, end_point);
     591             :       }
     592             : 
     593           0 :       glyph_size = Store16(glyph_buf.get(), glyph_size, instruction_size);
     594           0 :       if (PREDICT_FALSE(!instruction_stream.Read(glyph_buf.get() + glyph_size,
     595             :                                                  instruction_size))) {
     596           0 :         return FONT_COMPRESSION_FAILURE();
     597             :       }
     598           0 :       glyph_size += instruction_size;
     599             : 
     600           0 :       if (PREDICT_FALSE(!StorePoints(total_n_points, points.get(), n_contours,
     601             :             instruction_size, glyph_buf.get(), glyph_buf_size, &glyph_size))) {
     602           0 :         return FONT_COMPRESSION_FAILURE();
     603             :       }
     604             :     }
     605             : 
     606           0 :     loca_values[i] = out->Size() - glyf_start;
     607           0 :     if (PREDICT_FALSE(!out->Write(glyph_buf.get(), glyph_size))) {
     608           0 :       return FONT_COMPRESSION_FAILURE();
     609             :     }
     610             : 
     611             :     // TODO(user) Old code aligned glyphs ... but do we actually need to?
     612           0 :     if (PREDICT_FALSE(!Pad4(out))) {
     613           0 :       return FONT_COMPRESSION_FAILURE();
     614             :     }
     615             : 
     616           0 :     *glyf_checksum += ComputeULongSum(glyph_buf.get(), glyph_size);
     617             : 
     618             :     // We may need x_min to reconstruct 'hmtx'
     619           0 :     if (n_contours > 0) {
     620           0 :       Buffer x_min_buf(glyph_buf.get() + 2, 2);
     621           0 :       if (PREDICT_FALSE(!x_min_buf.ReadS16(&info->x_mins[i]))) {
     622           0 :         return FONT_COMPRESSION_FAILURE();
     623             :       }
     624             :     }
     625             :   }
     626             : 
     627             :   // glyf_table dst_offset was set by ReconstructFont
     628           0 :   glyf_table->dst_length = out->Size() - glyf_table->dst_offset;
     629           0 :   loca_table->dst_offset = out->Size();
     630             :   // loca[n] will be equal the length of the glyph data ('glyf') table
     631           0 :   loca_values[info->num_glyphs] = glyf_table->dst_length;
     632           0 :   if (PREDICT_FALSE(!StoreLoca(loca_values, info->index_format, loca_checksum,
     633             :       out))) {
     634           0 :     return FONT_COMPRESSION_FAILURE();
     635             :   }
     636           0 :   loca_table->dst_length = out->Size() - loca_table->dst_offset;
     637             : 
     638           0 :   return true;
     639             : }
     640             : 
     641           0 : Table* FindTable(std::vector<Table*>* tables, uint32_t tag) {
     642           0 :   for (Table* table : *tables) {
     643           0 :     if (table->tag == tag) {
     644           0 :       return table;
     645             :     }
     646             :   }
     647           0 :   return NULL;
     648             : }
     649             : 
     650             : // Get numberOfHMetrics, https://www.microsoft.com/typography/otspec/hhea.htm
     651           0 : bool ReadNumHMetrics(const uint8_t* data, size_t data_size,
     652             :                      uint16_t* num_hmetrics) {
     653             :   // Skip 34 to reach 'hhea' numberOfHMetrics
     654           0 :   Buffer buffer(data, data_size);
     655           0 :   if (PREDICT_FALSE(!buffer.Skip(34) || !buffer.ReadU16(num_hmetrics))) {
     656           0 :     return FONT_COMPRESSION_FAILURE();
     657             :   }
     658           0 :   return true;
     659             : }
     660             : 
     661             : // http://dev.w3.org/webfonts/WOFF2/spec/Overview.html#hmtx_table_format
     662           0 : bool ReconstructTransformedHmtx(const uint8_t* transformed_buf,
     663             :                                 size_t transformed_size,
     664             :                                 uint16_t num_glyphs,
     665             :                                 uint16_t num_hmetrics,
     666             :                                 const std::vector<int16_t>& x_mins,
     667             :                                 uint32_t* checksum,
     668             :                                 WOFF2Out* out) {
     669           0 :   Buffer hmtx_buff_in(transformed_buf, transformed_size);
     670             : 
     671             :   uint8_t hmtx_flags;
     672           0 :   if (PREDICT_FALSE(!hmtx_buff_in.ReadU8(&hmtx_flags))) {
     673           0 :     return FONT_COMPRESSION_FAILURE();
     674             :   }
     675             : 
     676           0 :   std::vector<uint16_t> advance_widths;
     677           0 :   std::vector<int16_t> lsbs;
     678           0 :   bool has_proportional_lsbs = (hmtx_flags & 1) == 0;
     679           0 :   bool has_monospace_lsbs = (hmtx_flags & 2) == 0;
     680             : 
     681             :   // you say you transformed but there is little evidence of it
     682           0 :   if (has_proportional_lsbs && has_monospace_lsbs) {
     683           0 :     return FONT_COMPRESSION_FAILURE();
     684             :   }
     685             : 
     686           0 :   assert(x_mins.size() == num_glyphs);
     687             : 
     688             :   // num_glyphs 0 is OK if there is no 'glyf' but cannot then xform 'hmtx'.
     689           0 :   if (PREDICT_FALSE(num_hmetrics > num_glyphs)) {
     690           0 :     return FONT_COMPRESSION_FAILURE();
     691             :   }
     692             : 
     693             :   // https://www.microsoft.com/typography/otspec/hmtx.htm
     694             :   // "...only one entry need be in the array, but that entry is required."
     695           0 :   if (PREDICT_FALSE(num_hmetrics < 1)) {
     696           0 :     return FONT_COMPRESSION_FAILURE();
     697             :   }
     698             : 
     699           0 :   for (uint16_t i = 0; i < num_hmetrics; i++) {
     700             :     uint16_t advance_width;
     701           0 :     if (PREDICT_FALSE(!hmtx_buff_in.ReadU16(&advance_width))) {
     702           0 :       return FONT_COMPRESSION_FAILURE();
     703             :     }
     704           0 :     advance_widths.push_back(advance_width);
     705             :   }
     706             : 
     707           0 :   for (uint16_t i = 0; i < num_hmetrics; i++) {
     708             :     int16_t lsb;
     709           0 :     if (has_proportional_lsbs) {
     710           0 :       if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
     711           0 :         return FONT_COMPRESSION_FAILURE();
     712             :       }
     713             :     } else {
     714           0 :       lsb = x_mins[i];
     715             :     }
     716           0 :     lsbs.push_back(lsb);
     717             :   }
     718             : 
     719           0 :   for (uint16_t i = num_hmetrics; i < num_glyphs; i++) {
     720             :     int16_t lsb;
     721           0 :     if (has_monospace_lsbs) {
     722           0 :       if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) {
     723           0 :         return FONT_COMPRESSION_FAILURE();
     724             :       }
     725             :     } else {
     726           0 :       lsb = x_mins[i];
     727             :     }
     728           0 :     lsbs.push_back(lsb);
     729             :   }
     730             : 
     731             :   // bake me a shiny new hmtx table
     732           0 :   uint32_t hmtx_output_size = 2 * num_glyphs + 2 * num_hmetrics;
     733           0 :   std::vector<uint8_t> hmtx_table(hmtx_output_size);
     734           0 :   uint8_t* dst = &hmtx_table[0];
     735           0 :   size_t dst_offset = 0;
     736           0 :   for (uint32_t i = 0; i < num_glyphs; i++) {
     737           0 :     if (i < num_hmetrics) {
     738           0 :       Store16(advance_widths[i], &dst_offset, dst);
     739             :     }
     740           0 :     Store16(lsbs[i], &dst_offset, dst);
     741             :   }
     742             : 
     743           0 :   *checksum = ComputeULongSum(&hmtx_table[0], hmtx_output_size);
     744           0 :   if (PREDICT_FALSE(!out->Write(&hmtx_table[0], hmtx_output_size))) {
     745           0 :     return FONT_COMPRESSION_FAILURE();
     746             :   }
     747             : 
     748           0 :   return true;
     749             : }
     750             : 
     751           0 : bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
     752             :   const uint8_t* src_buf, size_t src_size) {
     753           0 :   size_t uncompressed_size = dst_size;
     754           0 :   int ok = BrotliDecompressBuffer(src_size, src_buf,
     755           0 :                                   &uncompressed_size, dst_buf);
     756           0 :   if (PREDICT_FALSE(!ok || uncompressed_size != dst_size)) {
     757           0 :     return FONT_COMPRESSION_FAILURE();
     758             :   }
     759           0 :   return true;
     760             : }
     761             : 
     762           0 : bool ReadTableDirectory(Buffer* file, std::vector<Table>* tables,
     763             :     size_t num_tables) {
     764           0 :   uint32_t src_offset = 0;
     765           0 :   for (size_t i = 0; i < num_tables; ++i) {
     766           0 :     Table* table = &(*tables)[i];
     767             :     uint8_t flag_byte;
     768           0 :     if (PREDICT_FALSE(!file->ReadU8(&flag_byte))) {
     769           0 :       return FONT_COMPRESSION_FAILURE();
     770             :     }
     771             :     uint32_t tag;
     772           0 :     if ((flag_byte & 0x3f) == 0x3f) {
     773           0 :       if (PREDICT_FALSE(!file->ReadU32(&tag))) {
     774           0 :         return FONT_COMPRESSION_FAILURE();
     775             :       }
     776             :     } else {
     777           0 :       tag = kKnownTags[flag_byte & 0x3f];
     778             :     }
     779           0 :     uint32_t flags = 0;
     780           0 :     uint8_t xform_version = (flag_byte >> 6) & 0x03;
     781             : 
     782             :     // 0 means xform for glyph/loca, non-0 for others
     783           0 :     if (tag == kGlyfTableTag || tag == kLocaTableTag) {
     784           0 :       if (xform_version == 0) {
     785           0 :         flags |= kWoff2FlagsTransform;
     786             :       }
     787           0 :     } else if (xform_version != 0) {
     788           0 :       flags |= kWoff2FlagsTransform;
     789             :     }
     790           0 :     flags |= xform_version;
     791             : 
     792             :     uint32_t dst_length;
     793           0 :     if (PREDICT_FALSE(!ReadBase128(file, &dst_length))) {
     794           0 :       return FONT_COMPRESSION_FAILURE();
     795             :     }
     796           0 :     uint32_t transform_length = dst_length;
     797           0 :     if ((flags & kWoff2FlagsTransform) != 0) {
     798           0 :       if (PREDICT_FALSE(!ReadBase128(file, &transform_length))) {
     799           0 :         return FONT_COMPRESSION_FAILURE();
     800             :       }
     801           0 :       if (PREDICT_FALSE(tag == kLocaTableTag && transform_length)) {
     802           0 :         return FONT_COMPRESSION_FAILURE();
     803             :       }
     804             :     }
     805           0 :     if (PREDICT_FALSE(src_offset + transform_length < src_offset)) {
     806           0 :       return FONT_COMPRESSION_FAILURE();
     807             :     }
     808           0 :     table->src_offset = src_offset;
     809           0 :     table->src_length = transform_length;
     810           0 :     src_offset += transform_length;
     811             : 
     812           0 :     table->tag = tag;
     813           0 :     table->flags = flags;
     814           0 :     table->transform_length = transform_length;
     815           0 :     table->dst_length = dst_length;
     816             :   }
     817           0 :   return true;
     818             : }
     819             : 
     820             : // Writes a single Offset Table entry
     821           0 : size_t StoreOffsetTable(uint8_t* result, size_t offset, uint32_t flavor,
     822             :                         uint16_t num_tables) {
     823           0 :   offset = StoreU32(result, offset, flavor);  // sfnt version
     824           0 :   offset = Store16(result, offset, num_tables);  // num_tables
     825           0 :   unsigned max_pow2 = 0;
     826           0 :   while (1u << (max_pow2 + 1) <= num_tables) {
     827           0 :     max_pow2++;
     828             :   }
     829           0 :   const uint16_t output_search_range = (1u << max_pow2) << 4;
     830           0 :   offset = Store16(result, offset, output_search_range);  // searchRange
     831           0 :   offset = Store16(result, offset, max_pow2);  // entrySelector
     832             :   // rangeShift
     833           0 :   offset = Store16(result, offset, (num_tables << 4) - output_search_range);
     834           0 :   return offset;
     835             : }
     836             : 
     837           0 : size_t StoreTableEntry(uint8_t* result, uint32_t offset, uint32_t tag) {
     838           0 :   offset = StoreU32(result, offset, tag);
     839           0 :   offset = StoreU32(result, offset, 0);
     840           0 :   offset = StoreU32(result, offset, 0);
     841           0 :   offset = StoreU32(result, offset, 0);
     842           0 :   return offset;
     843             : }
     844             : 
     845             : // First table goes after all the headers, table directory, etc
     846           0 : uint64_t ComputeOffsetToFirstTable(const WOFF2Header& hdr) {
     847             :   uint64_t offset = kSfntHeaderSize +
     848           0 :     kSfntEntrySize * static_cast<uint64_t>(hdr.num_tables);
     849           0 :   if (hdr.header_version) {
     850           0 :     offset = CollectionHeaderSize(hdr.header_version, hdr.ttc_fonts.size())
     851           0 :       + kSfntHeaderSize * hdr.ttc_fonts.size();
     852           0 :     for (const auto& ttc_font : hdr.ttc_fonts) {
     853           0 :       offset += kSfntEntrySize * ttc_font.table_indices.size();
     854             :     }
     855             :   }
     856           0 :   return offset;
     857             : }
     858             : 
     859           0 : std::vector<Table*> Tables(WOFF2Header* hdr, size_t font_index) {
     860           0 :   std::vector<Table*> tables;
     861           0 :   if (PREDICT_FALSE(hdr->header_version)) {
     862           0 :     for (auto index : hdr->ttc_fonts[font_index].table_indices) {
     863           0 :       tables.push_back(&hdr->tables[index]);
     864             :     }
     865             :   } else {
     866           0 :     for (auto& table : hdr->tables) {
     867           0 :       tables.push_back(&table);
     868             :     }
     869             :   }
     870           0 :   return tables;
     871             : }
     872             : 
     873             : // Offset tables assumed to have been written in with 0's initially.
     874             : // WOFF2Header isn't const so we can use [] instead of at() (which upsets FF)
     875           0 : bool ReconstructFont(uint8_t* transformed_buf,
     876             :                      const uint32_t transformed_buf_size,
     877             :                      RebuildMetadata* metadata,
     878             :                      WOFF2Header* hdr,
     879             :                      size_t font_index,
     880             :                      WOFF2Out* out) {
     881           0 :   size_t dest_offset = out->Size();
     882             :   uint8_t table_entry[12];
     883           0 :   WOFF2FontInfo* info = &metadata->font_infos[font_index];
     884           0 :   std::vector<Table*> tables = Tables(hdr, font_index);
     885             : 
     886             :   // 'glyf' without 'loca' doesn't make sense
     887           0 :   if (PREDICT_FALSE(static_cast<bool>(FindTable(&tables, kGlyfTableTag)) !=
     888             :                     static_cast<bool>(FindTable(&tables, kLocaTableTag)))) {
     889           0 :     return FONT_COMPRESSION_FAILURE();
     890             :   }
     891             : 
     892           0 :   uint32_t font_checksum = metadata->header_checksum;
     893           0 :   if (hdr->header_version) {
     894           0 :     font_checksum = hdr->ttc_fonts[font_index].header_checksum;
     895             :   }
     896             : 
     897           0 :   uint32_t loca_checksum = 0;
     898           0 :   for (size_t i = 0; i < tables.size(); i++) {
     899           0 :     Table& table = *tables[i];
     900             : 
     901           0 :     std::pair<uint32_t, uint32_t> checksum_key = {table.tag, table.src_offset};
     902           0 :     bool reused = metadata->checksums.find(checksum_key)
     903           0 :                != metadata->checksums.end();
     904           0 :     if (PREDICT_FALSE(font_index == 0 && reused)) {
     905           0 :       return FONT_COMPRESSION_FAILURE();
     906             :     }
     907             : 
     908             :     // TODO(user) a collection with optimized hmtx that reused glyf/loca
     909             :     // would fail. We don't optimize hmtx for collections yet.
     910           0 :     if (PREDICT_FALSE(static_cast<uint64_t>(table.src_offset + table.src_length)
     911             :         > transformed_buf_size)) {
     912           0 :       return FONT_COMPRESSION_FAILURE();
     913             :     }
     914             : 
     915           0 :     if (table.tag == kHheaTableTag) {
     916           0 :       if (!ReadNumHMetrics(transformed_buf + table.src_offset,
     917           0 :           table.src_length, &info->num_hmetrics)) {
     918           0 :         return FONT_COMPRESSION_FAILURE();
     919             :       }
     920             :     }
     921             : 
     922           0 :     uint32_t checksum = 0;
     923           0 :     if (!reused) {
     924           0 :       if ((table.flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) {
     925           0 :         if (table.tag == kHeadTableTag) {
     926           0 :           if (PREDICT_FALSE(table.src_length < 12)) {
     927           0 :             return FONT_COMPRESSION_FAILURE();
     928             :           }
     929             :           // checkSumAdjustment = 0
     930           0 :           StoreU32(transformed_buf + table.src_offset, 8, 0);
     931             :         }
     932           0 :         table.dst_offset = dest_offset;
     933           0 :         checksum = ComputeULongSum(transformed_buf + table.src_offset,
     934           0 :                                    table.src_length);
     935           0 :         if (PREDICT_FALSE(!out->Write(transformed_buf + table.src_offset,
     936             :             table.src_length))) {
     937           0 :           return FONT_COMPRESSION_FAILURE();
     938             :         }
     939             :       } else {
     940           0 :         if (table.tag == kGlyfTableTag) {
     941           0 :           table.dst_offset = dest_offset;
     942             : 
     943           0 :           Table* loca_table = FindTable(&tables, kLocaTableTag);
     944           0 :           if (PREDICT_FALSE(!ReconstructGlyf(transformed_buf + table.src_offset,
     945             :               &table, &checksum, loca_table, &loca_checksum, info, out))) {
     946           0 :             return FONT_COMPRESSION_FAILURE();
     947             :           }
     948           0 :         } else if (table.tag == kLocaTableTag) {
     949             :           // All the work was done by ReconstructGlyf. We already know checksum.
     950           0 :           checksum = loca_checksum;
     951           0 :         } else if (table.tag == kHmtxTableTag) {
     952           0 :           table.dst_offset = dest_offset;
     953             :           // Tables are sorted so all the info we need has been gathered.
     954           0 :           if (PREDICT_FALSE(!ReconstructTransformedHmtx(
     955             :               transformed_buf + table.src_offset, table.src_length,
     956             :               info->num_glyphs, info->num_hmetrics, info->x_mins, &checksum,
     957             :               out))) {
     958           0 :             return FONT_COMPRESSION_FAILURE();
     959             :           }
     960             :         } else {
     961           0 :           return FONT_COMPRESSION_FAILURE();  // transform unknown
     962             :         }
     963             :       }
     964           0 :       metadata->checksums[checksum_key] = checksum;
     965             :     } else {
     966           0 :       checksum = metadata->checksums[checksum_key];
     967             :     }
     968           0 :     font_checksum += checksum;
     969             : 
     970             :     // update the table entry with real values.
     971           0 :     StoreU32(table_entry, 0, checksum);
     972           0 :     StoreU32(table_entry, 4, table.dst_offset);
     973           0 :     StoreU32(table_entry, 8, table.dst_length);
     974           0 :     if (PREDICT_FALSE(!out->Write(table_entry,
     975             :         info->table_entry_by_tag[table.tag] + 4, 12))) {
     976           0 :       return FONT_COMPRESSION_FAILURE();
     977             :     }
     978             : 
     979             :     // We replaced 0's. Update overall checksum.
     980           0 :     font_checksum += ComputeULongSum(table_entry, 12);
     981             : 
     982           0 :     if (PREDICT_FALSE(!Pad4(out))) {
     983           0 :       return FONT_COMPRESSION_FAILURE();
     984             :     }
     985             : 
     986           0 :     if (PREDICT_FALSE(static_cast<uint64_t>(table.dst_offset + table.dst_length)
     987             :         > out->Size())) {
     988           0 :       return FONT_COMPRESSION_FAILURE();
     989             :     }
     990           0 :     dest_offset = out->Size();
     991             :   }
     992             : 
     993             :   // Update 'head' checkSumAdjustment. We already set it to 0 and summed font.
     994           0 :   Table* head_table = FindTable(&tables, kHeadTableTag);
     995           0 :   if (head_table) {
     996           0 :     if (PREDICT_FALSE(head_table->dst_length < 12)) {
     997           0 :       return FONT_COMPRESSION_FAILURE();
     998             :     }
     999             :     uint8_t checksum_adjustment[4];
    1000           0 :     StoreU32(checksum_adjustment, 0, 0xB1B0AFBA - font_checksum);
    1001           0 :     if (PREDICT_FALSE(!out->Write(checksum_adjustment,
    1002             :                                   head_table->dst_offset + 8, 4))) {
    1003           0 :       return FONT_COMPRESSION_FAILURE();
    1004             :     }
    1005             :   }
    1006             : 
    1007           0 :   return true;
    1008             : }
    1009             : 
    1010           0 : bool ReadWOFF2Header(const uint8_t* data, size_t length, WOFF2Header* hdr) {
    1011           0 :   Buffer file(data, length);
    1012             : 
    1013             :   uint32_t signature;
    1014           0 :   if (PREDICT_FALSE(!file.ReadU32(&signature) || signature != kWoff2Signature ||
    1015             :       !file.ReadU32(&hdr->flavor))) {
    1016           0 :     return FONT_COMPRESSION_FAILURE();
    1017             :   }
    1018             : 
    1019             :   // TODO(user): Should call IsValidVersionTag() here.
    1020             : 
    1021             :   uint32_t reported_length;
    1022           0 :   if (PREDICT_FALSE(
    1023             :       !file.ReadU32(&reported_length) || length != reported_length)) {
    1024           0 :     return FONT_COMPRESSION_FAILURE();
    1025             :   }
    1026           0 :   if (PREDICT_FALSE(!file.ReadU16(&hdr->num_tables) || !hdr->num_tables)) {
    1027           0 :     return FONT_COMPRESSION_FAILURE();
    1028             :   }
    1029             : 
    1030             :   // We don't care about these fields of the header:
    1031             :   //   uint16_t reserved
    1032             :   //   uint32_t total_sfnt_size, we don't believe this, will compute later
    1033           0 :   if (PREDICT_FALSE(!file.Skip(6))) {
    1034           0 :     return FONT_COMPRESSION_FAILURE();
    1035             :   }
    1036           0 :   if (PREDICT_FALSE(!file.ReadU32(&hdr->compressed_length))) {
    1037           0 :     return FONT_COMPRESSION_FAILURE();
    1038             :   }
    1039             :   // We don't care about these fields of the header:
    1040             :   //   uint16_t major_version, minor_version
    1041           0 :   if (PREDICT_FALSE(!file.Skip(2 * 2))) {
    1042           0 :     return FONT_COMPRESSION_FAILURE();
    1043             :   }
    1044             :   uint32_t meta_offset;
    1045             :   uint32_t meta_length;
    1046             :   uint32_t meta_length_orig;
    1047           0 :   if (PREDICT_FALSE(!file.ReadU32(&meta_offset) ||
    1048             :       !file.ReadU32(&meta_length) ||
    1049             :       !file.ReadU32(&meta_length_orig))) {
    1050           0 :     return FONT_COMPRESSION_FAILURE();
    1051             :   }
    1052           0 :   if (meta_offset) {
    1053           0 :     if (PREDICT_FALSE(
    1054             :         meta_offset >= length || length - meta_offset < meta_length)) {
    1055           0 :       return FONT_COMPRESSION_FAILURE();
    1056             :     }
    1057             :   }
    1058             :   uint32_t priv_offset;
    1059             :   uint32_t priv_length;
    1060           0 :   if (PREDICT_FALSE(!file.ReadU32(&priv_offset) ||
    1061             :       !file.ReadU32(&priv_length))) {
    1062           0 :     return FONT_COMPRESSION_FAILURE();
    1063             :   }
    1064           0 :   if (priv_offset) {
    1065           0 :     if (PREDICT_FALSE(
    1066             :         priv_offset >= length || length - priv_offset < priv_length)) {
    1067           0 :       return FONT_COMPRESSION_FAILURE();
    1068             :     }
    1069             :   }
    1070           0 :   hdr->tables.resize(hdr->num_tables);
    1071           0 :   if (PREDICT_FALSE(!ReadTableDirectory(
    1072             :           &file, &hdr->tables, hdr->num_tables))) {
    1073           0 :     return FONT_COMPRESSION_FAILURE();
    1074             :   }
    1075             : 
    1076             :   // Before we sort for output the last table end is the uncompressed size.
    1077           0 :   Table& last_table = hdr->tables.back();
    1078           0 :   hdr->uncompressed_size = last_table.src_offset + last_table.src_length;
    1079           0 :   if (PREDICT_FALSE(hdr->uncompressed_size < last_table.src_offset)) {
    1080           0 :     return FONT_COMPRESSION_FAILURE();
    1081             :   }
    1082             : 
    1083           0 :   hdr->header_version = 0;
    1084             : 
    1085           0 :   if (hdr->flavor == kTtcFontFlavor) {
    1086           0 :     if (PREDICT_FALSE(!file.ReadU32(&hdr->header_version))) {
    1087           0 :       return FONT_COMPRESSION_FAILURE();
    1088             :     }
    1089           0 :     if (PREDICT_FALSE(hdr->header_version != 0x00010000
    1090             :                    && hdr->header_version != 0x00020000)) {
    1091           0 :       return FONT_COMPRESSION_FAILURE();
    1092             :     }
    1093             :     uint32_t num_fonts;
    1094           0 :     if (PREDICT_FALSE(!Read255UShort(&file, &num_fonts) || !num_fonts)) {
    1095           0 :       return FONT_COMPRESSION_FAILURE();
    1096             :     }
    1097           0 :     hdr->ttc_fonts.resize(num_fonts);
    1098             : 
    1099           0 :     for (uint32_t i = 0; i < num_fonts; i++) {
    1100           0 :       TtcFont& ttc_font = hdr->ttc_fonts[i];
    1101             :       uint32_t num_tables;
    1102           0 :       if (PREDICT_FALSE(!Read255UShort(&file, &num_tables) || !num_tables)) {
    1103           0 :         return FONT_COMPRESSION_FAILURE();
    1104             :       }
    1105           0 :       if (PREDICT_FALSE(!file.ReadU32(&ttc_font.flavor))) {
    1106           0 :         return FONT_COMPRESSION_FAILURE();
    1107             :       }
    1108             : 
    1109           0 :       ttc_font.table_indices.resize(num_tables);
    1110             : 
    1111           0 :       const Table* glyf_table = NULL;
    1112           0 :       const Table* loca_table = NULL;
    1113             : 
    1114           0 :       for (uint32_t j = 0; j < num_tables; j++) {
    1115             :         unsigned int table_idx;
    1116           0 :         if (PREDICT_FALSE(!Read255UShort(&file, &table_idx)) ||
    1117           0 :             table_idx >= hdr->tables.size()) {
    1118           0 :           return FONT_COMPRESSION_FAILURE();
    1119             :         }
    1120           0 :         ttc_font.table_indices[j] = table_idx;
    1121             : 
    1122           0 :         const Table& table = hdr->tables[table_idx];
    1123           0 :         if (table.tag == kLocaTableTag) {
    1124           0 :           loca_table = &table;
    1125             :         }
    1126           0 :         if (table.tag == kGlyfTableTag) {
    1127           0 :           glyf_table = &table;
    1128             :         }
    1129             : 
    1130             :       }
    1131             : 
    1132           0 :       if (PREDICT_FALSE((glyf_table == NULL) != (loca_table == NULL))) {
    1133             : #ifdef FONT_COMPRESSION_BIN
    1134             :         fprintf(stderr, "Cannot have just one of glyf/loca\n");
    1135             : #endif
    1136           0 :         return FONT_COMPRESSION_FAILURE();
    1137             :       }
    1138             :     }
    1139             :   }
    1140             : 
    1141           0 :   const uint64_t first_table_offset = ComputeOffsetToFirstTable(*hdr);
    1142             : 
    1143           0 :   hdr->compressed_offset = file.offset();
    1144           0 :   if (PREDICT_FALSE(hdr->compressed_offset >
    1145             :                     std::numeric_limits<uint32_t>::max())) {
    1146           0 :     return FONT_COMPRESSION_FAILURE();
    1147             :   }
    1148           0 :   uint64_t src_offset = Round4(hdr->compressed_offset + hdr->compressed_length);
    1149           0 :   uint64_t dst_offset = first_table_offset;
    1150             : 
    1151             : 
    1152           0 :   if (PREDICT_FALSE(src_offset > length)) {
    1153             : #ifdef FONT_COMPRESSION_BIN
    1154             :     fprintf(stderr, "offset fail; src_offset %" PRIu64 " length %lu "
    1155             :       "dst_offset %" PRIu64 "\n",
    1156             :       src_offset, length, dst_offset);
    1157             : #endif
    1158           0 :     return FONT_COMPRESSION_FAILURE();
    1159             :   }
    1160           0 :   if (meta_offset) {
    1161           0 :     if (PREDICT_FALSE(src_offset != meta_offset)) {
    1162           0 :       return FONT_COMPRESSION_FAILURE();
    1163             :     }
    1164           0 :     src_offset = Round4(meta_offset + meta_length);
    1165           0 :     if (PREDICT_FALSE(src_offset > std::numeric_limits<uint32_t>::max())) {
    1166           0 :       return FONT_COMPRESSION_FAILURE();
    1167             :     }
    1168             :   }
    1169             : 
    1170           0 :   if (priv_offset) {
    1171           0 :     if (PREDICT_FALSE(src_offset != priv_offset)) {
    1172           0 :       return FONT_COMPRESSION_FAILURE();
    1173             :     }
    1174           0 :     src_offset = Round4(priv_offset + priv_length);
    1175           0 :     if (PREDICT_FALSE(src_offset > std::numeric_limits<uint32_t>::max())) {
    1176           0 :       return FONT_COMPRESSION_FAILURE();
    1177             :     }
    1178             :   }
    1179             : 
    1180           0 :   if (PREDICT_FALSE(src_offset != Round4(length))) {
    1181           0 :     return FONT_COMPRESSION_FAILURE();
    1182             :   }
    1183             : 
    1184           0 :   return true;
    1185             : }
    1186             : 
    1187             : // Write everything before the actual table data
    1188           0 : bool WriteHeaders(const uint8_t* data, size_t length, RebuildMetadata* metadata,
    1189             :                   WOFF2Header* hdr, WOFF2Out* out) {
    1190           0 :   std::vector<uint8_t> output(ComputeOffsetToFirstTable(*hdr), 0);
    1191             : 
    1192             :   // Re-order tables in output (OTSpec) order
    1193           0 :   std::vector<Table> sorted_tables(hdr->tables);
    1194           0 :   if (hdr->header_version) {
    1195             :     // collection; we have to sort the table offset vector in each font
    1196           0 :     for (auto& ttc_font : hdr->ttc_fonts) {
    1197           0 :       std::map<uint32_t, uint16_t> sorted_index_by_tag;
    1198           0 :       for (auto table_index : ttc_font.table_indices) {
    1199           0 :         sorted_index_by_tag[hdr->tables[table_index].tag] = table_index;
    1200             :       }
    1201           0 :       uint16_t index = 0;
    1202           0 :       for (auto& i : sorted_index_by_tag) {
    1203           0 :         ttc_font.table_indices[index++] = i.second;
    1204             :       }
    1205             :     }
    1206             :   } else {
    1207             :     // non-collection; we can just sort the tables
    1208           0 :     std::sort(sorted_tables.begin(), sorted_tables.end());
    1209             :   }
    1210             : 
    1211             :   // Start building the font
    1212           0 :   uint8_t* result = &output[0];
    1213           0 :   size_t offset = 0;
    1214           0 :   if (hdr->header_version) {
    1215             :     // TTC header
    1216           0 :     offset = StoreU32(result, offset, hdr->flavor);  // TAG TTCTag
    1217           0 :     offset = StoreU32(result, offset, hdr->header_version);  // FIXED Version
    1218           0 :     offset = StoreU32(result, offset, hdr->ttc_fonts.size());  // ULONG numFonts
    1219             :     // Space for ULONG OffsetTable[numFonts] (zeroed initially)
    1220           0 :     size_t offset_table = offset;  // keep start of offset table for later
    1221           0 :     for (size_t i = 0; i < hdr->ttc_fonts.size(); i++) {
    1222           0 :       offset = StoreU32(result, offset, 0);  // will fill real values in later
    1223             :     }
    1224             :     // space for DSIG fields for header v2
    1225           0 :     if (hdr->header_version == 0x00020000) {
    1226           0 :       offset = StoreU32(result, offset, 0);  // ULONG ulDsigTag
    1227           0 :       offset = StoreU32(result, offset, 0);  // ULONG ulDsigLength
    1228           0 :       offset = StoreU32(result, offset, 0);  // ULONG ulDsigOffset
    1229             :     }
    1230             : 
    1231             :     // write Offset Tables and store the location of each in TTC Header
    1232           0 :     metadata->font_infos.resize(hdr->ttc_fonts.size());
    1233           0 :     for (size_t i = 0; i < hdr->ttc_fonts.size(); i++) {
    1234           0 :       TtcFont& ttc_font = hdr->ttc_fonts[i];
    1235             : 
    1236             :       // write Offset Table location into TTC Header
    1237           0 :       offset_table = StoreU32(result, offset_table, offset);
    1238             : 
    1239             :       // write the actual offset table so our header doesn't lie
    1240           0 :       ttc_font.dst_offset = offset;
    1241           0 :       offset = StoreOffsetTable(result, offset, ttc_font.flavor,
    1242           0 :                                 ttc_font.table_indices.size());
    1243             : 
    1244           0 :       for (const auto table_index : ttc_font.table_indices) {
    1245           0 :         uint32_t tag = hdr->tables[table_index].tag;
    1246           0 :         metadata->font_infos[i].table_entry_by_tag[tag] = offset;
    1247           0 :         offset = StoreTableEntry(result, offset, tag);
    1248             :       }
    1249             : 
    1250           0 :       ttc_font.header_checksum = ComputeULongSum(&output[ttc_font.dst_offset],
    1251           0 :                                                  offset - ttc_font.dst_offset);
    1252             :     }
    1253             :   } else {
    1254           0 :     metadata->font_infos.resize(1);
    1255           0 :     offset = StoreOffsetTable(result, offset, hdr->flavor, hdr->num_tables);
    1256           0 :     for (uint16_t i = 0; i < hdr->num_tables; ++i) {
    1257           0 :       metadata->font_infos[0].table_entry_by_tag[sorted_tables[i].tag] = offset;
    1258           0 :       offset = StoreTableEntry(result, offset, sorted_tables[i].tag);
    1259             :     }
    1260             :   }
    1261             : 
    1262           0 :   if (PREDICT_FALSE(!out->Write(&output[0], output.size()))) {
    1263           0 :     return FONT_COMPRESSION_FAILURE();
    1264             :   }
    1265           0 :   metadata->header_checksum = ComputeULongSum(&output[0], output.size());
    1266           0 :   return true;
    1267             : }
    1268             : 
    1269             : }  // namespace
    1270             : 
    1271           0 : size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
    1272           0 :   Buffer file(data, length);
    1273             :   uint32_t total_length;
    1274             : 
    1275           0 :   if (!file.Skip(16) ||
    1276           0 :       !file.ReadU32(&total_length)) {
    1277           0 :     return 0;
    1278             :   }
    1279           0 :   return total_length;
    1280             : }
    1281             : 
    1282           0 : bool ConvertWOFF2ToTTF(uint8_t *result, size_t result_length,
    1283             :                        const uint8_t *data, size_t length) {
    1284           0 :   WOFF2MemoryOut out(result, result_length);
    1285           0 :   return ConvertWOFF2ToTTF(data, length, &out);
    1286             : }
    1287             : 
    1288           0 : bool ConvertWOFF2ToTTF(const uint8_t* data, size_t length,
    1289             :                        WOFF2Out* out) {
    1290           0 :   RebuildMetadata metadata;
    1291           0 :   WOFF2Header hdr;
    1292           0 :   if (!ReadWOFF2Header(data, length, &hdr)) {
    1293           0 :     return FONT_COMPRESSION_FAILURE();
    1294             :   }
    1295             : 
    1296           0 :   if (!WriteHeaders(data, length, &metadata, &hdr, out)) {
    1297           0 :     return FONT_COMPRESSION_FAILURE();
    1298             :   }
    1299             : 
    1300           0 :   const float compression_ratio = (float) hdr.uncompressed_size / length;
    1301           0 :   if (compression_ratio > kMaxPlausibleCompressionRatio) {
    1302             : #ifdef FONT_COMPRESSION_BIN
    1303             :     fprintf(stderr, "Implausible compression ratio %.01f\n", compression_ratio);
    1304             : #endif
    1305           0 :     return FONT_COMPRESSION_FAILURE();
    1306             :   }
    1307             : 
    1308           0 :   const uint8_t* src_buf = data + hdr.compressed_offset;
    1309           0 :   std::vector<uint8_t> uncompressed_buf(hdr.uncompressed_size);
    1310           0 :   if (PREDICT_FALSE(!Woff2Uncompress(&uncompressed_buf[0],
    1311             :                                      hdr.uncompressed_size, src_buf,
    1312             :                                      hdr.compressed_length))) {
    1313           0 :     return FONT_COMPRESSION_FAILURE();
    1314             :   }
    1315             : 
    1316           0 :   for (size_t i = 0; i < metadata.font_infos.size(); i++) {
    1317           0 :     if (PREDICT_FALSE(!ReconstructFont(&uncompressed_buf[0],
    1318             :                                        hdr.uncompressed_size,
    1319             :                                        &metadata, &hdr, i, out))) {
    1320           0 :       return FONT_COMPRESSION_FAILURE();
    1321             :     }
    1322             :   }
    1323             : 
    1324           0 :   return true;
    1325             : }
    1326             : 
    1327             : } // namespace woff2

Generated by: LCOV version 1.13