message_lite.cc revision fbaaef999ba563838ebd00874ed8a1c01fbf286d
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
37#include <google/protobuf/message_lite.h>
38
39#include <google/protobuf/stubs/common.h>
40#include <google/protobuf/io/coded_stream.h>
41#include <google/protobuf/io/zero_copy_stream_impl.h>
42#include <google/protobuf/stubs/stl_util-inl.h>
43
44namespace google {
45namespace protobuf {
46
47MessageLite::~MessageLite() {}
48
49string MessageLite::InitializationErrorString() const {
50  return "(cannot determine missing fields for lite message)";
51}
52
53namespace {
54
55string InitializationErrorMessage(const char* action,
56                                  const MessageLite& message) {
57  // Note:  We want to avoid depending on strutil in the lite library, otherwise
58  //   we'd use:
59  //
60  // return strings::Substitute(
61  //   "Can't $0 message of type \"$1\" because it is missing required "
62  //   "fields: $2",
63  //   action, message.GetTypeName(),
64  //   message.InitializationErrorString());
65
66  string result;
67  result += "Can't ";
68  result += action;
69  result += " message of type \"";
70  result += message.GetTypeName();
71  result += "\" because it is missing required fields: ";
72  result += message.InitializationErrorString();
73  return result;
74}
75
76// Several of the Parse methods below just do one thing and then call another
77// method.  In a naive implementation, we might have ParseFromString() call
78// ParseFromArray() which would call ParseFromZeroCopyStream() which would call
79// ParseFromCodedStream() which would call MergeFromCodedStream() which would
80// call MergePartialFromCodedStream().  However, when parsing very small
81// messages, every function call introduces significant overhead.  To avoid
82// this without reproducing code, we use these forced-inline helpers.
83//
84// Note:  GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not
85//   definitions.
86inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
87                                       MessageLite* message)
88                                       GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
89inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
90                                       MessageLite* message)
91                                       GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
92inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
93                                              MessageLite* message)
94                                              GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
95inline bool InlineParseFromArray(const void* data, int size,
96                                 MessageLite* message)
97                                 GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
98inline bool InlineParsePartialFromArray(const void* data, int size,
99                                        MessageLite* message)
100                                        GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
101
102bool InlineMergeFromCodedStream(io::CodedInputStream* input,
103                                MessageLite* message) {
104  if (!message->MergePartialFromCodedStream(input)) return false;
105  if (!message->IsInitialized()) {
106    GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
107    return false;
108  }
109  return true;
110}
111
112bool InlineParseFromCodedStream(io::CodedInputStream* input,
113                                MessageLite* message) {
114  message->Clear();
115  return InlineMergeFromCodedStream(input, message);
116}
117
118bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
119                                       MessageLite* message) {
120  message->Clear();
121  return message->MergePartialFromCodedStream(input);
122}
123
124bool InlineParseFromArray(const void* data, int size, MessageLite* message) {
125  io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
126  return InlineParseFromCodedStream(&input, message) &&
127         input.ConsumedEntireMessage();
128}
129
130bool InlineParsePartialFromArray(const void* data, int size,
131                                 MessageLite* message) {
132  io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
133  return InlineParsePartialFromCodedStream(&input, message) &&
134         input.ConsumedEntireMessage();
135}
136
137}  // namespace
138
139bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
140  return InlineMergeFromCodedStream(input, this);
141}
142
143bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
144  return InlineParseFromCodedStream(input, this);
145}
146
147bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
148  return InlineParsePartialFromCodedStream(input, this);
149}
150
151bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
152  io::CodedInputStream decoder(input);
153  return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
154}
155
156bool MessageLite::ParsePartialFromZeroCopyStream(
157    io::ZeroCopyInputStream* input) {
158  io::CodedInputStream decoder(input);
159  return ParsePartialFromCodedStream(&decoder) &&
160         decoder.ConsumedEntireMessage();
161}
162
163bool MessageLite::ParseFromBoundedZeroCopyStream(
164    io::ZeroCopyInputStream* input, int size) {
165  io::CodedInputStream decoder(input);
166  decoder.PushLimit(size);
167  return ParseFromCodedStream(&decoder) &&
168         decoder.ConsumedEntireMessage() &&
169         decoder.BytesUntilLimit() == 0;
170}
171
172bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
173    io::ZeroCopyInputStream* input, int size) {
174  io::CodedInputStream decoder(input);
175  decoder.PushLimit(size);
176  return ParsePartialFromCodedStream(&decoder) &&
177         decoder.ConsumedEntireMessage() &&
178         decoder.BytesUntilLimit() == 0;
179}
180
181bool MessageLite::ParseFromString(const string& data) {
182  return InlineParseFromArray(data.data(), data.size(), this);
183}
184
185bool MessageLite::ParsePartialFromString(const string& data) {
186  return InlineParsePartialFromArray(data.data(), data.size(), this);
187}
188
189bool MessageLite::ParseFromArray(const void* data, int size) {
190  return InlineParseFromArray(data, size, this);
191}
192
193bool MessageLite::ParsePartialFromArray(const void* data, int size) {
194  return InlineParsePartialFromArray(data, size, this);
195}
196
197
198// ===================================================================
199
200uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
201  // We only optimize this when using optimize_for = SPEED.  In other cases
202  // we just use the CodedOutputStream path.
203  int size = GetCachedSize();
204  io::ArrayOutputStream out(target, size);
205  io::CodedOutputStream coded_out(&out);
206  SerializeWithCachedSizes(&coded_out);
207  GOOGLE_CHECK(!coded_out.HadError());
208  return target + size;
209}
210
211bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
212  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
213  return SerializePartialToCodedStream(output);
214}
215
216bool MessageLite::SerializePartialToCodedStream(
217    io::CodedOutputStream* output) const {
218  ByteSize();  // Force size to be cached.
219  SerializeWithCachedSizes(output);
220  return !output->HadError();
221}
222
223bool MessageLite::SerializeToZeroCopyStream(
224    io::ZeroCopyOutputStream* output) const {
225  io::CodedOutputStream encoder(output);
226  return SerializeToCodedStream(&encoder);
227}
228
229bool MessageLite::SerializePartialToZeroCopyStream(
230    io::ZeroCopyOutputStream* output) const {
231  io::CodedOutputStream encoder(output);
232  return SerializePartialToCodedStream(&encoder);
233}
234
235bool MessageLite::AppendToString(string* output) const {
236  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
237  return AppendPartialToString(output);
238}
239
240bool MessageLite::AppendPartialToString(string* output) const {
241  int old_size = output->size();
242  int byte_size = ByteSize();
243  STLStringResizeUninitialized(output, old_size + byte_size);
244  uint8* start = reinterpret_cast<uint8*>(string_as_array(output) + old_size);
245  uint8* end = SerializeWithCachedSizesToArray(start);
246  GOOGLE_CHECK_EQ(end - start, byte_size);
247  return true;
248}
249
250bool MessageLite::SerializeToString(string* output) const {
251  output->clear();
252  return AppendToString(output);
253}
254
255bool MessageLite::SerializePartialToString(string* output) const {
256  output->clear();
257  return AppendPartialToString(output);
258}
259
260bool MessageLite::SerializeToArray(void* data, int size) const {
261  GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
262  return SerializePartialToArray(data, size);
263}
264
265bool MessageLite::SerializePartialToArray(void* data, int size) const {
266  int byte_size = ByteSize();
267  if (size < byte_size) return false;
268  uint8* end =
269    SerializeWithCachedSizesToArray(reinterpret_cast<uint8*>(data));
270  GOOGLE_CHECK_EQ(end, reinterpret_cast<uint8*>(data) + byte_size);
271  return true;
272}
273
274string MessageLite::SerializeAsString() const {
275  // If the compiler implements the (Named) Return Value Optimization,
276  // the local variable 'result' will not actually reside on the stack
277  // of this function, but will be overlaid with the object that the
278  // caller supplied for the return value to be constructed in.
279  string output;
280  if (!AppendToString(&output))
281    output.clear();
282  return output;
283}
284
285string MessageLite::SerializePartialAsString() const {
286  string output;
287  if (!AppendPartialToString(&output))
288    output.clear();
289  return output;
290}
291
292}  // namespace protobuf
293}  // namespace google
294