// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "quiche/spdy/core/spdy_prefixed_buffer_reader.h"

#include <new>

#include "quiche/common/platform/api/quiche_logging.h"

namespace spdy {

SpdyPrefixedBufferReader::SpdyPrefixedBufferReader(const char* prefix,
                                                   size_t prefix_length,
                                                   const char* suffix,
                                                   size_t suffix_length)
    : prefix_(prefix),
      suffix_(suffix),
      prefix_length_(prefix_length),
      suffix_length_(suffix_length) {}

size_t SpdyPrefixedBufferReader::Available() {
  return prefix_length_ + suffix_length_;
}

bool SpdyPrefixedBufferReader::ReadN(size_t count, char* out) {
  if (Available() < count) {
    return false;
  }

  if (prefix_length_ >= count) {
    // Read is fully satisfied by the prefix.
    std::copy(prefix_, prefix_ + count, out);
    prefix_ += count;
    prefix_length_ -= count;
    return true;
  } else if (prefix_length_ != 0) {
    // Read is partially satisfied by the prefix.
    out = std::copy(prefix_, prefix_ + prefix_length_, out);
    count -= prefix_length_;
    prefix_length_ = 0;
    // Fallthrough to suffix read.
  }
  QUICHE_DCHECK(suffix_length_ >= count);
  // Read is satisfied by the suffix.
  std::copy(suffix_, suffix_ + count, out);
  suffix_ += count;
  suffix_length_ -= count;
  return true;
}

bool SpdyPrefixedBufferReader::ReadN(size_t count,
                                     SpdyPinnableBufferPiece* out) {
  if (Available() < count) {
    return false;
  }

  out->storage_.reset();
  out->length_ = count;

  if (prefix_length_ >= count) {
    // Read is fully satisfied by the prefix.
    out->buffer_ = prefix_;
    prefix_ += count;
    prefix_length_ -= count;
    return true;
  } else if (prefix_length_ != 0) {
    // Read is only partially satisfied by the prefix. We need to allocate
    // contiguous storage as the read spans the prefix & suffix.
    out->storage_.reset(new char[count]);
    out->buffer_ = out->storage_.get();
    ReadN(count, out->storage_.get());
    return true;
  } else {
    QUICHE_DCHECK(suffix_length_ >= count);
    // Read is fully satisfied by the suffix.
    out->buffer_ = suffix_;
    suffix_ += count;
    suffix_length_ -= count;
    return true;
  }
}

}  // namespace spdy
