1259698Sdim//===- YAML.h - YAMLIO utilities for object files ---------------*- C++ -*-===// 2259698Sdim// 3259698Sdim// The LLVM Compiler Infrastructure 4259698Sdim// 5259698Sdim// This file is distributed under the University of Illinois Open Source 6259698Sdim// License. See LICENSE.TXT for details. 7259698Sdim// 8259698Sdim//===----------------------------------------------------------------------===// 9259698Sdim// 10259698Sdim// This file declares utility classes for handling the YAML representation of 11259698Sdim// object files. 12259698Sdim// 13259698Sdim//===----------------------------------------------------------------------===// 14259698Sdim 15259698Sdim#ifndef LLVM_OBJECT_YAML_H 16259698Sdim#define LLVM_OBJECT_YAML_H 17259698Sdim 18259698Sdim#include "llvm/Support/YAMLTraits.h" 19259698Sdim 20259698Sdimnamespace llvm { 21259698Sdimnamespace object { 22259698Sdimnamespace yaml { 23259698Sdim 24259698Sdim/// \brief Specialized YAMLIO scalar type for representing a binary blob. 25259698Sdim/// 26259698Sdim/// A typical use case would be to represent the content of a section in a 27259698Sdim/// binary file. 28259698Sdim/// This class has custom YAMLIO traits for convenient reading and writing. 29259698Sdim/// It renders as a string of hex digits in a YAML file. 30259698Sdim/// For example, it might render as `DEADBEEFCAFEBABE` (YAML does not 31259698Sdim/// require the quotation marks, so for simplicity when outputting they are 32259698Sdim/// omitted). 33259698Sdim/// When reading, any string whose content is an even number of hex digits 34259698Sdim/// will be accepted. 35259698Sdim/// For example, all of the following are acceptable: 36259698Sdim/// `DEADBEEF`, `"DeADbEeF"`, `"\x44EADBEEF"` (Note: '\x44' == 'D') 37259698Sdim/// 38259698Sdim/// A significant advantage of using this class is that it never allocates 39259698Sdim/// temporary strings or buffers for any of its functionality. 40259698Sdim/// 41259698Sdim/// Example: 42259698Sdim/// 43259698Sdim/// The YAML mapping: 44259698Sdim/// \code 45259698Sdim/// Foo: DEADBEEFCAFEBABE 46259698Sdim/// \endcode 47259698Sdim/// 48259698Sdim/// Could be modeled in YAMLIO by the struct: 49259698Sdim/// \code 50259698Sdim/// struct FooHolder { 51259698Sdim/// BinaryRef Foo; 52259698Sdim/// }; 53259698Sdim/// namespace llvm { 54259698Sdim/// namespace yaml { 55259698Sdim/// template <> 56259698Sdim/// struct MappingTraits<FooHolder> { 57259698Sdim/// static void mapping(IO &IO, FooHolder &FH) { 58259698Sdim/// IO.mapRequired("Foo", FH.Foo); 59259698Sdim/// } 60259698Sdim/// }; 61259698Sdim/// } // end namespace yaml 62259698Sdim/// } // end namespace llvm 63259698Sdim/// \endcode 64259698Sdimclass BinaryRef { 65259698Sdim friend bool operator==(const BinaryRef &LHS, const BinaryRef &RHS); 66259698Sdim /// \brief Either raw binary data, or a string of hex bytes (must always 67259698Sdim /// be an even number of characters). 68259698Sdim ArrayRef<uint8_t> Data; 69259698Sdim /// \brief Discriminator between the two states of the `Data` member. 70259698Sdim bool DataIsHexString; 71259698Sdim 72259698Sdimpublic: 73259698Sdim BinaryRef(ArrayRef<uint8_t> Data) : Data(Data), DataIsHexString(false) {} 74259698Sdim BinaryRef(StringRef Data) 75259698Sdim : Data(reinterpret_cast<const uint8_t *>(Data.data()), Data.size()), 76259698Sdim DataIsHexString(true) {} 77259698Sdim BinaryRef() : DataIsHexString(true) {} 78259698Sdim /// \brief The number of bytes that are represented by this BinaryRef. 79259698Sdim /// This is the number of bytes that writeAsBinary() will write. 80259698Sdim ArrayRef<uint8_t>::size_type binary_size() const { 81259698Sdim if (DataIsHexString) 82259698Sdim return Data.size() / 2; 83259698Sdim return Data.size(); 84259698Sdim } 85259698Sdim /// \brief Write the contents (regardless of whether it is binary or a 86259698Sdim /// hex string) as binary to the given raw_ostream. 87259698Sdim void writeAsBinary(raw_ostream &OS) const; 88259698Sdim /// \brief Write the contents (regardless of whether it is binary or a 89259698Sdim /// hex string) as hex to the given raw_ostream. 90259698Sdim /// 91259698Sdim /// For example, a possible output could be `DEADBEEFCAFEBABE`. 92259698Sdim void writeAsHex(raw_ostream &OS) const; 93259698Sdim}; 94259698Sdim 95259698Sdiminline bool operator==(const BinaryRef &LHS, const BinaryRef &RHS) { 96259698Sdim // Special case for default constructed BinaryRef. 97259698Sdim if (LHS.Data.empty() && RHS.Data.empty()) 98259698Sdim return true; 99259698Sdim 100259698Sdim return LHS.DataIsHexString == RHS.DataIsHexString && LHS.Data == RHS.Data; 101259698Sdim} 102259698Sdim 103259698Sdim} 104259698Sdim} 105259698Sdim 106259698Sdimnamespace yaml { 107259698Sdimtemplate <> struct ScalarTraits<object::yaml::BinaryRef> { 108259698Sdim static void output(const object::yaml::BinaryRef &, void *, 109259698Sdim llvm::raw_ostream &); 110259698Sdim static StringRef input(StringRef, void *, object::yaml::BinaryRef &); 111259698Sdim}; 112259698Sdim} 113259698Sdim 114259698Sdim} 115259698Sdim 116259698Sdim#endif 117