1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// Authors: wink@google.com (Wink Saville),
32//          kenton@google.com (Kenton Varda)
33//  Based on original Protocol Buffers design by
34//  Sanjay Ghemawat, Jeff Dean, and others.
35
36#include <google/protobuf/message_lite.h>
37#include <string>
38#include <google/protobuf/stubs/common.h>
39#include <google/protobuf/io/coded_stream.h>
40#include <google/protobuf/io/zero_copy_stream_impl.h>
41#include <google/protobuf/stubs/stl_util-inl.h>
42
43namespace google {
44namespace protobuf {
45
46MessageLite::~MessageLite() {}
47
48string MessageLite::InitializationErrorString() const {
49  return "(cannot determine missing fields for lite message)";
50}
51
52namespace {
53
54// When serializing, we first compute the byte size, then serialize the message.
55// If serialization produces a different number of bytes than expected, we
56// call this function, which crashes.  The problem could be due to a bug in the
57// protobuf implementation but is more likely caused by concurrent modification
58// of the message.  This function attempts to distinguish between the two and
59// provide a useful error message.
60void ByteSizeConsistencyError(int byte_size_before_serialization,
61                              int byte_size_after_serialization,
62                              int bytes_produced_by_serialization) {
63  GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
64      << "Protocol message was modified concurrently during serialization.";
65  GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
66      << "Byte size calculation and serialization were inconsistent.  This "
67         "may indicate a bug in protocol buffers or it may be caused by "
68         "concurrent modification of the message.";
69  GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
70}
71
72string InitializationErrorMessage(const char* action,
73                                  const MessageLite& message) {
74  // Note:  We want to avoid depending on strutil in the lite library, otherwise
75  //   we'd use:
76  //
77  // return strings::Substitute(
78  //   "Can't $0 message of type \"$1\" because it is missing required "
79  //   "fields: $2",
80  //   action, message.GetTypeName(),
81  //   message.InitializationErrorString());
82
83  string result;
84  result += "Can't ";
85  result += action;
86  result += " message of type \"";
87  result += message.GetTypeName();
88  result += "\" because it is missing required fields: ";
89  result += message.InitializationErrorString();
90  return result;
91}
92
93// Several of the Parse methods below just do one thing and then call another
94// method.  In a naive implementation, we might have ParseFromString() call
95// ParseFromArray() which would call ParseFromZeroCopyStream() which would call
96// ParseFromCodedStream() which would call MergeFromCodedStream() which would
97// call MergePartialFromCodedStream().  However, when parsing very small
98// messages, every function call introduces significant overhead.  To avoid
99// this without reproducing code, we use these forced-inline helpers.
100//
101// Note:  GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not
102//   definitions.
103inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
104                                       MessageLite* message)
105                                       GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
106inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
107                                       MessageLite* message)
108                                       GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
109inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
110                                              MessageLite* message)
111                                              GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
112inline bool InlineParseFromArray(const void* data, int size,
113                                 MessageLite* message)
114                                 GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
115inline bool InlineParsePartialFromArray(const void* data, int size,
116                                        MessageLite* message)
117                                        GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
118
119bool InlineMergeFromCodedStream(io::CodedInputStream* input,
120                                MessageLite* message) {
121  if (!message->MergePartialFromCodedStream(input)) return false;
122  if (!message->IsInitialized()) {
123    GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
124    return false;
125  }
126  return true;
127}
128
129bool InlineParseFromCodedStream(io::CodedInputStream* input,
130                                MessageLite* message) {
131  message->Clear();
132  return InlineMergeFromCodedStream(input, message);
133}
134
135bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
136                                       MessageLite* message) {
137  message->Clear();
138  return message->MergePartialFromCodedStream(input);
139}
140
141bool InlineParseFromArray(const void* data, int size, MessageLite* message) {
142  io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
143  return InlineParseFromCodedStream(&input, message) &&
144         input.ConsumedEntireMessage();
145}
146
147bool InlineParsePartialFromArray(const void* data, int size,
148                                 MessageLite* message) {
149  io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
150  return InlineParsePartialFromCodedStream(&input, message) &&
151         input.ConsumedEntireMessage();
152}
153
154}  // namespace
155
156bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
157  return InlineMergeFromCodedStream(input, this);
158}
159
160bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
161  return InlineParseFromCodedStream(input, this);
162}
163
164bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
165  return InlineParsePartialFromCodedStream(input, this);
166}
167
168bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
169  io::CodedInputStream decoder(input);
170  return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
171}
172
173bool MessageLite::ParsePartialFromZeroCopyStream(
174    io::ZeroCopyInputStream* input) {
175  io::CodedInputStream decoder(input);
176  return ParsePartialFromCodedStream(&decoder) &&
177         decoder.ConsumedEntireMessage();
178}
179
180bool MessageLite::ParseFromBoundedZeroCopyStream(
181    io::ZeroCopyInputStream* input, int size) {
182  io::CodedInputStream decoder(input);
183  decoder.PushLimit(size);
184  return ParseFromCodedStream(&decoder) &&
185         decoder.ConsumedEntireMessage() &&
186         decoder.BytesUntilLimit() == 0;
187}
188
189bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
190    io::ZeroCopyInputStream* input, int size) {
191  io::CodedInputStream decoder(input);
192  decoder.PushLimit(size);
193  return ParsePartialFromCodedStream(&decoder) &&
194         decoder.ConsumedEntireMessage() &&
195         decoder.BytesUntilLimit() == 0;
196}
197
198bool MessageLite::ParseFromString(const string& data) {
199  return InlineParseFromArray(data.data(), data.size(), this);
200}
201
202bool MessageLite::ParsePartialFromString(const string& data) {
203  return InlineParsePartialFromArray(data.data(), data.size(), this);
204}
205
206bool MessageLite::ParseFromArray(const void* data, int size) {
207  return InlineParseFromArray(data, size, this);
208}
209
210bool MessageLite::ParsePartialFromArray(const void* data, int size) {
211  return InlineParsePartialFromArray(data, size, this);
212}
213
214
215// ===================================================================
216
217uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
218  // We only optimize this when using optimize_for = SPEED.  In other cases
219  // we just use the CodedOutputStream path.
220  int size = GetCachedSize();
221  io::ArrayOutputStream out(target, size);
222  io::CodedOutputStream coded_out(&out);
223  SerializeWithCachedSizes(&coded_out);
224  GOOGLE_CHECK(!coded_out.HadError());
225  return target + size;
226}
227
228bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
229  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
230  return SerializePartialToCodedStream(output);
231}
232
233bool MessageLite::SerializePartialToCodedStream(
234    io::CodedOutputStream* output) const {
235  const int size = ByteSize();  // Force size to be cached.
236  uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
237  if (buffer != NULL) {
238    uint8* end = SerializeWithCachedSizesToArray(buffer);
239    if (end - buffer != size) {
240      ByteSizeConsistencyError(size, ByteSize(), end - buffer);
241    }
242    return true;
243  } else {
244    int original_byte_count = output->ByteCount();
245    SerializeWithCachedSizes(output);
246    if (output->HadError()) {
247      return false;
248    }
249    int final_byte_count = output->ByteCount();
250
251    if (final_byte_count - original_byte_count != size) {
252      ByteSizeConsistencyError(size, ByteSize(),
253                               final_byte_count - original_byte_count);
254    }
255
256    return true;
257  }
258}
259
260bool MessageLite::SerializeToZeroCopyStream(
261    io::ZeroCopyOutputStream* output) const {
262  io::CodedOutputStream encoder(output);
263  return SerializeToCodedStream(&encoder);
264}
265
266bool MessageLite::SerializePartialToZeroCopyStream(
267    io::ZeroCopyOutputStream* output) const {
268  io::CodedOutputStream encoder(output);
269  return SerializePartialToCodedStream(&encoder);
270}
271
272bool MessageLite::AppendToString(string* output) const {
273  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
274  return AppendPartialToString(output);
275}
276
277bool MessageLite::AppendPartialToString(string* output) const {
278  int old_size = output->size();
279  int byte_size = ByteSize();
280  STLStringResizeUninitialized(output, old_size + byte_size);
281  uint8* start = reinterpret_cast<uint8*>(string_as_array(output) + old_size);
282  uint8* end = SerializeWithCachedSizesToArray(start);
283  if (end - start != byte_size) {
284    ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
285  }
286  return true;
287}
288
289bool MessageLite::SerializeToString(string* output) const {
290  output->clear();
291  return AppendToString(output);
292}
293
294bool MessageLite::SerializePartialToString(string* output) const {
295  output->clear();
296  return AppendPartialToString(output);
297}
298
299bool MessageLite::SerializeToArray(void* data, int size) const {
300  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
301  return SerializePartialToArray(data, size);
302}
303
304bool MessageLite::SerializePartialToArray(void* data, int size) const {
305  int byte_size = ByteSize();
306  if (size < byte_size) return false;
307  uint8* start = reinterpret_cast<uint8*>(data);
308  uint8* end = SerializeWithCachedSizesToArray(start);
309  if (end - start != byte_size) {
310    ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
311  }
312  return true;
313}
314
315string MessageLite::SerializeAsString() const {
316  // If the compiler implements the (Named) Return Value Optimization,
317  // the local variable 'result' will not actually reside on the stack
318  // of this function, but will be overlaid with the object that the
319  // caller supplied for the return value to be constructed in.
320  string output;
321  if (!AppendToString(&output))
322    output.clear();
323  return output;
324}
325
326string MessageLite::SerializePartialAsString() const {
327  string output;
328  if (!AppendPartialToString(&output))
329    output.clear();
330  return output;
331}
332
333}  // namespace protobuf
334}  // namespace google
335