1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef NVRAM_MESSAGES_MESSAGE_CODEC_H_ 18 #define NVRAM_MESSAGES_MESSAGE_CODEC_H_ 19 20 extern "C" { 21 #include <stddef.h> 22 #include <stdint.h> 23 } 24 25 #include <nvram/messages/compiler.h> 26 #include <nvram/messages/io.h> 27 28 namespace nvram { 29 namespace proto { 30 31 // |FieldDescriptor| describes a single proto field in a struct. We compile a 32 // table of field descriptors for each struct that needs to be encoded or 33 // decoded into the binary. See proto.hpp for the code that initializes the 34 // static tables. 35 struct FieldDescriptor { 36 // A function to encode a struct field in protobuf wire format. |object| is a 37 // pointer to the struct to read the value from, |writer| receives the output. 38 using EncodeFunction = bool(const void* object, ProtoWriter* writer); 39 40 // A function to encode a protobuf struct field from |reader|. The decoded 41 // data is stored in the struct instance pointed at by |object|. 42 using DecodeFunction = bool(void* object, ProtoReader* reader); 43 FieldDescriptorFieldDescriptor44 constexpr FieldDescriptor(uint32_t field_number, 45 WireType wire_type, 46 EncodeFunction* encode_function, 47 DecodeFunction* decode_function) 48 : field_number(field_number), 49 wire_type(wire_type), 50 encode_function(encode_function), 51 decode_function(decode_function) {} 52 53 uint32_t field_number; 54 WireType wire_type; 55 EncodeFunction* encode_function; 56 DecodeFunction* decode_function; 57 }; 58 59 // A table-driven protobuf message encoder. Takes a pointer to a C++ object to 60 // encode and a corresponding table of field descriptors. Provides functions to 61 // encode the message data in protobuf wire format. 62 class NVRAM_EXPORT MessageEncoderBase { 63 public: 64 // Initialize the encoder to encode |object|, using the descriptor table 65 // passed in |descriptors|. 66 MessageEncoderBase(const void* object, 67 const FieldDescriptor* descriptors, 68 size_t num_descriptors); 69 70 // Convenience helper that constructs an encoder instance and invokes 71 // |Encode()|. 72 static bool Encode(const void* object, 73 ProtoWriter* writer, 74 const FieldDescriptor* descriptors, 75 size_t num_descriptors); 76 77 // Returns the encoded size of the object. 78 size_t GetSize(); 79 80 // Encodes the object as a sequence of protobuf fields, wrapped in a 81 // length-delimited container. 82 bool Encode(ProtoWriter* writer); 83 84 // Encodes the object as a sequence of protobuf fields without any wrapping. 85 bool EncodeData(ProtoWriter* writer); 86 87 private: 88 // The pointer to the object to encode. This is a void pointer, so the encoder 89 // logic can be generic and doesn't need to be instantiated for every struct 90 // type. The encode function provided by the field descriptor will cast back 91 // to the correct type. 92 const void* object_; 93 94 // Field descriptor table. 95 const FieldDescriptor* descriptors_; 96 size_t num_descriptors_; 97 }; 98 99 // A protobuf message decoder, driven by a table of field descriptors. Consumes 100 // data from a |ProtoReader|, decodes fields per the descriptor table and stores 101 // it to a C++ object. 102 class NVRAM_EXPORT MessageDecoderBase { 103 public: 104 // Initialize a decoder to store field data according to the |descriptors| 105 // table in |object|. 106 MessageDecoderBase(void* object, 107 const FieldDescriptor* descriptors, 108 size_t num_descriptors); 109 110 // Convenience helper that constructs a decoder and invokes |Decode()|. 111 static bool Decode(void* object, 112 ProtoReader* reader, 113 const FieldDescriptor* descriptors, 114 size_t num_descriptors); 115 116 // Decode a nested protobuf message wrapped in a length-delimited protobuf 117 // field. 118 bool Decode(ProtoReader* reader); 119 120 // Decode a protobuf message from reader. This just reads the sequence of 121 // fields, not taking into account any wrapping. This is suitable for the 122 // topmost encoded message. 123 bool DecodeData(ProtoReader* reader); 124 125 private: 126 // Looks up the |FieldDescriptor| for decoding the next field. The descriptor 127 // must match the field number and wire type of the field. If no matching 128 // descriptor is found, |nullptr| is returned. 129 const FieldDescriptor* FindDescriptor(ProtoReader* reader) const; 130 131 // The object to decode to. This is a void pointer to keep the decoder generic 132 // and avoid type-specific code for each struct type. The decode function in 133 // the field descriptor casts back to the struct type. 134 void* object_; 135 136 // Descriptor table. 137 const FieldDescriptor* descriptors_; 138 size_t num_descriptors_; 139 }; 140 141 } // namespace proto 142 } // namespace nvram 143 144 #endif // NVRAM_MESSAGES_MESSAGE_CODEC_H_ 145