Home | History | Annotate | Download | only in data
      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