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