1 //===- YAML.h ---------------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_OBJECTYAML_YAML_H 10 #define LLVM_OBJECTYAML_YAML_H 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/Support/YAMLTraits.h" 15 #include <cstdint> 16 17 namespace llvm { 18 19 class raw_ostream; 20 21 namespace yaml { 22 23 /// Specialized YAMLIO scalar type for representing a binary blob. 24 /// 25 /// A typical use case would be to represent the content of a section in a 26 /// binary file. 27 /// This class has custom YAMLIO traits for convenient reading and writing. 28 /// It renders as a string of hex digits in a YAML file. 29 /// For example, it might render as `DEADBEEFCAFEBABE` (YAML does not 30 /// require the quotation marks, so for simplicity when outputting they are 31 /// omitted). 32 /// When reading, any string whose content is an even number of hex digits 33 /// will be accepted. 34 /// For example, all of the following are acceptable: 35 /// `DEADBEEF`, `"DeADbEeF"`, `"\x44EADBEEF"` (Note: '\x44' == 'D') 36 /// 37 /// A significant advantage of using this class is that it never allocates 38 /// temporary strings or buffers for any of its functionality. 39 /// 40 /// Example: 41 /// 42 /// The YAML mapping: 43 /// \code 44 /// Foo: DEADBEEFCAFEBABE 45 /// \endcode 46 /// 47 /// Could be modeled in YAMLIO by the struct: 48 /// \code 49 /// struct FooHolder { 50 /// BinaryRef Foo; 51 /// }; 52 /// namespace llvm { 53 /// namespace yaml { 54 /// template <> 55 /// struct MappingTraits<FooHolder> { 56 /// static void mapping(IO &IO, FooHolder &FH) { 57 /// IO.mapRequired("Foo", FH.Foo); 58 /// } 59 /// }; 60 /// } // end namespace yaml 61 /// } // end namespace llvm 62 /// \endcode 63 class BinaryRef { 64 friend bool operator==(const BinaryRef &LHS, const BinaryRef &RHS); 65 66 /// Either raw binary data, or a string of hex bytes (must always 67 /// be an even number of characters). 68 ArrayRef<uint8_t> Data; 69 70 /// Discriminator between the two states of the `Data` member. 71 bool DataIsHexString = true; 72 73 public: 74 BinaryRef() = default; BinaryRef(ArrayRef<uint8_t> Data)75 BinaryRef(ArrayRef<uint8_t> Data) : Data(Data), DataIsHexString(false) {} BinaryRef(StringRef Data)76 BinaryRef(StringRef Data) : Data(arrayRefFromStringRef(Data)) {} 77 78 /// The number of bytes that are represented by this BinaryRef. 79 /// This is the number of bytes that writeAsBinary() will write. binary_size()80 ArrayRef<uint8_t>::size_type binary_size() const { 81 if (DataIsHexString) 82 return Data.size() / 2; 83 return Data.size(); 84 } 85 86 /// Write the contents (regardless of whether it is binary or a 87 /// hex string) as binary to the given raw_ostream. 88 /// N can be used to specify the maximum number of bytes. 89 void writeAsBinary(raw_ostream &OS, uint64_t N = UINT64_MAX) const; 90 91 /// Write the contents (regardless of whether it is binary or a 92 /// hex string) as hex to the given raw_ostream. 93 /// 94 /// For example, a possible output could be `DEADBEEFCAFEBABE`. 95 void writeAsHex(raw_ostream &OS) const; 96 }; 97 98 inline bool operator==(const BinaryRef &LHS, const BinaryRef &RHS) { 99 // Special case for default constructed BinaryRef. 100 if (LHS.Data.empty() && RHS.Data.empty()) 101 return true; 102 103 return LHS.DataIsHexString == RHS.DataIsHexString && LHS.Data == RHS.Data; 104 } 105 106 template <> struct ScalarTraits<BinaryRef> { 107 static void output(const BinaryRef &, void *, raw_ostream &); 108 static StringRef input(StringRef, void *, BinaryRef &); 109 static QuotingType mustQuote(StringRef S) { return needsQuotes(S); } 110 }; 111 112 } // end namespace yaml 113 114 } // end namespace llvm 115 116 #endif // LLVM_OBJECTYAML_YAML_H 117