blob: fda5d851b282d0b63d1680a87289b877c1e6be5d [file] [log] [blame]
Kenichi Ishibashi142d8882014-05-30 09:06:32 +09001// Copyright 2014 Google Inc. All Rights Reserved.
Roderick Sheeter437bbad2013-11-19 14:32:56 -08002//
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//
Kenichi Ishibashic75ed762014-06-04 08:29:53 +090015// Library for converting WOFF2 format font files to their TTF versions.
Roderick Sheeter437bbad2013-11-19 14:32:56 -080016
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090017#include "./woff2_dec.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080018
19#include <stdlib.h>
20#include <complex>
21#include <cstring>
22#include <limits>
23#include <string>
24#include <vector>
25
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090026#include "./buffer.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080027#include "./decode.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080028#include "./round.h"
29#include "./store_bytes.h"
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090030#include "./table_tags.h"
31#include "./woff2_common.h"
Roderick Sheeter437bbad2013-11-19 14:32:56 -080032
33namespace woff2 {
34
35namespace {
36
37using std::string;
38using std::vector;
39
40
Roderick Sheeter437bbad2013-11-19 14:32:56 -080041// simple glyph flags
42const int kGlyfOnCurve = 1 << 0;
43const int kGlyfXShort = 1 << 1;
44const int kGlyfYShort = 1 << 2;
45const int kGlyfRepeat = 1 << 3;
46const int kGlyfThisXIsSame = 1 << 4;
47const int kGlyfThisYIsSame = 1 << 5;
48
49// composite glyph flags
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090050// See CompositeGlyph.java in sfntly for full definitions
Roderick Sheeter437bbad2013-11-19 14:32:56 -080051const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
Roderick Sheeter437bbad2013-11-19 14:32:56 -080052const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
Roderick Sheeter437bbad2013-11-19 14:32:56 -080053const int FLAG_MORE_COMPONENTS = 1 << 5;
54const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
55const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
56const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
Roderick Sheeter437bbad2013-11-19 14:32:56 -080057
58const size_t kSfntHeaderSize = 12;
59const size_t kSfntEntrySize = 16;
60const size_t kCheckSumAdjustmentOffset = 8;
61
62const size_t kEndPtsOfContoursOffset = 10;
63const size_t kCompositeGlyphBegin = 10;
64
Roderick Sheeter437bbad2013-11-19 14:32:56 -080065// Based on section 6.1.1 of MicroType Express draft spec
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090066bool Read255UShort(Buffer* buf, unsigned int* value) {
Roderick Sheeter437bbad2013-11-19 14:32:56 -080067 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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090073 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -080074 }
75 if (code == kWordCode) {
76 uint16_t result = 0;
77 if (!buf->ReadU16(&result)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090078 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -080079 }
80 *value = result;
81 return true;
82 } else if (code == kOneMoreByteCode1) {
83 uint8_t result = 0;
84 if (!buf->ReadU8(&result)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090085 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -080086 }
87 *value = result + kLowestUCode;
88 return true;
89 } else if (code == kOneMoreByteCode2) {
90 uint8_t result = 0;
91 if (!buf->ReadU8(&result)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +090092 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -080093 }
94 *value = result + kLowestUCode * 2;
95 return true;
96 } else {
97 *value = code;
98 return true;
99 }
100}
101
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900102bool ReadBase128(Buffer* buf, uint32_t* value) {
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800103 uint32_t result = 0;
104 for (size_t i = 0; i < 5; ++i) {
105 uint8_t code = 0;
106 if (!buf->ReadU8(&code)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900107 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800108 }
109 // If any of the top seven bits are set then we're about to overflow.
110 if (result & 0xe0000000) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900111 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800112 }
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
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900120 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800121}
122
123int WithSign(int flag, int baseval) {
124 // Precondition: 0 <= baseval < 65536 (to avoid integer overflow)
125 return (flag & 1) ? baseval : -baseval;
126}
127
128bool 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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900135 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800136 }
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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900155 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800156 }
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.
199bool 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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900241 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800242 }
243 dst[flag_offset++] = repeat_count;
244 }
245 if (flag_offset >= dst_size) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900246 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800247 }
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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900258 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800259 }
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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900266 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800267 }
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.
300void 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).
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900323bool ProcessBboxStream(Buffer* bbox_stream, unsigned int n_glyphs,
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800324 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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900328 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800329 }
330 // Safe because n_glyphs is bounded
331 unsigned int bitmap_length = ((n_glyphs + 31) >> 5) << 2;
332 if (!bbox_stream->Skip(bitmap_length)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900333 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800334 }
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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900339 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800340 }
341 if (glyf_buf_length < 2 + 10 ||
342 loca_offset > glyf_buf_length - 2 - 10) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900343 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800344 }
345 if (!bbox_stream->Read(glyf_buf + loca_offset + 2, 8)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900346 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800347 }
348 }
349 }
350 return true;
351}
352
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900353bool ProcessComposite(Buffer* composite_stream, uint8_t* dst,
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800354 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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900361 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800362 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900378 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800379 }
380 }
381 size_t composite_glyph_size = composite_stream->offset() - start_offset;
382 if (composite_glyph_size + kCompositeGlyphBegin > dst_size) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900383 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800384 }
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
395bool 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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900400 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800401 }
402 if (offset_size * loca_size > dst_size) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900403 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800404 }
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
418bool 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;
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900422 Buffer file(data, data_size);
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800423 uint32_t version;
424 std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
425
426 if (!file.ReadU32(&version)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900427 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800428 }
429 uint16_t num_glyphs;
430 uint16_t index_format;
431 if (!file.ReadU16(&num_glyphs) ||
432 !file.ReadU16(&index_format)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900433 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800434 }
435 unsigned int offset = (2 + kNumSubStreams) * 4;
436 if (offset > data_size) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900437 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800438 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900443 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800444 }
445 if (substream_size > data_size - offset) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900446 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800447 }
448 substreams[i] = std::make_pair(data + offset, substream_size);
449 offset += substream_size;
450 }
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900451 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);
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800458
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900467 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800468 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900477 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800478 }
479 if (have_instructions) {
480 if (!Read255UShort(&glyph_stream, &instruction_size)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900481 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800482 }
483 if (instruction_size + 2 > glyf_dst_size - glyph_size) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900484 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800485 }
486 Store16(glyf_dst, glyph_size, instruction_size);
487 if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
488 instruction_size)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900489 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800490 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900501 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800502 }
503 n_points_vec.push_back(n_points_contour);
504 if (total_n_points + n_points_contour < total_n_points) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900505 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800506 }
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()) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900511 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800512 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900520 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800521 }
522 const uint32_t header_and_endpts_contours_size =
523 kEndPtsOfContoursOffset + 2 * n_contours;
524 if (glyf_dst_size < header_and_endpts_contours_size) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900525 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800526 }
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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900534 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800535 }
536 offset = Store16(glyf_dst, offset, end_point);
537 }
538 if (!flag_stream.Skip(flag_size)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900539 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800540 }
541 if (!glyph_stream.Skip(triplet_bytes_consumed)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900542 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800543 }
544 unsigned int instruction_size;
545 if (!Read255UShort(&glyph_stream, &instruction_size)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900546 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800547 }
548 if (glyf_dst_size - header_and_endpts_contours_size <
549 instruction_size + 2) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900550 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800551 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900555 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800556 }
557 if (!StorePoints(points, n_contours, instruction_size,
558 glyf_dst, glyf_dst_size, &glyph_size)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900559 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800560 }
561 } else {
562 glyph_size = 0;
563 }
564 loca_values[i] = loca_offset;
565 if (glyph_size + 3 < glyph_size) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900566 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800567 }
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.
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900572 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800573 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900579 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800580 }
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.
587const 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
597bool 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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900600 if (tag == kGlyfTableTag) {
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800601 const Table* glyf_table = FindTable(tables, tag);
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900602 const Table* loca_table = FindTable(tables, kLocaTableTag);
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800603 if (glyf_table == NULL || loca_table == NULL) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900604 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800605 }
606 if (static_cast<uint64_t>(glyf_table->dst_offset + glyf_table->dst_length) >
607 dst_length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900608 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800609 }
610 if (static_cast<uint64_t>(loca_table->dst_offset + loca_table->dst_length) >
611 dst_length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900612 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800613 }
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);
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900617 } else if (tag == kLocaTableTag) {
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800618 // processing was already done by glyf table, but validate
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900619 if (!FindTable(tables, kGlyfTableTag)) {
620 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800621 }
622 } else {
623 // transform for the tag is not known
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900624 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800625 }
626 return true;
627}
628
629uint32_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
639bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900640 const Table* head_table = FindTable(tables, kHeadTableTag);
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800641 if (head_table == NULL ||
642 head_table->dst_length < kCheckSumAdjustmentOffset + 4) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900643 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800644 }
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
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800664bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
Roderick Sheeter2ec0cb82014-05-07 11:01:07 -0700665 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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900670 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800671 }
Roderick Sheeter2ec0cb82014-05-07 11:01:07 -0700672 return true;
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800673}
674
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900675bool ReadShortDirectory(Buffer* file, std::vector<Table>* tables,
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800676 size_t num_tables) {
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800677 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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900681 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800682 }
683 uint32_t tag;
David Kuettel47c50162014-04-29 17:47:03 -0700684 if ((flag_byte & 0x3f) == 0x3f) {
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800685 if (!file->ReadU32(&tag)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900686 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800687 }
688 } else {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900689 tag = kKnownTags[flag_byte & 0x3f];
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800690 }
David Kuettel47c50162014-04-29 17:47:03 -0700691 // Bits 6 and 7 are reserved and must be 0.
692 if ((flag_byte & 0xC0) != 0) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900693 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800694 }
Roderick Sheeter2ec0cb82014-05-07 11:01:07 -0700695 uint32_t flags = 0;
Zoltan Szabadka22e2c322014-03-27 16:13:13 +0100696 if (i > 0) {
697 flags |= kWoff2FlagsContinueStream;
698 }
David Kuettel47c50162014-04-29 17:47:03 -0700699 // Always transform the glyf and loca tables
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900700 if (tag == kGlyfTableTag || tag == kLocaTableTag) {
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800701 flags |= kWoff2FlagsTransform;
702 }
703 uint32_t dst_length;
704 if (!ReadBase128(file, &dst_length)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900705 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800706 }
707 uint32_t transform_length = dst_length;
708 if ((flags & kWoff2FlagsTransform) != 0) {
709 if (!ReadBase128(file, &transform_length)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900710 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800711 }
712 }
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800713 table->tag = tag;
714 table->flags = flags;
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800715 table->transform_length = transform_length;
716 table->dst_length = dst_length;
717 }
718 return true;
719}
720
721} // namespace
722
723size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900724 Buffer file(data, length);
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800725 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
734bool ConvertWOFF2ToTTF(uint8_t* result, size_t result_length,
735 const uint8_t* data, size_t length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900736 Buffer file(data, length);
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800737
738 uint32_t signature;
739 uint32_t flavor;
740 if (!file.ReadU32(&signature) || signature != kWoff2Signature ||
741 !file.ReadU32(&flavor)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900742 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800743 }
744
745 // TODO(user): Should call IsValidVersionTag() here.
746
747 uint32_t reported_length;
748 if (!file.ReadU32(&reported_length) || length != reported_length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900749 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800750 }
751 uint16_t num_tables;
752 if (!file.ReadU16(&num_tables) || !num_tables) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900753 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800754 }
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800755 // We don't care about these fields of the header:
Zoltan Szabadka494c85c2014-03-20 14:35:41 +0100756 // uint16_t reserved
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800757 // uint32_t total_sfnt_size
Zoltan Szabadka22e2c322014-03-27 16:13:13 +0100758 if (!file.Skip(6)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900759 return FONT_COMPRESSION_FAILURE();
Zoltan Szabadka22e2c322014-03-27 16:13:13 +0100760 }
761 uint32_t compressed_length;
762 if (!file.ReadU32(&compressed_length)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900763 return FONT_COMPRESSION_FAILURE();
Zoltan Szabadka22e2c322014-03-27 16:13:13 +0100764 }
765 // We don't care about these fields of the header:
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800766 // uint16_t major_version, minor_version
767 // uint32_t meta_offset, meta_length, meta_orig_length
768 // uint32_t priv_offset, priv_length
Zoltan Szabadka22e2c322014-03-27 16:13:13 +0100769 if (!file.Skip(24)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900770 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800771 }
772 std::vector<Table> tables(num_tables);
773 // Note: change below to ReadLongDirectory to enable long format.
774 if (!ReadShortDirectory(&file, &tables, num_tables)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900775 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800776 }
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;
Zoltan Szabadka22e2c322014-03-27 16:13:13 +0100784 table->src_length = (i == 0 ? compressed_length : 0);
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800785 src_offset += table->src_length;
786 if (src_offset > std::numeric_limits<uint32_t>::max()) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900787 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800788 }
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()) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900793 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800794 }
795 dst_offset = Round4(dst_offset);
Roderick Sheeter2ec0cb82014-05-07 11:01:07 -0700796
797 uncompressed_sum += table->src_length;
798 if (uncompressed_sum > std::numeric_limits<uint32_t>::max()) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900799 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800800 }
801 }
802 // Enforce same 30M limit on uncompressed tables as OTS
803 if (uncompressed_sum > 30 * 1024 * 1024) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900804 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800805 }
806 if (src_offset > length || dst_offset > result_length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900807 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800808 }
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) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900812 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800813 }
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;
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800841 size_t transform_length = table->transform_length;
842 if ((flags & kWoff2FlagsContinueStream) != 0) {
843 if (!continue_valid) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900844 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800845 }
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800846 } 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()) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900854 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800855 }
856 }
857 uncompressed_buf.resize(total_size);
858 if (!Woff2Uncompress(&uncompressed_buf[0], total_size,
Roderick Sheeter2ec0cb82014-05-07 11:01:07 -0700859 src_buf, compressed_length)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900860 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800861 }
862 transform_buf = &uncompressed_buf[0];
863 continue_valid = true;
864 } else {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900865 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800866 }
867
868 if ((flags & kWoff2FlagsTransform) == 0) {
869 if (transform_length != table->dst_length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900870 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800871 }
872 if (static_cast<uint64_t>(table->dst_offset + transform_length) >
873 result_length) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900874 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800875 }
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)) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900881 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800882 }
883 }
884 if (continue_valid) {
885 transform_buf += transform_length;
Kenichi Ishibashic75ed762014-06-04 08:29:53 +0900886 if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
Kenichi Ishibashi142d8882014-05-30 09:06:32 +0900887 return FONT_COMPRESSION_FAILURE();
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800888 }
889 }
890 }
891
892 return FixChecksums(tables, result);
893}
894
Roderick Sheeter437bbad2013-11-19 14:32:56 -0800895} // namespace woff2