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