readable_font_data.cc revision 529b91d37af56176354f05229a86bfa87ff1fb00
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 !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 71int32_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 82int32_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 89int32_t ReadableFontData::ReadChar(int32_t index) { 90 return ReadUByte(index); 91} 92 93int32_t ReadableFontData::ReadUShort(int32_t index) { 94 return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1)); 95} 96 97int32_t ReadableFontData::ReadShort(int32_t index) { 98 return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16; 99} 100 101int32_t ReadableFontData::ReadUInt24(int32_t index) { 102 return 0xffffff & (ReadUByte(index) << 16 | 103 ReadUByte(index + 1) << 8 | 104 ReadUByte(index + 2)); 105} 106 107int64_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 114int32_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 124int32_t ReadableFontData::ReadLong(int32_t index) { 125 return ReadByte(index) << 24 | 126 ReadUByte(index + 1) << 16 | 127 ReadUByte(index + 2) << 8 | 128 ReadUByte(index + 3); 129} 130 131int32_t ReadableFontData::ReadFixed(int32_t index) { 132 return ReadLong(index); 133} 134 135int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) { 136 return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4); 137} 138 139int32_t ReadableFontData::ReadFWord(int32_t index) { 140 return ReadShort(index); 141} 142 143int32_t ReadableFontData::ReadFUFWord(int32_t index) { 144 return ReadUShort(index); 145} 146 147int32_t ReadableFontData::CopyTo(OutputStream* os) { 148 return array_->CopyTo(os, BoundOffset(0), Length()); 149} 150 151int32_t ReadableFontData::CopyTo(WritableFontData* wfd) { 152 return array_->CopyTo(wfd->BoundOffset(0), 153 wfd->array_, 154 BoundOffset(0), 155 Length()); 156} 157 158int32_t ReadableFontData::CopyTo(ByteArray* ba) { 159 return array_->CopyTo(ba, BoundOffset(0), Length()); 160} 161 162int32_t ReadableFontData::SearchUShort(int32_t start_index, 163 int32_t start_offset, 164 int32_t end_index, 165 int32_t end_offset, 166 int32_t length, 167 int32_t key) { 168 int32_t location = 0; 169 int32_t bottom = 0; 170 int32_t top = length; 171 while (top != bottom) { 172 location = (top + bottom) / 2; 173 int32_t location_start = ReadUShort(start_index + location * start_offset); 174 if (key < location_start) { 175 // location is below current location 176 top = location; 177 } else { 178 // is key below the upper bound? 179 int32_t location_end = ReadUShort(end_index + location * end_offset); 180#if defined (SFNTLY_DEBUG_FONTDATA) 181 fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); 182#endif 183 if (key <= location_end) { 184 return location; 185 } else { 186 // location is above the current location 187 bottom = location + 1; 188 } 189 } 190 } 191 return -1; 192} 193 194int32_t ReadableFontData::SearchUShort(int32_t start_index, 195 int32_t start_offset, 196 int32_t length, 197 int32_t key) { 198 int32_t location = 0; 199 int32_t bottom = 0; 200 int32_t top = length; 201 while (top != bottom) { 202 location = (top + bottom) / 2; 203 int32_t location_start = ReadUShort(start_index + location * start_offset); 204 if (key < location_start) { 205 // location is below current location 206 top = location; 207 } else if (key > location_start) { 208 // location is above current location 209 bottom = location + 1; 210 } else { 211 return location; 212 } 213 } 214 return -1; 215} 216 217int32_t ReadableFontData::SearchULong(int32_t start_index, 218 int32_t start_offset, 219 int32_t end_index, 220 int32_t end_offset, 221 int32_t length, 222 int32_t key) { 223 int32_t location = 0; 224 int32_t bottom = 0; 225 int32_t top = length; 226 while (top != bottom) { 227 location = (top + bottom) / 2; 228 int32_t location_start = ReadULongAsInt(start_index 229 + location * start_offset); 230 if (key < location_start) { 231 // location is below current location 232 top = location; 233 } else { 234 // is key below the upper bound? 235 int32_t location_end = ReadULongAsInt(end_index + location * end_offset); 236#if defined (SFNTLY_DEBUG_FONTDATA) 237 fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end); 238#endif 239 if (key <= location_end) { 240 return location; 241 } else { 242 // location is above the current location 243 bottom = location + 1; 244 } 245 } 246 } 247 return -1; 248} 249 250CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset, 251 int32_t length) { 252 if (offset < 0 || offset + length > Size()) { 253 return NULL; 254 } 255 FontDataPtr slice = new ReadableFontData(this, offset, length); 256 // Note: exception not ported because the condition is always false in C++. 257 // if (slice == null) { throw new IndexOutOfBoundsException( ... 258 return slice.Detach(); 259} 260 261CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) { 262 if (offset < 0 || offset > Size()) { 263 return NULL; 264 } 265 FontDataPtr slice = new ReadableFontData(this, offset); 266 // Note: exception not ported because the condition is always false in C++. 267 // if (slice == null) { throw new IndexOutOfBoundsException( ... 268 return slice.Detach(); 269} 270 271ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset) 272 : FontData(data, offset), 273 checksum_set_(false), 274 checksum_(0) { 275} 276 277ReadableFontData::ReadableFontData(ReadableFontData* data, 278 int32_t offset, 279 int32_t length) 280 : FontData(data, offset, length), 281 checksum_set_(false), 282 checksum_(0) { 283} 284 285void ReadableFontData::ComputeChecksum() { 286 // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity 287 int64_t sum = 0; 288 if (checksum_range_.empty()) { 289 sum = ComputeCheckSum(0, Length()); 290 } else { 291 for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size(); 292 low_bound_index += 2) { 293 int32_t low_bound = checksum_range_[low_bound_index]; 294 int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ? 295 Length() : 296 checksum_range_[low_bound_index + 1]; 297 sum += ComputeCheckSum(low_bound, high_bound); 298 } 299 } 300 301 checksum_ = sum & 0xffffffffL; 302 checksum_set_ = true; 303} 304 305int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound, 306 int32_t high_bound) { 307 int64_t sum = 0; 308 // Checksum all whole 4-byte chunks. 309 for (int32_t i = low_bound; i <= high_bound - 4; i += 4) { 310 sum += ReadULong(i); 311 } 312 313 // Add last fragment if not 4-byte multiple 314 int32_t off = high_bound & -4; 315 if (off < high_bound) { 316 int32_t b3 = ReadUByte(off); 317 int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0; 318 int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0; 319 int32_t b0 = 0; 320 sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; 321 } 322 return sum; 323} 324 325} // namespace sfntly 326