blob: 6731b0c0600afd22f623141252b7e2b58d413061 [file] [log] [blame]
// Copyright 2015 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.
#ifndef NET_DER_INPUT_H_
#define NET_DER_INPUT_H_
#include <stdint.h>
#include <string>
#include "base/compiler_specific.h"
#include "net/base/net_export.h"
namespace net {
namespace der {
class Mark;
// An opaque class that represents a fixed buffer of data of a fixed length,
// to be used as an input to other operations. An Input object does not own
// the data it references, so callers are responsible for making sure that
// the data outlives the Input object and any other associated objects.
//
// All data access for an Input should be done through the ByteReader and Mark
// classes. This class and associated classes are designed with safety in mind
// to make it difficult to read memory outside of an Input. ByteReader provides
// a simple API for reading through the Input sequentially. For more
// complicated uses, multiple instances of a ByteReader for a particular Input
// can be created, and instances of Mark can be used to coordinate between the
// ByteReaders.
//
// One such use case of multiple ByteReaders would be looking ahead in an
// input: A ByteReader is copied and then is used to read some number of
// bytes into the input, based on the content it is reading. A Mark can then be
// set using the temporary ByteReader to indicate how far it read into the
// Input. The original ByteReader can then be synchronized with how far the
// temporary ByteReader read, by using either AdvanceToMark() or ReadToMark().
class NET_EXPORT_PRIVATE Input {
public:
// Creates an empty Input, one from which no data can be read.
Input();
// Creates an Input from a constant array |data|.
template <size_t N>
explicit Input(const uint8_t(&data)[N])
: data_(data), len_(N) {}
// Creates an Input from the given |data| and |len|.
Input(const uint8_t* data, size_t len);
// Creates an Input from the given string |s|.
explicit Input(const std::string& s);
// Returns the length in bytes of an Input's data.
size_t Length() const { return len_; }
// Return true if the Input's data and |other|'s data are byte-wise equal.
bool Equals(const Input& other) const;
// Returns a pointer to the Input's data. This method is marked as "unsafe"
// because access to the Input's data should be done through ByteReader
// instead. This method should only be used where using a ByteReader truly
// is not an option.
const uint8_t* UnsafeData() const { return data_; }
private:
const uint8_t* data_;
size_t len_;
};
// This class provides ways to read data from an Input in a bounds-checked way.
// The ByteReader is designed to read through the input sequentially. Once a
// byte has been read with a ByteReader, the caller can't go back and re-read
// that byte with the same reader. Of course, the caller can create multiple
// ByteReaders for the same input (or copy an existing ByteReader).
//
// For something simple like a single byte lookahead, the easiest way to do
// that is to copy the ByteReader and call ReadByte() on the copy - the original
// ByteReader will be unaffected and the peeked byte will be read through
// ReadByte(). For other read patterns, it can be useful to mark where one is
// in a ByteReader to be able to return to that spot.
//
// Some operations using Mark can also be done by creating a copy of the
// ByteReader. By using a Mark instead, you use less memory, but more
// importantly, you end up with an immutable object that matches the semantics
// of what is intended.
class NET_EXPORT_PRIVATE ByteReader {
public:
// Creates a ByteReader to read the data represented by an Input.
explicit ByteReader(const Input& in);
// Reads a single byte from the input source, putting the byte read in
// |*byte_p|. If a byte cannot be read from the input (because there is
// no input left), then this method returns false.
bool ReadByte(uint8_t* out) WARN_UNUSED_RESULT;
// Reads |len| bytes from the input source, and initializes an Input to
// point to that data. If there aren't enough bytes left in the input source,
// then this method returns false.
bool ReadBytes(size_t len, Input* out) WARN_UNUSED_RESULT;
// Returns how many bytes are left to read.
size_t BytesLeft() const { return len_; }
// Returns whether there is any more data to be read.
bool HasMore();
// Creates a new Mark at the current position of this ByteReader. If another
// ByteReader is advanced to this mark, the next byte read by the other
// ByteReader will be the same as the next byte read by this ByteReader.
Mark NewMark();
// Advances this ByteReader to the position marked by |mark|. Note that
// a ByteReader can only advance forward - it is not possible to "rewind"
// to a previous mark. To do this, one would need to create a new ByteReader
// (from the same input) and AdvanceToMark() on the new ByteReader.
//
// If it is not possible to advance this ByteReader to the mark, this method
// returns false and does nothing.
bool AdvanceToMark(Mark mark) WARN_UNUSED_RESULT;
// Reads all data from the cursor of this ByteReader up to the mark, and
// initializes an Input to point to that data. If the Mark is not valid for
// this ByteReader, then this method returns false and does not modify |*out|.
bool ReadToMark(Mark mark, Input* out) WARN_UNUSED_RESULT;
private:
void Advance(size_t len);
const uint8_t* data_;
size_t len_;
};
// An immutable opaque pointer into the data represented by an Input. A Mark
// object is used to save and restore the state (position) of a ByteReader to
// allow for lookahead or backtracking. All interaction with a Mark object is
// done through the ByteReader class.
class NET_EXPORT_PRIVATE Mark {
public:
// Creates a null Mark. This Mark will not be usable with any ByteReader.
// This only exists so that a class can have a Mark member which may or may
// not be a valid Mark at any given time.
static Mark NullMark();
// Checks whether a given Mark is an empty Mark.
bool IsEmpty();
friend class ByteReader;
private:
explicit Mark(const uint8_t* ptr);
Mark();
const uint8_t* ptr_;
};
} // namespace der
} // namespace net
#endif // NET_DER_INPUT_H_