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