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