big_endian.h 2.9 KB
Newer Older
gejun's avatar
gejun committed
1 2 3 4
// 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.

5 6
#ifndef BUTIL_BIG_ENDIAN_H_
#define BUTIL_BIG_ENDIAN_H_
gejun's avatar
gejun committed
7

8 9 10
#include "butil/base_export.h"
#include "butil/basictypes.h"
#include "butil/strings/string_piece.h"
gejun's avatar
gejun committed
11

12
namespace butil {
gejun's avatar
gejun committed
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

// Read an integer (signed or unsigned) from |buf| in Big Endian order.
// Note: this loop is unrolled with -O1 and above.
// NOTE(szym): glibc dns-canon.c and SpdyFrameBuilder use
// ntohs(*(uint16_t*)ptr) which is potentially unaligned.
// This would cause SIGBUS on ARMv5 or earlier and ARMv6-M.
template<typename T>
inline void ReadBigEndian(const char buf[], T* out) {
  *out = buf[0];
  for (size_t i = 1; i < sizeof(T); ++i) {
    *out <<= 8;
    // Must cast to uint8_t to avoid clobbering by sign extension.
    *out |= static_cast<uint8_t>(buf[i]);
  }
}

// Write an integer (signed or unsigned) |val| to |buf| in Big Endian order.
// Note: this loop is unrolled with -O1 and above.
template<typename T>
inline void WriteBigEndian(char buf[], T val) {
  for (size_t i = 0; i < sizeof(T); ++i) {
    buf[sizeof(T)-i-1] = static_cast<char>(val & 0xFF);
    val >>= 8;
  }
}

// Specializations to make clang happy about the (dead code) shifts above.
template<>
inline void ReadBigEndian<uint8_t>(const char buf[], uint8_t* out) {
  *out = buf[0];
}

template<>
inline void WriteBigEndian<uint8_t>(char buf[], uint8_t val) {
  buf[0] = static_cast<char>(val);
}

// Allows reading integers in network order (big endian) while iterating over
// an underlying buffer. All the reading functions advance the internal pointer.
52
class BUTIL_EXPORT BigEndianReader {
gejun's avatar
gejun committed
53 54 55 56 57 58 59 60 61
 public:
  BigEndianReader(const char* buf, size_t len);

  const char* ptr() const { return ptr_; }
  int remaining() const { return end_ - ptr_; }

  bool Skip(size_t len);
  bool ReadBytes(void* out, size_t len);
  // Creates a StringPiece in |out| that points to the underlying buffer.
62
  bool ReadPiece(butil::StringPiece* out, size_t len);
gejun's avatar
gejun committed
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
  bool ReadU8(uint8_t* value);
  bool ReadU16(uint16_t* value);
  bool ReadU32(uint32_t* value);

 private:
  // Hidden to promote type safety.
  template<typename T>
  bool Read(T* v);

  const char* ptr_;
  const char* end_;
};

// Allows writing integers in network order (big endian) while iterating over
// an underlying buffer. All the writing functions advance the internal pointer.
78
class BUTIL_EXPORT BigEndianWriter {
gejun's avatar
gejun committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
 public:
  BigEndianWriter(char* buf, size_t len);

  char* ptr() const { return ptr_; }
  int remaining() const { return end_ - ptr_; }

  bool Skip(size_t len);
  bool WriteBytes(const void* buf, size_t len);
  bool WriteU8(uint8_t value);
  bool WriteU16(uint16_t value);
  bool WriteU32(uint32_t value);

 private:
  // Hidden to promote type safety.
  template<typename T>
  bool Write(T v);

  char* ptr_;
  char* end_;
};

100
}  // namespace butil
gejun's avatar
gejun committed
101

102
#endif  // BUTIL_BIG_ENDIAN_H_