// 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 "net/spdy/spdy_prefixed_buffer_reader.h"

#include "base/logging.h"

namespace net {

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.
  }
  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 {
    DCHECK(suffix_length_ >= count);
    // Read is fully satisfied by the suffix.
    out->buffer_ = suffix_;
    suffix_ += count;
    suffix_length_ -= count;
    return true;
  }
}

}  // namespace net