Use NeverDestroyed instead of DEPRECATED_DEFINE_STATIC_LOCAL
[WebKit-https.git] / Source / WebCore / platform / graphics / WOFFFileFormat.cpp
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 namespace WebCore {
34
35 static bool readUInt32(SharedBuffer* buffer, size_t& offset, uint32_t& value)
36 {
37     ASSERT_ARG(offset, offset <= buffer->size());
38     if (buffer->size() - offset < sizeof(value))
39         return false;
40
41     value = ntohl(*reinterpret_cast_ptr<const uint32_t*>(buffer->data() + offset));
42     offset += sizeof(value);
43
44     return true;
45 }
46
47 static bool readUInt16(SharedBuffer* buffer, size_t& offset, uint16_t& value)
48 {
49     ASSERT_ARG(offset, offset <= buffer->size());
50     if (buffer->size() - offset < sizeof(value))
51         return false;
52
53     value = ntohs(*reinterpret_cast_ptr<const uint16_t*>(buffer->data() + offset));
54     offset += sizeof(value);
55
56     return true;
57 }
58
59 static bool writeUInt32(Vector<char>& vector, uint32_t value)
60 {
61     uint32_t bigEndianValue = htonl(value);
62     return vector.tryAppend(reinterpret_cast_ptr<char*>(&bigEndianValue), sizeof(bigEndianValue));
63 }
64
65 static bool writeUInt16(Vector<char>& vector, uint16_t value)
66 {
67     uint16_t bigEndianValue = htons(value);
68     return vector.tryAppend(reinterpret_cast_ptr<char*>(&bigEndianValue), sizeof(bigEndianValue));
69 }
70
71 static const uint32_t woffSignature = 0x774f4646; /* 'wOFF' */
72
73 bool isWOFF(SharedBuffer* buffer)
74 {
75     size_t offset = 0;
76     uint32_t signature;
77
78     return readUInt32(buffer, offset, signature) && signature == woffSignature;
79 }
80
81 bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt)
82 {
83     ASSERT_ARG(sfnt, sfnt.isEmpty());
84
85     size_t offset = 0;
86
87     // Read the WOFF header.
88     uint32_t signature;
89     if (!readUInt32(woff, offset, signature) || signature != woffSignature) {
90         ASSERT_NOT_REACHED();
91         return false;
92     }
93
94     uint32_t flavor;
95     if (!readUInt32(woff, offset, flavor))
96         return false;
97
98     uint32_t length;
99     if (!readUInt32(woff, offset, length) || length != woff->size())
100         return false;
101
102     uint16_t numTables;
103     if (!readUInt16(woff, offset, numTables))
104         return false;
105
106     if (!numTables || numTables > 0x0fff)
107         return false;
108
109     uint16_t reserved;
110     if (!readUInt16(woff, offset, reserved) || reserved)
111         return false;
112
113     uint32_t totalSfntSize;
114     if (!readUInt32(woff, offset, totalSfntSize))
115         return false;
116
117     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))
118         return false;
119
120     offset += sizeof(uint16_t); // majorVersion
121     offset += sizeof(uint16_t); // minorVersion
122     offset += sizeof(uint32_t); // metaOffset
123     offset += sizeof(uint32_t); // metaLength
124     offset += sizeof(uint32_t); // metaOrigLength
125     offset += sizeof(uint32_t); // privOffset
126     offset += sizeof(uint32_t); // privLength
127
128     // Check if the WOFF can supply as many tables as it claims it has.
129     if (woff->size() - offset < numTables * 5 * sizeof(uint32_t))
130         return false;
131
132     // Write the sfnt offset subtable.
133     uint16_t entrySelector = 0;
134     uint16_t searchRange = 1;
135     while (searchRange < numTables >> 1) {
136         entrySelector++;
137         searchRange <<= 1;
138     }
139     searchRange <<= 4;
140     uint16_t rangeShift = (numTables << 4) - searchRange;
141
142     if (!writeUInt32(sfnt, flavor)
143         || !writeUInt16(sfnt, numTables)
144         || !writeUInt16(sfnt, searchRange)
145         || !writeUInt16(sfnt, entrySelector)
146         || !writeUInt16(sfnt, rangeShift))
147         return false;
148
149     if (sfnt.size() > totalSfntSize)
150         return false;
151
152     if (totalSfntSize - sfnt.size() < numTables * 4 * sizeof(uint32_t))
153         return false;
154
155     size_t sfntTableDirectoryCursor = sfnt.size();
156     sfnt.grow(sfnt.size() + numTables * 4 * sizeof(uint32_t));
157
158     // Process tables.
159     for (uint16_t i = 0; i < numTables; ++i) {
160         // Read a WOFF table directory entry.
161         uint32_t tableTag;
162         if (!readUInt32(woff, offset, tableTag))
163             return false;
164
165         uint32_t tableOffset;
166         if (!readUInt32(woff, offset, tableOffset))
167             return false;
168
169         uint32_t tableCompLength;
170         if (!readUInt32(woff, offset, tableCompLength))
171             return false;
172
173         if (tableOffset > woff->size() || tableCompLength > woff->size() - tableOffset)
174             return false;
175
176         uint32_t tableOrigLength;
177         if (!readUInt32(woff, offset, tableOrigLength) || tableCompLength > tableOrigLength)
178             return false;
179
180         if (tableOrigLength > totalSfntSize || sfnt.size() > totalSfntSize - tableOrigLength)
181             return false;
182
183         uint32_t tableOrigChecksum;
184         if (!readUInt32(woff, offset, tableOrigChecksum))
185             return false;
186
187         // Write an sfnt table directory entry.
188         uint32_t* sfntTableDirectoryPtr = reinterpret_cast_ptr<uint32_t*>(sfnt.data() + sfntTableDirectoryCursor);
189         *sfntTableDirectoryPtr++ = htonl(tableTag);
190         *sfntTableDirectoryPtr++ = htonl(tableOrigChecksum);
191         *sfntTableDirectoryPtr++ = htonl(sfnt.size());
192         *sfntTableDirectoryPtr++ = htonl(tableOrigLength);
193         sfntTableDirectoryCursor += 4 * sizeof(uint32_t);
194
195         if (tableCompLength == tableOrigLength) {
196             // The table is not compressed.
197             if (!sfnt.tryAppend(woff->data() + tableOffset, tableCompLength))
198                 return false;
199         } else {
200             uLongf destLen = tableOrigLength;
201             if (!sfnt.tryReserveCapacity(sfnt.size() + tableOrigLength))
202                 return false;
203             Bytef* dest = reinterpret_cast<Bytef*>(sfnt.end());
204             sfnt.grow(sfnt.size() + tableOrigLength);
205             if (uncompress(dest, &destLen, reinterpret_cast<const Bytef*>(woff->data() + tableOffset), tableCompLength) != Z_OK)
206                 return false;
207             if (destLen != tableOrigLength)
208                 return false;
209         }
210
211         // Pad to a multiple of 4 bytes.
212         while (sfnt.size() % 4)
213             sfnt.append(0);
214     }
215
216     return sfnt.size() == totalSfntSize;
217 }
218     
219 } // namespace WebCore