1 /* 2 * Copyright 2011 Google Inc. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "sfntly/data/readable_font_data.h" 18 19 #include <stdio.h> 20 21 #include <limits> 22 23 #include "sfntly/data/memory_byte_array.h" 24 #include "sfntly/data/writable_font_data.h" 25 #include "sfntly/port/exception_type.h" 26 27 namespace sfntly { 28 29 ReadableFontData::ReadableFontData(ByteArray* array) 30 : FontData(array), 31 checksum_set_(false), 32 checksum_(0) { 33 } 34 35 ReadableFontData::~ReadableFontData() {} 36 37 // TODO(arthurhsu): re-investigate the memory model of this function. It's 38 // not too useful without copying, but it's not performance 39 // savvy to do copying. 40 CALLER_ATTACH 41 ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) { 42 assert(b); 43 ByteArrayPtr ba = new MemoryByteArray(b->size()); 44 ba->Put(0, b); 45 ReadableFontDataPtr wfd = new ReadableFontData(ba); 46 return wfd.Detach(); 47 } 48 49 int64_t ReadableFontData::Checksum() { 50 AutoLock lock(checksum_lock_); 51 if (!checksum_set_) { 52 ComputeChecksum(); 53 } 54 return checksum_; 55 } 56 57 void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) { 58 checksum_range_ = ranges; 59 checksum_set_ = false; // UNIMPLEMENTED: atomicity 60 } 61 62 int32_t ReadableFontData::ReadUByte(int32_t index) { 63 int32_t b = array_->Get(BoundOffset(index)); 64 if (b < 0) { 65 #if !defined (SFNTLY_NO_EXCEPTION) 66 throw IndexOutOfBoundException( 67 "Index attempted to be read from is out of bounds", index); 68 #endif 69 return kInvalidUnsigned; 70 } 71 return b; 72 } 73 74 int32_t ReadableFontData::ReadByte(int32_t index) { 75 int32_t b = array_->Get(BoundOffset(index)); 76 if (b < 0) { 77 #if !defined (SFNTLY_NO_EXCEPTION) 78 throw IndexOutOfBoundException( 79 "Index attempted to be read from is out of bounds", index); 80 #endif 81 return kInvalidByte; 82 } 83 return (b << 24) >> 24; 84 } 85 86 int32_t ReadableFontData::ReadBytes(int32_t index, 87 byte_t* b, 88 int32_t offset, 89 int32_t length) { 90 return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length)); 91 } 92 93 int32_t ReadableFontData::ReadChar(int32_t index) { 94 return ReadUByte(index); 95 } 96 97 int32_t ReadableFontData::ReadUShort(int32_t index) { 98 int32_t b1 = ReadUByte(index); 99 if (b1 < 0) 100 return kInvalidUnsigned; 101 int32_t b2 = ReadUByte(index + 1); 102 if (b2 < 0) 103 return kInvalidUnsigned; 104 return 0xffff & (b1 << 8 | b2); 105 } 106 107 int32_t ReadableFontData::ReadShort(int32_t index) { 108 int32_t b1 = ReadByte(index); 109 if (b1 == kInvalidByte) 110 return kInvalidShort; 111 int32_t b2 = ReadUByte(index + 1); 112 if (b2 < 0) 113 return kInvalidShort; 114 115 uint32_t result = static_cast<uint32_t>(b1) << 8 | b2; 116 return static_cast<int32_t>(result << 16) >> 16; 117 } 118 119 int32_t ReadableFontData::ReadUInt24(int32_t index) { 120 int32_t b1 = ReadUByte(index); 121 if (b1 < 0) 122 return kInvalidUnsigned; 123 int32_t b2 = ReadUByte(index + 1); 124 if (b2 < 0) 125 return kInvalidUnsigned; 126 int32_t b3 = ReadUByte(index + 2); 127 if (b3 < 0) 128 return kInvalidUnsigned; 129 return 0xffffff & (b1 << 16 | b2 << 8 | b3); 130 } 131 132 int64_t ReadableFontData::ReadULong(int32_t index) { 133 int32_t b1 = ReadUByte(index); 134 if (b1 < 0) 135 return kInvalidUnsigned; 136 int32_t b2 = ReadUByte(index + 1); 137 if (b2 < 0) 138 return kInvalidUnsigned; 139 int32_t b3 = ReadUByte(index + 2); 140 if (b3 < 0) 141 return kInvalidUnsigned; 142 int32_t b4 = ReadUByte(index + 3); 143 if (b4 < 0) 144 return kInvalidUnsigned; 145 return 0xffffffffL & (b1 << 24 | b2 << 16 | b3 << 8 | b4); 146 } 147 148 int32_t ReadableFontData::ReadULongAsInt(int32_t index) { 149 int64_t ulong = ReadULong(index); 150 #if !defined (SFNTLY_NO_EXCEPTION) 151 if ((ulong & 0x80000000) == 0x80000000) { 152 throw ArithmeticException("Long value too large to fit into an integer."); 153 } 154 #endif 155 return static_cast<int32_t>(ulong); 156 } 157 158 int64_t ReadableFontData::ReadULongLE(int32_t index) { 159 int32_t b1 = ReadUByte(index); 160 if (b1 < 0) 161 return kInvalidUnsigned; 162 int32_t b2 = ReadUByte(index + 1); 163 if (b2 < 0) 164 return kInvalidUnsigned; 165 int32_t b3 = ReadUByte(index + 2); 166 if (b3 < 0) 167 return kInvalidUnsigned; 168 int32_t b4 = ReadUByte(index + 3); 169 if (b4 < 0) 170 return kInvalidUnsigned; 171 return 0xffffffffL & (b1 | b2 << 8 | b3 << 16 | b4 << 24); 172 } 173 174 int32_t ReadableFontData::ReadLong(int32_t index) { 175 int32_t b1 = ReadByte(index); 176 if (b1 == kInvalidByte) 177 return kInvalidLong; 178 int32_t b2 = ReadUByte(index + 1); 179 if (b2 < 0) 180 return kInvalidLong; 181 int32_t b3 = ReadUByte(index + 2); 182 if (b3 < 0) 183 return kInvalidLong; 184 int32_t b4 = ReadUByte(index + 3); 185 if (b4 < 0) 186 return kInvalidLong; 187 return static_cast<uint32_t>(b1) << 24 | b2 << 16 | b3 << 8 | b4; 188 } 189 190 int32_t ReadableFontData::ReadFixed(int32_t index) { 191 return ReadLong(index); 192 } 193 194 int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) { 195 int32_t high = ReadULong(index); 196 if (high == kInvalidUnsigned) 197 return kInvalidLongDateTime; 198 int32_t low = ReadULong(index + 4); 199 if (low == kInvalidUnsigned) 200 return kInvalidLongDateTime; 201 return (int64_t)high << 32 | low; 202 } 203 204 int32_t ReadableFontData::ReadFWord(int32_t index) { 205 return ReadShort(index); 206 } 207 208 int32_t ReadableFontData::ReadFUFWord(int32_t index) { 209 return ReadUShort(index); 210 } 211 212 int32_t ReadableFontData::CopyTo(OutputStream* os) { 213 return array_->CopyTo(os, BoundOffset(0), Length()); 214 } 215 216 int32_t ReadableFontData::CopyTo(WritableFontData* wfd) { 217 return array_->CopyTo(wfd->BoundOffset(0), 218 wfd->array_, 219 BoundOffset(0), 220 Length()); 221 } 222 223 int32_t ReadableFontData::CopyTo(ByteArray* ba) { 224 return array_->CopyTo(ba, BoundOffset(0), Length()); 225 } 226 227 int32_t ReadableFontData::SearchUShort(int32_t start_index, 228 int32_t start_offset, 229 int32_t end_index, 230 int32_t end_offset, 231 int32_t length, 232 int32_t key) { 233 int32_t location = 0; 234 int32_t bottom = 0; 235 int32_t top = length; 236 while (top != bottom) { 237 location = (top + bottom) / 2; 238 int32_t location_start = ReadUShort(start_index + location * start_offset); 239 if (key < location_start) { 240 // location is below current location 241 top = location; 242 } else { 243 // is key below the upper bound? 244 int32_t location_end = ReadUShort(end_index + location * end_offset); 245 #if defined (SFNTLY_DEBUG_FONTDATA) 246 fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); 247 #endif 248 if (key <= location_end) 249 return location; 250 251 // location is above the current location 252 bottom = location + 1; 253 } 254 } 255 return -1; 256 } 257 258 int32_t ReadableFontData::SearchUShort(int32_t start_index, 259 int32_t start_offset, 260 int32_t length, 261 int32_t key) { 262 int32_t location = 0; 263 int32_t bottom = 0; 264 int32_t top = length; 265 while (top != bottom) { 266 location = (top + bottom) / 2; 267 int32_t location_start = ReadUShort(start_index + location * start_offset); 268 if (key == location_start) 269 return location; 270 271 if (key < location_start) { 272 // location is below current location 273 top = location; 274 } else { 275 // location is above current location 276 bottom = location + 1; 277 } 278 } 279 return -1; 280 } 281 282 int32_t ReadableFontData::SearchULong(int32_t start_index, 283 int32_t start_offset, 284 int32_t end_index, 285 int32_t end_offset, 286 int32_t length, 287 int32_t key) { 288 int32_t location = 0; 289 int32_t bottom = 0; 290 int32_t top = length; 291 while (top != bottom) { 292 location = (top + bottom) / 2; 293 int32_t location_start = ReadULongAsInt(start_index 294 + location * start_offset); 295 if (key < location_start) { 296 // location is below current location 297 top = location; 298 } else { 299 // is key below the upper bound? 300 int32_t location_end = ReadULongAsInt(end_index + location * end_offset); 301 #if defined (SFNTLY_DEBUG_FONTDATA) 302 fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); 303 #endif 304 if (key <= location_end) 305 return location; 306 307 // location is above the current location 308 bottom = location + 1; 309 } 310 } 311 return -1; 312 } 313 314 CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset, 315 int32_t length) { 316 if (offset < 0 || length < 0 || 317 offset > std::numeric_limits<int32_t>::max() - length || 318 offset + length > Size()) { 319 #if !defined (SFNTLY_NO_EXCEPTION) 320 throw IndexOutOfBoundsException( 321 "Attempt to bind data outside of its limits"); 322 #endif 323 return NULL; 324 } 325 FontDataPtr slice = new ReadableFontData(this, offset, length); 326 return slice.Detach(); 327 } 328 329 CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) { 330 if (offset < 0 || offset > Size()) { 331 #if !defined (SFNTLY_NO_EXCEPTION) 332 throw IndexOutOfBoundsException( 333 "Attempt to bind data outside of its limits"); 334 #endif 335 return NULL; 336 } 337 FontDataPtr slice = new ReadableFontData(this, offset); 338 return slice.Detach(); 339 } 340 341 ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset) 342 : FontData(data, offset), 343 checksum_set_(false), 344 checksum_(0) { 345 } 346 347 ReadableFontData::ReadableFontData(ReadableFontData* data, 348 int32_t offset, 349 int32_t length) 350 : FontData(data, offset, length), 351 checksum_set_(false), 352 checksum_(0) { 353 } 354 355 void ReadableFontData::ComputeChecksum() { 356 // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity 357 int64_t sum = 0; 358 if (checksum_range_.empty()) { 359 sum = ComputeCheckSum(0, Length()); 360 } else { 361 for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size(); 362 low_bound_index += 2) { 363 int32_t low_bound = checksum_range_[low_bound_index]; 364 int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ? 365 Length() : 366 checksum_range_[low_bound_index + 1]; 367 sum += ComputeCheckSum(low_bound, high_bound); 368 } 369 } 370 371 checksum_ = sum & 0xffffffffL; 372 checksum_set_ = true; 373 } 374 375 int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound, 376 int32_t high_bound) { 377 int64_t sum = 0; 378 // Checksum all whole 4-byte chunks. 379 for (int32_t i = low_bound; i <= high_bound - 4; i += 4) { 380 sum += ReadULong(i); 381 } 382 383 // Add last fragment if not 4-byte multiple 384 int32_t off = high_bound & -4; 385 if (off < high_bound) { 386 int32_t b3 = ReadUByte(off); 387 int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0; 388 int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0; 389 int32_t b0 = 0; 390 sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; 391 } 392 return sum; 393 } 394 395 } // namespace sfntly 396