summaryrefslogtreecommitdiff
path: root/sfntly/data/readable_font_data.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sfntly/data/readable_font_data.cc')
-rw-r--r--sfntly/data/readable_font_data.cc336
1 files changed, 336 insertions, 0 deletions
diff --git a/sfntly/data/readable_font_data.cc b/sfntly/data/readable_font_data.cc
new file mode 100644
index 0000000..06d783f
--- /dev/null
+++ b/sfntly/data/readable_font_data.cc
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "sfntly/data/readable_font_data.h"
+
+#include <stdio.h>
+
+#include "sfntly/data/memory_byte_array.h"
+#include "sfntly/data/writable_font_data.h"
+#include "sfntly/port/exception_type.h"
+
+namespace sfntly {
+
+ReadableFontData::ReadableFontData(ByteArray* array)
+ : FontData(array),
+ checksum_set_(false),
+ checksum_(0) {
+}
+
+ReadableFontData::~ReadableFontData() {}
+
+// TODO(arthurhsu): re-investigate the memory model of this function. It's
+// not too useful without copying, but it's not performance
+// savvy to do copying.
+CALLER_ATTACH
+ReadableFontData* ReadableFontData::CreateReadableFontData(ByteVector* b) {
+ assert(b);
+ ByteArrayPtr ba = new MemoryByteArray(b->size());
+ ba->Put(0, b);
+ ReadableFontDataPtr wfd = new ReadableFontData(ba);
+ return wfd.Detach();
+}
+
+int64_t ReadableFontData::Checksum() {
+ AutoLock lock(checksum_lock_);
+ if (!checksum_set_) {
+ ComputeChecksum();
+ }
+ return checksum_;
+}
+
+void ReadableFontData::SetCheckSumRanges(const IntegerList& ranges) {
+ checksum_range_ = ranges;
+ checksum_set_ = false; // UNIMPLEMENTED: atomicity
+}
+
+int32_t ReadableFontData::ReadUByte(int32_t index) {
+ int32_t b = array_->Get(BoundOffset(index));
+#if !defined (SFNTLY_NO_EXCEPTION)
+ if (b < 0) {
+ throw IndexOutOfBoundException(
+ "Index attempted to be read from is out of bounds", index);
+ }
+#endif
+ return b;
+}
+
+int32_t ReadableFontData::ReadByte(int32_t index) {
+ int32_t b = array_->Get(BoundOffset(index));
+#if !defined (SFNTLY_NO_EXCEPTION)
+ if (b < 0) {
+ throw IndexOutOfBoundException(
+ "Index attempted to be read from is out of bounds", index);
+ }
+#endif
+ return (b << 24) >> 24;
+}
+
+int32_t ReadableFontData::ReadBytes(int32_t index,
+ byte_t* b,
+ int32_t offset,
+ int32_t length) {
+ return array_->Get(BoundOffset(index), b, offset, BoundLength(index, length));
+}
+
+int32_t ReadableFontData::ReadChar(int32_t index) {
+ return ReadUByte(index);
+}
+
+int32_t ReadableFontData::ReadUShort(int32_t index) {
+ return 0xffff & (ReadUByte(index) << 8 | ReadUByte(index + 1));
+}
+
+int32_t ReadableFontData::ReadShort(int32_t index) {
+ return ((ReadByte(index) << 8 | ReadUByte(index + 1)) << 16) >> 16;
+}
+
+int32_t ReadableFontData::ReadUInt24(int32_t index) {
+ return 0xffffff & (ReadUByte(index) << 16 |
+ ReadUByte(index + 1) << 8 |
+ ReadUByte(index + 2));
+}
+
+int64_t ReadableFontData::ReadULong(int32_t index) {
+ return 0xffffffffL & (ReadUByte(index) << 24 |
+ ReadUByte(index + 1) << 16 |
+ ReadUByte(index + 2) << 8 |
+ ReadUByte(index + 3));
+}
+
+int32_t ReadableFontData::ReadULongAsInt(int32_t index) {
+ int64_t ulong = ReadULong(index);
+#if !defined (SFNTLY_NO_EXCEPTION)
+ if ((ulong & 0x80000000) == 0x80000000) {
+ throw ArithmeticException("Long value too large to fit into an integer.");
+ }
+#endif
+ return static_cast<int32_t>(ulong);
+}
+
+int64_t ReadableFontData::ReadULongLE(int32_t index) {
+ return 0xffffffffL & (ReadUByte(index) |
+ ReadUByte(index + 1) << 8 |
+ ReadUByte(index + 2) << 16 |
+ ReadUByte(index + 3) << 24);
+}
+
+int32_t ReadableFontData::ReadLong(int32_t index) {
+ return ReadByte(index) << 24 |
+ ReadUByte(index + 1) << 16 |
+ ReadUByte(index + 2) << 8 |
+ ReadUByte(index + 3);
+}
+
+int32_t ReadableFontData::ReadFixed(int32_t index) {
+ return ReadLong(index);
+}
+
+int64_t ReadableFontData::ReadDateTimeAsLong(int32_t index) {
+ return (int64_t)ReadULong(index) << 32 | ReadULong(index + 4);
+}
+
+int32_t ReadableFontData::ReadFWord(int32_t index) {
+ return ReadShort(index);
+}
+
+int32_t ReadableFontData::ReadFUFWord(int32_t index) {
+ return ReadUShort(index);
+}
+
+int32_t ReadableFontData::CopyTo(OutputStream* os) {
+ return array_->CopyTo(os, BoundOffset(0), Length());
+}
+
+int32_t ReadableFontData::CopyTo(WritableFontData* wfd) {
+ return array_->CopyTo(wfd->BoundOffset(0),
+ wfd->array_,
+ BoundOffset(0),
+ Length());
+}
+
+int32_t ReadableFontData::CopyTo(ByteArray* ba) {
+ return array_->CopyTo(ba, BoundOffset(0), Length());
+}
+
+int32_t ReadableFontData::SearchUShort(int32_t start_index,
+ int32_t start_offset,
+ int32_t end_index,
+ int32_t end_offset,
+ int32_t length,
+ int32_t key) {
+ int32_t location = 0;
+ int32_t bottom = 0;
+ int32_t top = length;
+ while (top != bottom) {
+ location = (top + bottom) / 2;
+ int32_t location_start = ReadUShort(start_index + location * start_offset);
+ if (key < location_start) {
+ // location is below current location
+ top = location;
+ } else {
+ // is key below the upper bound?
+ int32_t location_end = ReadUShort(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+ fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+ if (key <= location_end) {
+ return location;
+ } else {
+ // location is above the current location
+ bottom = location + 1;
+ }
+ }
+ }
+ return -1;
+}
+
+int32_t ReadableFontData::SearchUShort(int32_t start_index,
+ int32_t start_offset,
+ int32_t length,
+ int32_t key) {
+ int32_t location = 0;
+ int32_t bottom = 0;
+ int32_t top = length;
+ while (top != bottom) {
+ location = (top + bottom) / 2;
+ int32_t location_start = ReadUShort(start_index + location * start_offset);
+ if (key < location_start) {
+ // location is below current location
+ top = location;
+ } else if (key > location_start) {
+ // location is above current location
+ bottom = location + 1;
+ } else {
+ return location;
+ }
+ }
+ return -1;
+}
+
+int32_t ReadableFontData::SearchULong(int32_t start_index,
+ int32_t start_offset,
+ int32_t end_index,
+ int32_t end_offset,
+ int32_t length,
+ int32_t key) {
+ int32_t location = 0;
+ int32_t bottom = 0;
+ int32_t top = length;
+ while (top != bottom) {
+ location = (top + bottom) / 2;
+ int32_t location_start = ReadULongAsInt(start_index
+ + location * start_offset);
+ if (key < location_start) {
+ // location is below current location
+ top = location;
+ } else {
+ // is key below the upper bound?
+ int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+ fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+ if (key <= location_end) {
+ return location;
+ } else {
+ // location is above the current location
+ bottom = location + 1;
+ }
+ }
+ }
+ return -1;
+}
+
+CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
+ int32_t length) {
+ if (offset < 0 || offset + length > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+ throw IndexOutOfBoundsException(
+ "Attempt to bind data outside of its limits");
+#endif
+ return NULL;
+ }
+ FontDataPtr slice = new ReadableFontData(this, offset, length);
+ return slice.Detach();
+}
+
+CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset) {
+ if (offset < 0 || offset > Size()) {
+#if !defined (SFNTLY_NO_EXCEPTION)
+ throw IndexOutOfBoundsException(
+ "Attempt to bind data outside of its limits");
+#endif
+ return NULL;
+ }
+ FontDataPtr slice = new ReadableFontData(this, offset);
+ return slice.Detach();
+}
+
+ReadableFontData::ReadableFontData(ReadableFontData* data, int32_t offset)
+ : FontData(data, offset),
+ checksum_set_(false),
+ checksum_(0) {
+}
+
+ReadableFontData::ReadableFontData(ReadableFontData* data,
+ int32_t offset,
+ int32_t length)
+ : FontData(data, offset, length),
+ checksum_set_(false),
+ checksum_(0) {
+}
+
+void ReadableFontData::ComputeChecksum() {
+ // TODO(arthurhsu): IMPLEMENT: synchronization/atomicity
+ int64_t sum = 0;
+ if (checksum_range_.empty()) {
+ sum = ComputeCheckSum(0, Length());
+ } else {
+ for (uint32_t low_bound_index = 0; low_bound_index < checksum_range_.size();
+ low_bound_index += 2) {
+ int32_t low_bound = checksum_range_[low_bound_index];
+ int32_t high_bound = (low_bound_index == checksum_range_.size() - 1) ?
+ Length() :
+ checksum_range_[low_bound_index + 1];
+ sum += ComputeCheckSum(low_bound, high_bound);
+ }
+ }
+
+ checksum_ = sum & 0xffffffffL;
+ checksum_set_ = true;
+}
+
+int64_t ReadableFontData::ComputeCheckSum(int32_t low_bound,
+ int32_t high_bound) {
+ int64_t sum = 0;
+ // Checksum all whole 4-byte chunks.
+ for (int32_t i = low_bound; i <= high_bound - 4; i += 4) {
+ sum += ReadULong(i);
+ }
+
+ // Add last fragment if not 4-byte multiple
+ int32_t off = high_bound & -4;
+ if (off < high_bound) {
+ int32_t b3 = ReadUByte(off);
+ int32_t b2 = (off + 1 < high_bound) ? ReadUByte(off + 1) : 0;
+ int32_t b1 = (off + 2 < high_bound) ? ReadUByte(off + 2) : 0;
+ int32_t b0 = 0;
+ sum += (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+ }
+ return sum;
+}
+
+} // namespace sfntly