Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/modules/woff2/./../../../modules/woff2/src/woff2_dec.cc
Warning:line 325, column 3
Value stored to 'offset' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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