1*7ba4dab5SXin Li /*
2*7ba4dab5SXin Li * Copyright (C) 2016 The Android Open Source Project
3*7ba4dab5SXin Li *
4*7ba4dab5SXin Li * Licensed under the Apache License, Version 2.0 (the "License");
5*7ba4dab5SXin Li * you may not use this file except in compliance with the License.
6*7ba4dab5SXin Li * You may obtain a copy of the License at
7*7ba4dab5SXin Li *
8*7ba4dab5SXin Li * http://www.apache.org/licenses/LICENSE-2.0
9*7ba4dab5SXin Li *
10*7ba4dab5SXin Li * Unless required by applicable law or agreed to in writing, software
11*7ba4dab5SXin Li * distributed under the License is distributed on an "AS IS" BASIS,
12*7ba4dab5SXin Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*7ba4dab5SXin Li * See the License for the specific language governing permissions and
14*7ba4dab5SXin Li * limitations under the License.
15*7ba4dab5SXin Li */
16*7ba4dab5SXin Li
17*7ba4dab5SXin Li #include <nvram/messages/message_codec.h>
18*7ba4dab5SXin Li
19*7ba4dab5SXin Li namespace nvram {
20*7ba4dab5SXin Li namespace proto {
21*7ba4dab5SXin Li
MessageEncoderBase(const void * object,const FieldDescriptor * descriptors,size_t num_descriptors)22*7ba4dab5SXin Li MessageEncoderBase::MessageEncoderBase(const void* object,
23*7ba4dab5SXin Li const FieldDescriptor* descriptors,
24*7ba4dab5SXin Li size_t num_descriptors)
25*7ba4dab5SXin Li : object_(object),
26*7ba4dab5SXin Li descriptors_(descriptors),
27*7ba4dab5SXin Li num_descriptors_(num_descriptors) {}
28*7ba4dab5SXin Li
Encode(const void * object,ProtoWriter * writer,const FieldDescriptor * descriptors,size_t num_descriptors)29*7ba4dab5SXin Li bool MessageEncoderBase::Encode(const void* object,
30*7ba4dab5SXin Li ProtoWriter* writer,
31*7ba4dab5SXin Li const FieldDescriptor* descriptors,
32*7ba4dab5SXin Li size_t num_descriptors) {
33*7ba4dab5SXin Li MessageEncoderBase encoder(object, descriptors, num_descriptors);
34*7ba4dab5SXin Li return encoder.Encode(writer);
35*7ba4dab5SXin Li }
36*7ba4dab5SXin Li
GetSize()37*7ba4dab5SXin Li size_t MessageEncoderBase::GetSize() {
38*7ba4dab5SXin Li CountingOutputStreamBuffer counting_stream;
39*7ba4dab5SXin Li ProtoWriter writer(&counting_stream);
40*7ba4dab5SXin Li return EncodeData(&writer) ? counting_stream.bytes_written() : 0;
41*7ba4dab5SXin Li }
42*7ba4dab5SXin Li
Encode(ProtoWriter * writer)43*7ba4dab5SXin Li bool MessageEncoderBase::Encode(ProtoWriter* writer) {
44*7ba4dab5SXin Li // We need to compute the total size of all struct fields up front in order to
45*7ba4dab5SXin Li // write a length delimiter that designates the end of the encoded nested
46*7ba4dab5SXin Li // message. Note that computing the size of |object| requires a second
47*7ba4dab5SXin Li // |EncodeData()| call in addition to the one that actually encodes the data.
48*7ba4dab5SXin Li // When handling nested message structures, each level triggers its own size
49*7ba4dab5SXin Li // computation, which are redundant with those performed by the levels above.
50*7ba4dab5SXin Li //
51*7ba4dab5SXin Li // For now, we just accept this inefficiency in the interest of keeping things
52*7ba4dab5SXin Li // simple and correct. If this ever becomes a performance problem for deeply
53*7ba4dab5SXin Li // nested structs here are some options:
54*7ba4dab5SXin Li // * Reserve bytes in |writer| for the encoded size. Once |Encode()|
55*7ba4dab5SXin Li // completes, it is known how many bytes were required, at which point the
56*7ba4dab5SXin Li // size field can be updated. The drawback with this solution is that
57*7ba4dab5SXin Li // varint encoding is variable length, so we'd have to write a degenerated
58*7ba4dab5SXin Li // varint that may occupy more bytes than actually required.
59*7ba4dab5SXin Li // * Cache encoded sizes in the struct. This is the solution implemented in
60*7ba4dab5SXin Li // the regular protobuf implementation. This is relatively straightforward,
61*7ba4dab5SXin Li // but at the expense of holding data in struct that doesn't really belong
62*7ba4dab5SXin Li // there.
63*7ba4dab5SXin Li // * Make a first pass over the struct tree, compute sizes and cache them in
64*7ba4dab5SXin Li // some auxiliary data structure held in the encoder. This is probably the
65*7ba4dab5SXin Li // cleanest solution, but comes at the expense of having to thread the size
66*7ba4dab5SXin Li // cache data structure through the encoding logic.
67*7ba4dab5SXin Li return writer->WriteLengthHeader(GetSize()) && EncodeData(writer);
68*7ba4dab5SXin Li }
69*7ba4dab5SXin Li
EncodeData(ProtoWriter * writer)70*7ba4dab5SXin Li bool MessageEncoderBase::EncodeData(ProtoWriter* writer) {
71*7ba4dab5SXin Li for (size_t i = 0; i < num_descriptors_; ++i) {
72*7ba4dab5SXin Li const FieldDescriptor& desc = descriptors_[i];
73*7ba4dab5SXin Li writer->set_field_number(desc.field_number);
74*7ba4dab5SXin Li if (!desc.encode_function(object_, writer)) {
75*7ba4dab5SXin Li return false;
76*7ba4dab5SXin Li }
77*7ba4dab5SXin Li }
78*7ba4dab5SXin Li
79*7ba4dab5SXin Li return true;
80*7ba4dab5SXin Li }
81*7ba4dab5SXin Li
MessageDecoderBase(void * object,const FieldDescriptor * descriptors,size_t num_descriptors)82*7ba4dab5SXin Li MessageDecoderBase::MessageDecoderBase(void* object,
83*7ba4dab5SXin Li const FieldDescriptor* descriptors,
84*7ba4dab5SXin Li size_t num_descriptors)
85*7ba4dab5SXin Li : object_(object),
86*7ba4dab5SXin Li descriptors_(descriptors),
87*7ba4dab5SXin Li num_descriptors_(num_descriptors) {}
88*7ba4dab5SXin Li
Decode(void * object,ProtoReader * reader,const FieldDescriptor * descriptors,size_t num_descriptors)89*7ba4dab5SXin Li bool MessageDecoderBase::Decode(void* object,
90*7ba4dab5SXin Li ProtoReader* reader,
91*7ba4dab5SXin Li const FieldDescriptor* descriptors,
92*7ba4dab5SXin Li size_t num_descriptors) {
93*7ba4dab5SXin Li MessageDecoderBase decoder(object, descriptors, num_descriptors);
94*7ba4dab5SXin Li return decoder.Decode(reader);
95*7ba4dab5SXin Li }
96*7ba4dab5SXin Li
Decode(ProtoReader * reader)97*7ba4dab5SXin Li bool MessageDecoderBase::Decode(ProtoReader* reader) {
98*7ba4dab5SXin Li NestedInputStreamBuffer nested_stream_buffer(reader->stream_buffer(),
99*7ba4dab5SXin Li reader->field_size());
100*7ba4dab5SXin Li ProtoReader nested_reader(&nested_stream_buffer);
101*7ba4dab5SXin Li return DecodeData(&nested_reader) && nested_reader.Done();
102*7ba4dab5SXin Li }
103*7ba4dab5SXin Li
DecodeData(ProtoReader * reader)104*7ba4dab5SXin Li bool MessageDecoderBase::DecodeData(ProtoReader* reader) {
105*7ba4dab5SXin Li while (!reader->Done()) {
106*7ba4dab5SXin Li if (!reader->ReadWireTag()) {
107*7ba4dab5SXin Li return false;
108*7ba4dab5SXin Li }
109*7ba4dab5SXin Li const FieldDescriptor* desc = FindDescriptor(reader);
110*7ba4dab5SXin Li if (desc) {
111*7ba4dab5SXin Li if (!desc->decode_function(object_, reader)) {
112*7ba4dab5SXin Li return false;
113*7ba4dab5SXin Li }
114*7ba4dab5SXin Li } else {
115*7ba4dab5SXin Li // Unknown field number or wire type mismatch. Skip field data.
116*7ba4dab5SXin Li if (!reader->SkipField()) {
117*7ba4dab5SXin Li return false;
118*7ba4dab5SXin Li }
119*7ba4dab5SXin Li }
120*7ba4dab5SXin Li }
121*7ba4dab5SXin Li
122*7ba4dab5SXin Li return true;
123*7ba4dab5SXin Li }
124*7ba4dab5SXin Li
FindDescriptor(ProtoReader * reader) const125*7ba4dab5SXin Li const FieldDescriptor* MessageDecoderBase::FindDescriptor(
126*7ba4dab5SXin Li ProtoReader* reader) const {
127*7ba4dab5SXin Li for (size_t i = 0; i < num_descriptors_; ++i) {
128*7ba4dab5SXin Li const FieldDescriptor& desc = descriptors_[i];
129*7ba4dab5SXin Li if (reader->field_number() == desc.field_number &&
130*7ba4dab5SXin Li reader->wire_type() == desc.wire_type) {
131*7ba4dab5SXin Li return &desc;
132*7ba4dab5SXin Li }
133*7ba4dab5SXin Li }
134*7ba4dab5SXin Li return nullptr;
135*7ba4dab5SXin Li }
136*7ba4dab5SXin Li
137*7ba4dab5SXin Li } // namespace proto
138*7ba4dab5SXin Li } // namespace nvram
139