129345531d776962073312d423917406fc59b09f6Jaesung Chung// Copyright 2015 Google Inc.
229345531d776962073312d423917406fc59b09f6Jaesung Chung//
329345531d776962073312d423917406fc59b09f6Jaesung Chung// Licensed under the Apache License, Version 2.0 (the "License");
429345531d776962073312d423917406fc59b09f6Jaesung Chung// you may not use this file except in compliance with the License.
529345531d776962073312d423917406fc59b09f6Jaesung Chung// You may obtain a copy of the License at
629345531d776962073312d423917406fc59b09f6Jaesung Chung//
729345531d776962073312d423917406fc59b09f6Jaesung Chung//      http://www.apache.org/licenses/LICENSE-2.0
829345531d776962073312d423917406fc59b09f6Jaesung Chung//
929345531d776962073312d423917406fc59b09f6Jaesung Chung// Unless required by applicable law or agreed to in writing, software
1029345531d776962073312d423917406fc59b09f6Jaesung Chung// distributed under the License is distributed on an "AS IS" BASIS,
1129345531d776962073312d423917406fc59b09f6Jaesung Chung// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1229345531d776962073312d423917406fc59b09f6Jaesung Chung// See the License for the specific language governing permissions and
1329345531d776962073312d423917406fc59b09f6Jaesung Chung// limitations under the License.
1429345531d776962073312d423917406fc59b09f6Jaesung Chung//
1529345531d776962073312d423917406fc59b09f6Jaesung Chung////////////////////////////////////////////////////////////////////////////////
1629345531d776962073312d423917406fc59b09f6Jaesung Chung
1729345531d776962073312d423917406fc59b09f6Jaesung Chung#include "src/binary_parse/range_checked_byte_ptr.h"
1829345531d776962073312d423917406fc59b09f6Jaesung Chung
1929345531d776962073312d423917406fc59b09f6Jaesung Chung#include <assert.h>
2029345531d776962073312d423917406fc59b09f6Jaesung Chung#include <cstddef>
2129345531d776962073312d423917406fc59b09f6Jaesung Chung#include <cstring>
2229345531d776962073312d423917406fc59b09f6Jaesung Chung
2329345531d776962073312d423917406fc59b09f6Jaesung Chungnamespace piex {
2429345531d776962073312d423917406fc59b09f6Jaesung Chungnamespace binary_parse {
2529345531d776962073312d423917406fc59b09f6Jaesung Chung
2629345531d776962073312d423917406fc59b09f6Jaesung Chung#ifdef BREAK_IF_DEBUGGING_AND_OUT_OF_RANGE
2729345531d776962073312d423917406fc59b09f6Jaesung Chung#define BREAK_IF_DEBUGGING() assert(false)
2829345531d776962073312d423917406fc59b09f6Jaesung Chung#else
2929345531d776962073312d423917406fc59b09f6Jaesung Chung#define BREAK_IF_DEBUGGING() assert(true)
3029345531d776962073312d423917406fc59b09f6Jaesung Chung#endif
3129345531d776962073312d423917406fc59b09f6Jaesung Chung
3229345531d776962073312d423917406fc59b09f6Jaesung Chungnamespace {
3329345531d776962073312d423917406fc59b09f6Jaesung Chungclass MemoryPagedByteArray : public PagedByteArray {
3429345531d776962073312d423917406fc59b09f6Jaesung Chung public:
3529345531d776962073312d423917406fc59b09f6Jaesung Chung  MemoryPagedByteArray(const unsigned char *buffer, const size_t len);
3629345531d776962073312d423917406fc59b09f6Jaesung Chung
3729345531d776962073312d423917406fc59b09f6Jaesung Chung  virtual size_t length() const;
3829345531d776962073312d423917406fc59b09f6Jaesung Chung  virtual size_t pageSize() const;
3929345531d776962073312d423917406fc59b09f6Jaesung Chung  virtual void getPage(size_t page_index, const unsigned char **begin,
4029345531d776962073312d423917406fc59b09f6Jaesung Chung                       const unsigned char **end, PagePtr *page) const;
4129345531d776962073312d423917406fc59b09f6Jaesung Chung
4229345531d776962073312d423917406fc59b09f6Jaesung Chung private:
4329345531d776962073312d423917406fc59b09f6Jaesung Chung  const unsigned char *buffer_;
4429345531d776962073312d423917406fc59b09f6Jaesung Chung  const size_t len_;
4529345531d776962073312d423917406fc59b09f6Jaesung Chung};
4629345531d776962073312d423917406fc59b09f6Jaesung Chung
4729345531d776962073312d423917406fc59b09f6Jaesung ChungMemoryPagedByteArray::MemoryPagedByteArray(const unsigned char *buffer,
4829345531d776962073312d423917406fc59b09f6Jaesung Chung                                           const size_t len)
4929345531d776962073312d423917406fc59b09f6Jaesung Chung    : buffer_(buffer), len_(len) {}
5029345531d776962073312d423917406fc59b09f6Jaesung Chung
5129345531d776962073312d423917406fc59b09f6Jaesung Chungsize_t MemoryPagedByteArray::length() const { return len_; }
5229345531d776962073312d423917406fc59b09f6Jaesung Chung
5329345531d776962073312d423917406fc59b09f6Jaesung Chungsize_t MemoryPagedByteArray::pageSize() const { return len_; }
5429345531d776962073312d423917406fc59b09f6Jaesung Chung
55b415ce2eec78846ec705c983f98a74c9526f3faaEik Brauervoid MemoryPagedByteArray::getPage(size_t /* page_index */,
5629345531d776962073312d423917406fc59b09f6Jaesung Chung                                   const unsigned char **begin,
5729345531d776962073312d423917406fc59b09f6Jaesung Chung                                   const unsigned char **end,
5829345531d776962073312d423917406fc59b09f6Jaesung Chung                                   PagePtr *page) const {
5929345531d776962073312d423917406fc59b09f6Jaesung Chung  *begin = buffer_;
6029345531d776962073312d423917406fc59b09f6Jaesung Chung  *end = buffer_ + len_;
6129345531d776962073312d423917406fc59b09f6Jaesung Chung  *page = PagePtr();
6229345531d776962073312d423917406fc59b09f6Jaesung Chung}
6329345531d776962073312d423917406fc59b09f6Jaesung Chung
6429345531d776962073312d423917406fc59b09f6Jaesung Chung// A functor that does nothing. This is used as a no-op shared pointer
6529345531d776962073312d423917406fc59b09f6Jaesung Chung// deallocator below.
6629345531d776962073312d423917406fc59b09f6Jaesung Chungclass NullFunctor {
6729345531d776962073312d423917406fc59b09f6Jaesung Chung public:
6829345531d776962073312d423917406fc59b09f6Jaesung Chung  void operator()() {}
69b415ce2eec78846ec705c983f98a74c9526f3faaEik Brauer  void operator()(PagedByteArray * /* p */) const {}
7029345531d776962073312d423917406fc59b09f6Jaesung Chung};
7129345531d776962073312d423917406fc59b09f6Jaesung Chung}  // namespace
7229345531d776962073312d423917406fc59b09f6Jaesung Chung
7329345531d776962073312d423917406fc59b09f6Jaesung ChungPagedByteArray::~PagedByteArray() {}
7429345531d776962073312d423917406fc59b09f6Jaesung Chung
7529345531d776962073312d423917406fc59b09f6Jaesung ChungRangeCheckedBytePtr::RangeCheckedBytePtr()
7629345531d776962073312d423917406fc59b09f6Jaesung Chung    : array_(),
7729345531d776962073312d423917406fc59b09f6Jaesung Chung      page_data_(NULL),
7829345531d776962073312d423917406fc59b09f6Jaesung Chung      current_pos_(0),
7929345531d776962073312d423917406fc59b09f6Jaesung Chung      sub_array_begin_(0),
8029345531d776962073312d423917406fc59b09f6Jaesung Chung      sub_array_end_(0),
8129345531d776962073312d423917406fc59b09f6Jaesung Chung      page_begin_offset_(0),
8229345531d776962073312d423917406fc59b09f6Jaesung Chung      current_page_len_(0),
8329345531d776962073312d423917406fc59b09f6Jaesung Chung      error_flag_(RANGE_CHECKED_BYTE_ERROR) {}
8429345531d776962073312d423917406fc59b09f6Jaesung Chung
8529345531d776962073312d423917406fc59b09f6Jaesung ChungRangeCheckedBytePtr::RangeCheckedBytePtr(const unsigned char *array,
8629345531d776962073312d423917406fc59b09f6Jaesung Chung                                         const size_t len)
8729345531d776962073312d423917406fc59b09f6Jaesung Chung    : array_(new MemoryPagedByteArray(array, len)),
8829345531d776962073312d423917406fc59b09f6Jaesung Chung      page_data_(NULL),
8929345531d776962073312d423917406fc59b09f6Jaesung Chung      current_pos_(0),
9029345531d776962073312d423917406fc59b09f6Jaesung Chung      sub_array_begin_(0),
9129345531d776962073312d423917406fc59b09f6Jaesung Chung      sub_array_end_(len),
9229345531d776962073312d423917406fc59b09f6Jaesung Chung      page_begin_offset_(0),
9329345531d776962073312d423917406fc59b09f6Jaesung Chung      current_page_len_(0),
9429345531d776962073312d423917406fc59b09f6Jaesung Chung      error_flag_(RANGE_CHECKED_BYTE_SUCCESS) {
9529345531d776962073312d423917406fc59b09f6Jaesung Chung  assert(array);
9629345531d776962073312d423917406fc59b09f6Jaesung Chung  if (array == NULL) {
9729345531d776962073312d423917406fc59b09f6Jaesung Chung    error_flag_ = RANGE_CHECKED_BYTE_ERROR;
9829345531d776962073312d423917406fc59b09f6Jaesung Chung  }
9929345531d776962073312d423917406fc59b09f6Jaesung Chung}
10029345531d776962073312d423917406fc59b09f6Jaesung Chung
10129345531d776962073312d423917406fc59b09f6Jaesung ChungRangeCheckedBytePtr::RangeCheckedBytePtr(PagedByteArray *array)
10229345531d776962073312d423917406fc59b09f6Jaesung Chung    : array_(array, NullFunctor()),
10329345531d776962073312d423917406fc59b09f6Jaesung Chung      page_data_(NULL),
10429345531d776962073312d423917406fc59b09f6Jaesung Chung      current_pos_(0),
10529345531d776962073312d423917406fc59b09f6Jaesung Chung      sub_array_begin_(0),
10629345531d776962073312d423917406fc59b09f6Jaesung Chung      sub_array_end_(array->length()),
10729345531d776962073312d423917406fc59b09f6Jaesung Chung      page_begin_offset_(0),
10829345531d776962073312d423917406fc59b09f6Jaesung Chung      current_page_len_(0),
10929345531d776962073312d423917406fc59b09f6Jaesung Chung      error_flag_(RANGE_CHECKED_BYTE_SUCCESS) {}
11029345531d776962073312d423917406fc59b09f6Jaesung Chung
11129345531d776962073312d423917406fc59b09f6Jaesung ChungRangeCheckedBytePtr RangeCheckedBytePtr::invalidPointer() {
11229345531d776962073312d423917406fc59b09f6Jaesung Chung  return RangeCheckedBytePtr();
11329345531d776962073312d423917406fc59b09f6Jaesung Chung}
11429345531d776962073312d423917406fc59b09f6Jaesung Chung
11529345531d776962073312d423917406fc59b09f6Jaesung ChungRangeCheckedBytePtr RangeCheckedBytePtr::pointerToSubArray(
11629345531d776962073312d423917406fc59b09f6Jaesung Chung    size_t pos, size_t length) const {
11729345531d776962073312d423917406fc59b09f6Jaesung Chung  RangeCheckedBytePtr sub_result = (*this) + pos;
11829345531d776962073312d423917406fc59b09f6Jaesung Chung  if (!sub_result.errorOccurred() && length <= sub_result.remainingLength()) {
11929345531d776962073312d423917406fc59b09f6Jaesung Chung    sub_result.sub_array_begin_ = sub_result.current_pos_;
12029345531d776962073312d423917406fc59b09f6Jaesung Chung    sub_result.sub_array_end_ = sub_result.sub_array_begin_ + length;
12129345531d776962073312d423917406fc59b09f6Jaesung Chung
12229345531d776962073312d423917406fc59b09f6Jaesung Chung    // Restrict the boundaries of the current page to the newly set sub-array.
12329345531d776962073312d423917406fc59b09f6Jaesung Chung    sub_result.restrictPageToSubArray();
12429345531d776962073312d423917406fc59b09f6Jaesung Chung
12529345531d776962073312d423917406fc59b09f6Jaesung Chung    return sub_result;
12629345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
12729345531d776962073312d423917406fc59b09f6Jaesung Chung    error_flag_ = RANGE_CHECKED_BYTE_ERROR;
12829345531d776962073312d423917406fc59b09f6Jaesung Chung    return invalidPointer();
12929345531d776962073312d423917406fc59b09f6Jaesung Chung  }
13029345531d776962073312d423917406fc59b09f6Jaesung Chung}
13129345531d776962073312d423917406fc59b09f6Jaesung Chung
13229345531d776962073312d423917406fc59b09f6Jaesung Chungsize_t RangeCheckedBytePtr::offsetInArray() const {
13329345531d776962073312d423917406fc59b09f6Jaesung Chung  // sub_array_begin_ <= current_pos_ is a class invariant, but protect
13429345531d776962073312d423917406fc59b09f6Jaesung Chung  // against violations of this invariant.
13529345531d776962073312d423917406fc59b09f6Jaesung Chung  if (sub_array_begin_ <= current_pos_) {
13629345531d776962073312d423917406fc59b09f6Jaesung Chung    return current_pos_ - sub_array_begin_;
13729345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
13829345531d776962073312d423917406fc59b09f6Jaesung Chung    assert(false);
13929345531d776962073312d423917406fc59b09f6Jaesung Chung    return 0;
14029345531d776962073312d423917406fc59b09f6Jaesung Chung  }
14129345531d776962073312d423917406fc59b09f6Jaesung Chung}
14229345531d776962073312d423917406fc59b09f6Jaesung Chung
14329345531d776962073312d423917406fc59b09f6Jaesung Chungstd::string RangeCheckedBytePtr::substr(size_t pos, size_t length) const {
14429345531d776962073312d423917406fc59b09f6Jaesung Chung  std::vector<unsigned char> bytes = extractBytes(pos, length);
14529345531d776962073312d423917406fc59b09f6Jaesung Chung  std::string result;
14629345531d776962073312d423917406fc59b09f6Jaesung Chung  result.reserve(bytes.size());
14729345531d776962073312d423917406fc59b09f6Jaesung Chung  for (size_t i = 0; i < bytes.size(); ++i) {
14829345531d776962073312d423917406fc59b09f6Jaesung Chung    result.push_back(static_cast<char>(bytes[i]));
14929345531d776962073312d423917406fc59b09f6Jaesung Chung  }
15029345531d776962073312d423917406fc59b09f6Jaesung Chung  return result;
15129345531d776962073312d423917406fc59b09f6Jaesung Chung}
15229345531d776962073312d423917406fc59b09f6Jaesung Chung
15329345531d776962073312d423917406fc59b09f6Jaesung Chungstd::vector<unsigned char> RangeCheckedBytePtr::extractBytes(
15429345531d776962073312d423917406fc59b09f6Jaesung Chung    size_t pos, size_t length) const {
15529345531d776962073312d423917406fc59b09f6Jaesung Chung  std::vector<unsigned char> result;
15629345531d776962073312d423917406fc59b09f6Jaesung Chung  if (pos + length < pos /* overflow */ || remainingLength() < pos + length) {
15729345531d776962073312d423917406fc59b09f6Jaesung Chung    BREAK_IF_DEBUGGING();
15829345531d776962073312d423917406fc59b09f6Jaesung Chung    error_flag_ = RANGE_CHECKED_BYTE_ERROR_OVERFLOW;
15929345531d776962073312d423917406fc59b09f6Jaesung Chung    return result;
16029345531d776962073312d423917406fc59b09f6Jaesung Chung  }
16129345531d776962073312d423917406fc59b09f6Jaesung Chung  result.reserve(length);
16229345531d776962073312d423917406fc59b09f6Jaesung Chung  for (size_t i = 0; i < length; ++i) {
16329345531d776962073312d423917406fc59b09f6Jaesung Chung    result.push_back((*this)[pos + i]);
16429345531d776962073312d423917406fc59b09f6Jaesung Chung  }
16529345531d776962073312d423917406fc59b09f6Jaesung Chung  return result;
16629345531d776962073312d423917406fc59b09f6Jaesung Chung}
16729345531d776962073312d423917406fc59b09f6Jaesung Chung
16829345531d776962073312d423917406fc59b09f6Jaesung Chungbool operator==(const RangeCheckedBytePtr &x, const RangeCheckedBytePtr &y) {
16929345531d776962073312d423917406fc59b09f6Jaesung Chung  if (x.array_ != y.array_) {
17029345531d776962073312d423917406fc59b09f6Jaesung Chung    assert(false);
17129345531d776962073312d423917406fc59b09f6Jaesung Chung    return false;
17229345531d776962073312d423917406fc59b09f6Jaesung Chung  }
17329345531d776962073312d423917406fc59b09f6Jaesung Chung
17429345531d776962073312d423917406fc59b09f6Jaesung Chung  return x.current_pos_ == y.current_pos_;
17529345531d776962073312d423917406fc59b09f6Jaesung Chung}
17629345531d776962073312d423917406fc59b09f6Jaesung Chung
17729345531d776962073312d423917406fc59b09f6Jaesung Chungbool operator!=(const RangeCheckedBytePtr &x, const RangeCheckedBytePtr &y) {
17829345531d776962073312d423917406fc59b09f6Jaesung Chung  return !(x == y);
17929345531d776962073312d423917406fc59b09f6Jaesung Chung}
18029345531d776962073312d423917406fc59b09f6Jaesung Chung
18129345531d776962073312d423917406fc59b09f6Jaesung Chungvoid RangeCheckedBytePtr::loadPageForOffset(size_t offset) const {
18229345531d776962073312d423917406fc59b09f6Jaesung Chung  // The offset should always lie within the bounds of the sub-array (this
18329345531d776962073312d423917406fc59b09f6Jaesung Chung  // condition is enforced at the callsite). However, even if the offset lies
18429345531d776962073312d423917406fc59b09f6Jaesung Chung  // outside the sub-array, the restrictPageToSubArray() call at the end
18529345531d776962073312d423917406fc59b09f6Jaesung Chung  // ensures that the object is left in a consistent state that maintains the
18629345531d776962073312d423917406fc59b09f6Jaesung Chung  // class invariants.
18729345531d776962073312d423917406fc59b09f6Jaesung Chung  assert(offset >= sub_array_begin_ && offset < sub_array_end_);
18829345531d776962073312d423917406fc59b09f6Jaesung Chung
18929345531d776962073312d423917406fc59b09f6Jaesung Chung  // Ensure that offset lies within the array.
19029345531d776962073312d423917406fc59b09f6Jaesung Chung  if (offset >= array_->length()) {
19129345531d776962073312d423917406fc59b09f6Jaesung Chung    assert(false);
19229345531d776962073312d423917406fc59b09f6Jaesung Chung    return;
19329345531d776962073312d423917406fc59b09f6Jaesung Chung  }
19429345531d776962073312d423917406fc59b09f6Jaesung Chung
19529345531d776962073312d423917406fc59b09f6Jaesung Chung  // Determine the index of the page to request.
19629345531d776962073312d423917406fc59b09f6Jaesung Chung  size_t page_index = offset / array_->pageSize();
19729345531d776962073312d423917406fc59b09f6Jaesung Chung
19829345531d776962073312d423917406fc59b09f6Jaesung Chung  // Get the page.
19929345531d776962073312d423917406fc59b09f6Jaesung Chung  const unsigned char *page_begin;
20029345531d776962073312d423917406fc59b09f6Jaesung Chung  const unsigned char *page_end;
20129345531d776962073312d423917406fc59b09f6Jaesung Chung  array_->getPage(page_index, &page_begin, &page_end, &page_);
20229345531d776962073312d423917406fc59b09f6Jaesung Chung
20329345531d776962073312d423917406fc59b09f6Jaesung Chung  // Ensure that the page has the expected length (as specified in the
20429345531d776962073312d423917406fc59b09f6Jaesung Chung  // PagedByteArray interface).
20529345531d776962073312d423917406fc59b09f6Jaesung Chung  size_t expected_page_size = array_->pageSize();
20629345531d776962073312d423917406fc59b09f6Jaesung Chung  if (page_index == (array_->length() - 1) / array_->pageSize()) {
20729345531d776962073312d423917406fc59b09f6Jaesung Chung    expected_page_size = array_->length() - array_->pageSize() * page_index;
20829345531d776962073312d423917406fc59b09f6Jaesung Chung  }
20929345531d776962073312d423917406fc59b09f6Jaesung Chung  if ((page_end < page_begin) ||
21029345531d776962073312d423917406fc59b09f6Jaesung Chung      (static_cast<size_t>(page_end - page_begin) != expected_page_size)) {
21129345531d776962073312d423917406fc59b09f6Jaesung Chung    assert(false);
21229345531d776962073312d423917406fc59b09f6Jaesung Chung    return;
21329345531d776962073312d423917406fc59b09f6Jaesung Chung  }
21429345531d776962073312d423917406fc59b09f6Jaesung Chung
21529345531d776962073312d423917406fc59b09f6Jaesung Chung  // Remember information about page.
21629345531d776962073312d423917406fc59b09f6Jaesung Chung  page_data_ = page_begin;
21729345531d776962073312d423917406fc59b09f6Jaesung Chung  page_begin_offset_ = page_index * array_->pageSize();
218a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer  current_page_len_ = static_cast<size_t>(page_end - page_begin);
21929345531d776962073312d423917406fc59b09f6Jaesung Chung
22029345531d776962073312d423917406fc59b09f6Jaesung Chung  // Restrict the boundaries of the page to lie within the sub-array.
22129345531d776962073312d423917406fc59b09f6Jaesung Chung  restrictPageToSubArray();
22229345531d776962073312d423917406fc59b09f6Jaesung Chung}
22329345531d776962073312d423917406fc59b09f6Jaesung Chung
22429345531d776962073312d423917406fc59b09f6Jaesung Chungvoid RangeCheckedBytePtr::restrictPageToSubArray() const {
22529345531d776962073312d423917406fc59b09f6Jaesung Chung  // Restrict the current page's boundaries so that it is always contained
22629345531d776962073312d423917406fc59b09f6Jaesung Chung  // completely within the extent of the sub-array.
22729345531d776962073312d423917406fc59b09f6Jaesung Chung  // This function is purposely designed to work correctly in the following
22829345531d776962073312d423917406fc59b09f6Jaesung Chung  // two special cases:
22929345531d776962073312d423917406fc59b09f6Jaesung Chung  // a) The current page lies entirely outside the sub-array. In this case,
23029345531d776962073312d423917406fc59b09f6Jaesung Chung  //    current_page_len_ will be set to zero. page_data_ may either remain
23129345531d776962073312d423917406fc59b09f6Jaesung Chung  //    unchanged or may be changed to point one element beyond the end of the
23229345531d776962073312d423917406fc59b09f6Jaesung Chung  //    page, depending on whether the current page lies before or after the
23329345531d776962073312d423917406fc59b09f6Jaesung Chung  //    sub-array.
23429345531d776962073312d423917406fc59b09f6Jaesung Chung  // b) The current page is in the state as initialized by the constructor
23529345531d776962073312d423917406fc59b09f6Jaesung Chung  //    (i.e. page_data_ is NULL and current_page_len_ is zero). In this case,
23629345531d776962073312d423917406fc59b09f6Jaesung Chung  //    page_data_ and current_page_len_ will remain unchanged.
23729345531d776962073312d423917406fc59b09f6Jaesung Chung
23829345531d776962073312d423917406fc59b09f6Jaesung Chung  // Does the beginning of the page lie before the beginning of the sub-array?
23929345531d776962073312d423917406fc59b09f6Jaesung Chung  if (page_begin_offset_ < sub_array_begin_) {
24029345531d776962073312d423917406fc59b09f6Jaesung Chung    // Compute amount by which to shorten page.
24129345531d776962073312d423917406fc59b09f6Jaesung Chung    size_t amount_to_shorten = sub_array_begin_ - page_begin_offset_;
24229345531d776962073312d423917406fc59b09f6Jaesung Chung    if (amount_to_shorten > current_page_len_) {
24329345531d776962073312d423917406fc59b09f6Jaesung Chung      amount_to_shorten = current_page_len_;
24429345531d776962073312d423917406fc59b09f6Jaesung Chung    }
24529345531d776962073312d423917406fc59b09f6Jaesung Chung
24629345531d776962073312d423917406fc59b09f6Jaesung Chung    // Adjust beginning of page accordingly.
24729345531d776962073312d423917406fc59b09f6Jaesung Chung    page_begin_offset_ += amount_to_shorten;
24829345531d776962073312d423917406fc59b09f6Jaesung Chung    page_data_ += amount_to_shorten;
24929345531d776962073312d423917406fc59b09f6Jaesung Chung    current_page_len_ -= amount_to_shorten;
25029345531d776962073312d423917406fc59b09f6Jaesung Chung  }
25129345531d776962073312d423917406fc59b09f6Jaesung Chung
25229345531d776962073312d423917406fc59b09f6Jaesung Chung  // Does the end of the page lie beyond the end of the sub-array?
25329345531d776962073312d423917406fc59b09f6Jaesung Chung  if (page_begin_offset_ + current_page_len_ > sub_array_end_) {
25429345531d776962073312d423917406fc59b09f6Jaesung Chung    // Reduce length of page accordingly.
25529345531d776962073312d423917406fc59b09f6Jaesung Chung    size_t new_len = sub_array_end_ - page_begin_offset_;
25629345531d776962073312d423917406fc59b09f6Jaesung Chung    if (new_len > current_page_len_) {
25729345531d776962073312d423917406fc59b09f6Jaesung Chung      new_len = current_page_len_;
25829345531d776962073312d423917406fc59b09f6Jaesung Chung    }
25929345531d776962073312d423917406fc59b09f6Jaesung Chung    current_page_len_ = new_len;
26029345531d776962073312d423917406fc59b09f6Jaesung Chung  }
26129345531d776962073312d423917406fc59b09f6Jaesung Chung}
26229345531d776962073312d423917406fc59b09f6Jaesung Chung
26329345531d776962073312d423917406fc59b09f6Jaesung Chungint memcmp(const RangeCheckedBytePtr &x, const RangeCheckedBytePtr &y,
26429345531d776962073312d423917406fc59b09f6Jaesung Chung           size_t num) {
26529345531d776962073312d423917406fc59b09f6Jaesung Chung  std::vector<unsigned char> x_vec = x.extractBytes(0, num);
26629345531d776962073312d423917406fc59b09f6Jaesung Chung  std::vector<unsigned char> y_vec = y.extractBytes(0, num);
26729345531d776962073312d423917406fc59b09f6Jaesung Chung
26829345531d776962073312d423917406fc59b09f6Jaesung Chung  if (!x.errorOccurred() && !y.errorOccurred()) {
26929345531d776962073312d423917406fc59b09f6Jaesung Chung    return ::memcmp(&x_vec[0], &y_vec[0], num);
27029345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
27129345531d776962073312d423917406fc59b09f6Jaesung Chung    // return an arbitrary value
27229345531d776962073312d423917406fc59b09f6Jaesung Chung    return -1;
27329345531d776962073312d423917406fc59b09f6Jaesung Chung  }
27429345531d776962073312d423917406fc59b09f6Jaesung Chung}
27529345531d776962073312d423917406fc59b09f6Jaesung Chung
27629345531d776962073312d423917406fc59b09f6Jaesung Chungint strcmp(const RangeCheckedBytePtr &x, const std::string &y) {
27729345531d776962073312d423917406fc59b09f6Jaesung Chung  std::vector<unsigned char> x_vec = x.extractBytes(0, y.length());
27829345531d776962073312d423917406fc59b09f6Jaesung Chung
27929345531d776962073312d423917406fc59b09f6Jaesung Chung  if (!x.errorOccurred()) {
28029345531d776962073312d423917406fc59b09f6Jaesung Chung    return ::memcmp(&x_vec[0], y.c_str(), y.length());
28129345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
28229345531d776962073312d423917406fc59b09f6Jaesung Chung    // return an arbitrary value
28329345531d776962073312d423917406fc59b09f6Jaesung Chung    return -1;
28429345531d776962073312d423917406fc59b09f6Jaesung Chung  }
28529345531d776962073312d423917406fc59b09f6Jaesung Chung}
28629345531d776962073312d423917406fc59b09f6Jaesung Chung
28729345531d776962073312d423917406fc59b09f6Jaesung Chungsize_t strlen(const RangeCheckedBytePtr &src) {
28829345531d776962073312d423917406fc59b09f6Jaesung Chung  size_t len = 0;
28929345531d776962073312d423917406fc59b09f6Jaesung Chung  RangeCheckedBytePtr str = src;
29029345531d776962073312d423917406fc59b09f6Jaesung Chung  while (!str.errorOccurred() && (str[0] != '\0')) {
29129345531d776962073312d423917406fc59b09f6Jaesung Chung    str++;
29229345531d776962073312d423917406fc59b09f6Jaesung Chung    len++;
29329345531d776962073312d423917406fc59b09f6Jaesung Chung  }
29429345531d776962073312d423917406fc59b09f6Jaesung Chung  return len;
29529345531d776962073312d423917406fc59b09f6Jaesung Chung}
29629345531d776962073312d423917406fc59b09f6Jaesung Chung
29729345531d776962073312d423917406fc59b09f6Jaesung Chungint16 Get16s(const RangeCheckedBytePtr &input, const bool big_endian,
29829345531d776962073312d423917406fc59b09f6Jaesung Chung             MemoryStatus *status) {
29929345531d776962073312d423917406fc59b09f6Jaesung Chung  const uint16 unsigned_value = Get16u(input, big_endian, status);
30029345531d776962073312d423917406fc59b09f6Jaesung Chung  if (*status != RANGE_CHECKED_BYTE_SUCCESS) {
30129345531d776962073312d423917406fc59b09f6Jaesung Chung    // Return an arbitrary value.
30229345531d776962073312d423917406fc59b09f6Jaesung Chung    return 0;
30329345531d776962073312d423917406fc59b09f6Jaesung Chung  }
30429345531d776962073312d423917406fc59b09f6Jaesung Chung
30529345531d776962073312d423917406fc59b09f6Jaesung Chung  // Convert the two's-complement signed integer encoded in 'unsigned_value'
30629345531d776962073312d423917406fc59b09f6Jaesung Chung  // into a signed representation in the implementation's native representation
30729345531d776962073312d423917406fc59b09f6Jaesung Chung  // for signed integers. An optimized Blaze build (x64) compiles all of the
30829345531d776962073312d423917406fc59b09f6Jaesung Chung  // following code to a no-op (as of this writing).
30929345531d776962073312d423917406fc59b09f6Jaesung Chung  // For further details, see the corresponding comment in Get32s().
31029345531d776962073312d423917406fc59b09f6Jaesung Chung  if (unsigned_value == 0x8000u) {
31129345531d776962073312d423917406fc59b09f6Jaesung Chung    return static_cast<int16>(-0x8000);
31229345531d776962073312d423917406fc59b09f6Jaesung Chung  } else if (unsigned_value > 0x8000u) {
31329345531d776962073312d423917406fc59b09f6Jaesung Chung    return -static_cast<int16>(0x10000u - unsigned_value);
31429345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
31529345531d776962073312d423917406fc59b09f6Jaesung Chung    return static_cast<int16>(unsigned_value);
31629345531d776962073312d423917406fc59b09f6Jaesung Chung  }
31729345531d776962073312d423917406fc59b09f6Jaesung Chung}
31829345531d776962073312d423917406fc59b09f6Jaesung Chung
31929345531d776962073312d423917406fc59b09f6Jaesung Chunguint16 Get16u(const RangeCheckedBytePtr &input, const bool big_endian,
32029345531d776962073312d423917406fc59b09f6Jaesung Chung              MemoryStatus *status) {
32129345531d776962073312d423917406fc59b09f6Jaesung Chung  if (input.remainingLength() < 2) {
32229345531d776962073312d423917406fc59b09f6Jaesung Chung    if (status && *status == RANGE_CHECKED_BYTE_SUCCESS) {
32329345531d776962073312d423917406fc59b09f6Jaesung Chung      *status = RANGE_CHECKED_BYTE_ERROR;
32429345531d776962073312d423917406fc59b09f6Jaesung Chung    }
32529345531d776962073312d423917406fc59b09f6Jaesung Chung    // Return an arbitrary value.
32629345531d776962073312d423917406fc59b09f6Jaesung Chung    return 0;
32729345531d776962073312d423917406fc59b09f6Jaesung Chung  }
32829345531d776962073312d423917406fc59b09f6Jaesung Chung  if (big_endian) {
329a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer    return (static_cast<uint16>(input[0]) << 8) | static_cast<uint16>(input[1]);
33029345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
331a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer    return (static_cast<uint16>(input[1]) << 8) | static_cast<uint16>(input[0]);
33229345531d776962073312d423917406fc59b09f6Jaesung Chung  }
33329345531d776962073312d423917406fc59b09f6Jaesung Chung}
33429345531d776962073312d423917406fc59b09f6Jaesung Chung
33529345531d776962073312d423917406fc59b09f6Jaesung Chungint32 Get32s(const RangeCheckedBytePtr &input, const bool big_endian,
33629345531d776962073312d423917406fc59b09f6Jaesung Chung             MemoryStatus *status) {
33729345531d776962073312d423917406fc59b09f6Jaesung Chung  const uint32 unsigned_value = Get32u(input, big_endian, status);
33829345531d776962073312d423917406fc59b09f6Jaesung Chung  if (*status != RANGE_CHECKED_BYTE_SUCCESS) {
33929345531d776962073312d423917406fc59b09f6Jaesung Chung    // Return an arbitrary value.
34029345531d776962073312d423917406fc59b09f6Jaesung Chung    return 0;
34129345531d776962073312d423917406fc59b09f6Jaesung Chung  }
34229345531d776962073312d423917406fc59b09f6Jaesung Chung
34329345531d776962073312d423917406fc59b09f6Jaesung Chung  // Convert the two's-complement signed integer encoded in 'unsigned_value'
34429345531d776962073312d423917406fc59b09f6Jaesung Chung  // into a signed representation in the implementation's native representation
34529345531d776962073312d423917406fc59b09f6Jaesung Chung  // for signed integers.
34629345531d776962073312d423917406fc59b09f6Jaesung Chung  // For all practical purposes, the same result could be obtained simply by
34729345531d776962073312d423917406fc59b09f6Jaesung Chung  // casting unsigned_value to int32; the result of this is
34829345531d776962073312d423917406fc59b09f6Jaesung Chung  // implementation-defined, but on all of the platforms we care about, it does
34929345531d776962073312d423917406fc59b09f6Jaesung Chung  // what we want.
35029345531d776962073312d423917406fc59b09f6Jaesung Chung  // The code below, however, arguably has the aesthetic advantage of being
35129345531d776962073312d423917406fc59b09f6Jaesung Chung  // independent of the representation for signed integers chosen by the
35229345531d776962073312d423917406fc59b09f6Jaesung Chung  // implementation, as long as 'int' and 'unsigned' have the required range to
35329345531d776962073312d423917406fc59b09f6Jaesung Chung  // represent all of the required values.
35429345531d776962073312d423917406fc59b09f6Jaesung Chung  // An optimized Blaze build (x64) compiles all of the following code to a
35529345531d776962073312d423917406fc59b09f6Jaesung Chung  // no-op (as of this writing); i.e. the value that Get32u() returned in %eax
35629345531d776962073312d423917406fc59b09f6Jaesung Chung  // is left unchanged.
35729345531d776962073312d423917406fc59b09f6Jaesung Chung  if (unsigned_value == 0x80000000u) {
35829345531d776962073312d423917406fc59b09f6Jaesung Chung    // Read here on why the constant expression is written this way:
35929345531d776962073312d423917406fc59b09f6Jaesung Chung    // http://stackoverflow.com/questions/14695118
36029345531d776962073312d423917406fc59b09f6Jaesung Chung    return -0x7fffffff - 1;
36129345531d776962073312d423917406fc59b09f6Jaesung Chung  } else if (unsigned_value > 0x80000000u) {
36229345531d776962073312d423917406fc59b09f6Jaesung Chung    // The expression
36329345531d776962073312d423917406fc59b09f6Jaesung Chung    //   0xffffffffu - unsigned_value + 1
36429345531d776962073312d423917406fc59b09f6Jaesung Chung    // is a portable way of flipping the sign of a twos-complement signed
36529345531d776962073312d423917406fc59b09f6Jaesung Chung    // integer whose binary representation is stored in an unsigned integer.
36629345531d776962073312d423917406fc59b09f6Jaesung Chung    // '0xffffffffu + 1' is used in preference to simply '0' because it makes
36729345531d776962073312d423917406fc59b09f6Jaesung Chung    // it clearer that the correct result will be obtained even if an int is
36829345531d776962073312d423917406fc59b09f6Jaesung Chung    // greater than 32 bits. The '0xffffffffu + 1' is "spread out" around
36929345531d776962073312d423917406fc59b09f6Jaesung Chung    // 'unsigned_value' to prevent the compiler from warning about an
37029345531d776962073312d423917406fc59b09f6Jaesung Chung    // integral constant overflow. ('0' would produce the correct result in
37129345531d776962073312d423917406fc59b09f6Jaesung Chung    // this case too but would rely in a more subtle way on the rules for
37229345531d776962073312d423917406fc59b09f6Jaesung Chung    // unsigned wraparound.)
37329345531d776962073312d423917406fc59b09f6Jaesung Chung    return -static_cast<int32>(0xffffffffu - unsigned_value + 1);
37429345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
37529345531d776962073312d423917406fc59b09f6Jaesung Chung    return static_cast<int32>(unsigned_value);
37629345531d776962073312d423917406fc59b09f6Jaesung Chung  }
37729345531d776962073312d423917406fc59b09f6Jaesung Chung}
37829345531d776962073312d423917406fc59b09f6Jaesung Chung
37929345531d776962073312d423917406fc59b09f6Jaesung Chunguint32 Get32u(const RangeCheckedBytePtr &input, const bool big_endian,
38029345531d776962073312d423917406fc59b09f6Jaesung Chung              MemoryStatus *status) {
38129345531d776962073312d423917406fc59b09f6Jaesung Chung  if (input.remainingLength() < 4) {
38229345531d776962073312d423917406fc59b09f6Jaesung Chung    if (status && *status == RANGE_CHECKED_BYTE_SUCCESS) {
38329345531d776962073312d423917406fc59b09f6Jaesung Chung      *status = RANGE_CHECKED_BYTE_ERROR;
38429345531d776962073312d423917406fc59b09f6Jaesung Chung    }
38529345531d776962073312d423917406fc59b09f6Jaesung Chung    // Return an arbitrary value.
38629345531d776962073312d423917406fc59b09f6Jaesung Chung    return 0;
38729345531d776962073312d423917406fc59b09f6Jaesung Chung  }
38829345531d776962073312d423917406fc59b09f6Jaesung Chung  if (big_endian) {
389a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer    return (static_cast<uint32>(input[0]) << 24) |
390a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer           (static_cast<uint32>(input[1]) << 16) |
391a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer           (static_cast<uint32>(input[2]) << 8) |
392a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer           (static_cast<uint32>(input[3]) << 0);
39329345531d776962073312d423917406fc59b09f6Jaesung Chung  } else {
394a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer    return (static_cast<uint32>(input[3]) << 24) |
395a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer           (static_cast<uint32>(input[2]) << 16) |
396a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer           (static_cast<uint32>(input[1]) << 8) |
397a9540117cdd785b0dd75f8c4c28b278f86eb485cEik Brauer           (static_cast<uint32>(input[0]) << 0);
39829345531d776962073312d423917406fc59b09f6Jaesung Chung  }
39929345531d776962073312d423917406fc59b09f6Jaesung Chung}
40029345531d776962073312d423917406fc59b09f6Jaesung Chung
40129345531d776962073312d423917406fc59b09f6Jaesung Chung}  // namespace binary_parse
40229345531d776962073312d423917406fc59b09f6Jaesung Chung}  // namespace piex
403