1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WOFFFileFormat.h"
28#include <zlib.h>
29
30#include "SharedBuffer.h"
31#include <wtf/ByteOrder.h>
32
33#if USE(WOFF2)
34#include <woff2/decode.h>
35static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2"
36#endif
37
38namespace WebCore {
39
40static bool readUInt32(SharedBuffer& buffer, size_t& offset, uint32_t& value)
41{
42 ASSERT_ARG(offset, offset <= buffer.size());
43 if (buffer.size() - offset < sizeof(value))
44 return false;
45
46 value = ntohl(*reinterpret_cast_ptr<const uint32_t*>(buffer.data() + offset));
47 offset += sizeof(value);
48
49 return true;
50}
51
52static bool readUInt16(SharedBuffer& buffer, size_t& offset, uint16_t& value)
53{
54 ASSERT_ARG(offset, offset <= buffer.size());
55 if (buffer.size() - offset < sizeof(value))
56 return false;
57
58 value = ntohs(*reinterpret_cast_ptr<const uint16_t*>(buffer.data() + offset));
59 offset += sizeof(value);
60
61 return true;
62}
63
64static bool writeUInt32(Vector<char>& vector, uint32_t value)
65{
66 uint32_t bigEndianValue = htonl(value);
67 return vector.tryAppend(reinterpret_cast_ptr<char*>(&bigEndianValue), sizeof(bigEndianValue));
68}
69
70static bool writeUInt16(Vector<char>& vector, uint16_t value)
71{
72 uint16_t bigEndianValue = htons(value);
73 return vector.tryAppend(reinterpret_cast_ptr<char*>(&bigEndianValue), sizeof(bigEndianValue));
74}
75
76static const uint32_t woffSignature = 0x774f4646; /* 'wOFF' */
77
78bool isWOFF(SharedBuffer& buffer)
79{
80 size_t offset = 0;
81 uint32_t signature;
82
83 if (!readUInt32(buffer, offset, signature))
84 return false;
85
86#if USE(WOFF2)
87 return signature == woffSignature || signature == kWoff2Signature;
88#else
89 return signature == woffSignature;
90#endif
91}
92
93#if USE(WOFF2)
94class WOFF2VectorOut : public woff2::WOFF2Out {
95public:
96 WOFF2VectorOut(Vector<char>& vector)
97 : m_vector(vector)
98 { }
99
100 bool Write(const void* data, size_t n) override
101 {
102 if (!m_vector.tryReserveCapacity(m_vector.size() + n))
103 return false;
104 m_vector.append(static_cast<const char*>(data), n);
105 return true;
106 }
107
108 bool Write(const void* data, size_t offset, size_t n) override
109 {
110 if (!m_vector.tryReserveCapacity(offset + n))
111 return false;
112 if (offset + n > m_vector.size())
113 m_vector.grow(offset + n);
114 m_vector.remove(offset, n);
115 m_vector.insert(offset, static_cast<const char*>(data), n);
116 return true;
117 }
118
119 size_t Size() override
120 {
121 return m_vector.size();
122 }
123
124private:
125 Vector<char>& m_vector;
126};
127#endif
128
129bool convertWOFFToSfnt(SharedBuffer& woff, Vector<char>& sfnt)
130{
131 ASSERT_ARG(sfnt, sfnt.isEmpty());
132
133 size_t offset = 0;
134
135 // Read the WOFF header.
136 uint32_t signature;
137 if (!readUInt32(woff, offset, signature)) {
138 ASSERT_NOT_REACHED();
139 return false;
140 }
141
142#if USE(WOFF2)
143 if (signature == kWoff2Signature) {
144 const uint8_t* woffData = reinterpret_cast_ptr<const uint8_t*>(woff.data());
145 const size_t woffSize = woff.size();
146 const size_t sfntSize = woff2::ComputeWOFF2FinalSize(woffData, woffSize);
147
148 if (!sfnt.tryReserveCapacity(sfntSize))
149 return false;
150
151 WOFF2VectorOut out(sfnt);
152 return woff2::ConvertWOFF2ToTTF(woffData, woffSize, &out);
153 }
154#endif
155
156 if (signature != woffSignature) {
157 ASSERT_NOT_REACHED();
158 return false;
159 }
160
161 uint32_t flavor;
162 if (!readUInt32(woff, offset, flavor))
163 return false;
164
165 uint32_t length;
166 if (!readUInt32(woff, offset, length) || length != woff.size())
167 return false;
168
169 uint16_t numTables;
170 if (!readUInt16(woff, offset, numTables))
171 return false;
172
173 if (!numTables || numTables > 0x0fff)
174 return false;
175
176 uint16_t reserved;
177 if (!readUInt16(woff, offset, reserved) || reserved)
178 return false;
179
180 uint32_t totalSfntSize;
181 if (!readUInt32(woff, offset, totalSfntSize))
182 return false;
183
184 if (woff.size() - offset < sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t))
185 return false;
186
187 offset += sizeof(uint16_t); // majorVersion
188 offset += sizeof(uint16_t); // minorVersion
189 offset += sizeof(uint32_t); // metaOffset
190 offset += sizeof(uint32_t); // metaLength
191 offset += sizeof(uint32_t); // metaOrigLength
192 offset += sizeof(uint32_t); // privOffset
193 offset += sizeof(uint32_t); // privLength
194
195 // Check if the WOFF can supply as many tables as it claims it has.
196 if (woff.size() - offset < numTables * 5 * sizeof(uint32_t))
197 return false;
198
199 // Write the sfnt offset subtable.
200 uint16_t entrySelector = 0;
201 uint16_t searchRange = 1;
202 while (searchRange < numTables >> 1) {
203 entrySelector++;
204 searchRange <<= 1;
205 }
206 searchRange <<= 4;
207 uint16_t rangeShift = (numTables << 4) - searchRange;
208
209 if (!writeUInt32(sfnt, flavor)
210 || !writeUInt16(sfnt, numTables)
211 || !writeUInt16(sfnt, searchRange)
212 || !writeUInt16(sfnt, entrySelector)
213 || !writeUInt16(sfnt, rangeShift))
214 return false;
215
216 if (sfnt.size() > totalSfntSize)
217 return false;
218
219 if (totalSfntSize - sfnt.size() < numTables * 4 * sizeof(uint32_t))
220 return false;
221
222 size_t sfntTableDirectoryCursor = sfnt.size();
223 sfnt.grow(sfnt.size() + numTables * 4 * sizeof(uint32_t));
224
225 // Process tables.
226 for (uint16_t i = 0; i < numTables; ++i) {
227 // Read a WOFF table directory entry.
228 uint32_t tableTag;
229 if (!readUInt32(woff, offset, tableTag))
230 return false;
231
232 uint32_t tableOffset;
233 if (!readUInt32(woff, offset, tableOffset))
234 return false;
235
236 uint32_t tableCompLength;
237 if (!readUInt32(woff, offset, tableCompLength))
238 return false;
239
240 if (tableOffset > woff.size() || tableCompLength > woff.size() - tableOffset)
241 return false;
242
243 uint32_t tableOrigLength;
244 if (!readUInt32(woff, offset, tableOrigLength) || tableCompLength > tableOrigLength)
245 return false;
246
247 if (tableOrigLength > totalSfntSize || sfnt.size() > totalSfntSize - tableOrigLength)
248 return false;
249
250 uint32_t tableOrigChecksum;
251 if (!readUInt32(woff, offset, tableOrigChecksum))
252 return false;
253
254 // Write an sfnt table directory entry.
255 uint32_t* sfntTableDirectoryPtr = reinterpret_cast_ptr<uint32_t*>(sfnt.data() + sfntTableDirectoryCursor);
256 *sfntTableDirectoryPtr++ = htonl(tableTag);
257 *sfntTableDirectoryPtr++ = htonl(tableOrigChecksum);
258 *sfntTableDirectoryPtr++ = htonl(sfnt.size());
259 *sfntTableDirectoryPtr++ = htonl(tableOrigLength);
260 sfntTableDirectoryCursor += 4 * sizeof(uint32_t);
261
262 if (tableCompLength == tableOrigLength) {
263 // The table is not compressed.
264 if (!sfnt.tryAppend(woff.data() + tableOffset, tableCompLength))
265 return false;
266 } else {
267 uLongf destLen = tableOrigLength;
268 if (!sfnt.tryReserveCapacity(sfnt.size() + tableOrigLength))
269 return false;
270 Bytef* dest = reinterpret_cast<Bytef*>(sfnt.end());
271 sfnt.grow(sfnt.size() + tableOrigLength);
272 if (uncompress(dest, &destLen, reinterpret_cast<const Bytef*>(woff.data() + tableOffset), tableCompLength) != Z_OK)
273 return false;
274 if (destLen != tableOrigLength)
275 return false;
276 }
277
278 // Pad to a multiple of 4 bytes.
279 while (sfnt.size() % 4)
280 sfnt.append(0);
281 }
282
283 return sfnt.size() == totalSfntSize;
284}
285
286} // namespace WebCore
287