blob: 2ce4920c7efadc19bc60dfc0c78be6a7a7a6575b [file] [log] [blame]
kenton@google.com80b1d622009-07-29 01:13:20 +00001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
Feng Xiaoe4288622014-10-01 16:26:23 -07003// https://developers.google.com/protocol-buffers/
kenton@google.com80b1d622009-07-29 01:13:20 +00004//
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// Author: kenton@google.com (Kenton Varda)
32// Based on original Protocol Buffers design by
33// Sanjay Ghemawat, Jeff Dean, and others.
34
kenton@google.comfccb1462009-12-18 02:11:36 +000035#include <google/protobuf/wire_format_lite_inl.h>
36
kenton@google.com80b1d622009-07-29 01:13:20 +000037#include <stack>
38#include <string>
39#include <vector>
kenton@google.com80b1d622009-07-29 01:13:20 +000040#include <google/protobuf/stubs/common.h>
kenton@google.comfccb1462009-12-18 02:11:36 +000041#include <google/protobuf/io/coded_stream_inl.h>
kenton@google.com80b1d622009-07-29 01:13:20 +000042#include <google/protobuf/io/zero_copy_stream.h>
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +000043#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
kenton@google.com80b1d622009-07-29 01:13:20 +000044
45namespace google {
46namespace protobuf {
47namespace internal {
48
49#ifndef _MSC_VER // MSVC doesn't like definitions of inline constants, GCC
50 // requires them.
51const int WireFormatLite::kMessageSetItemStartTag;
52const int WireFormatLite::kMessageSetItemEndTag;
53const int WireFormatLite::kMessageSetTypeIdTag;
54const int WireFormatLite::kMessageSetMessageTag;
55
56#endif
57
Andrew Paprocki4eaa16f2014-10-31 15:46:39 -040058// IBM xlC requires prefixing constants with WireFormatLite::
kenton@google.com80b1d622009-07-29 01:13:20 +000059const int WireFormatLite::kMessageSetItemTagsSize =
Feng Xiao99aa0f92014-11-20 16:18:53 -080060 io::CodedOutputStream::StaticVarintSize32<
61 WireFormatLite::kMessageSetItemStartTag>::value +
62 io::CodedOutputStream::StaticVarintSize32<
63 WireFormatLite::kMessageSetItemEndTag>::value +
64 io::CodedOutputStream::StaticVarintSize32<
65 WireFormatLite::kMessageSetTypeIdTag>::value +
66 io::CodedOutputStream::StaticVarintSize32<
67 WireFormatLite::kMessageSetMessageTag>::value;
kenton@google.com80b1d622009-07-29 01:13:20 +000068
69const WireFormatLite::CppType
70WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = {
71 static_cast<CppType>(0), // 0 is reserved for errors
72
73 CPPTYPE_DOUBLE, // TYPE_DOUBLE
74 CPPTYPE_FLOAT, // TYPE_FLOAT
75 CPPTYPE_INT64, // TYPE_INT64
76 CPPTYPE_UINT64, // TYPE_UINT64
77 CPPTYPE_INT32, // TYPE_INT32
78 CPPTYPE_UINT64, // TYPE_FIXED64
79 CPPTYPE_UINT32, // TYPE_FIXED32
80 CPPTYPE_BOOL, // TYPE_BOOL
81 CPPTYPE_STRING, // TYPE_STRING
82 CPPTYPE_MESSAGE, // TYPE_GROUP
83 CPPTYPE_MESSAGE, // TYPE_MESSAGE
84 CPPTYPE_STRING, // TYPE_BYTES
85 CPPTYPE_UINT32, // TYPE_UINT32
86 CPPTYPE_ENUM, // TYPE_ENUM
87 CPPTYPE_INT32, // TYPE_SFIXED32
88 CPPTYPE_INT64, // TYPE_SFIXED64
89 CPPTYPE_INT32, // TYPE_SINT32
90 CPPTYPE_INT64, // TYPE_SINT64
91};
92
93const WireFormatLite::WireType
94WireFormatLite::kWireTypeForFieldType[MAX_FIELD_TYPE + 1] = {
95 static_cast<WireFormatLite::WireType>(-1), // invalid
96 WireFormatLite::WIRETYPE_FIXED64, // TYPE_DOUBLE
97 WireFormatLite::WIRETYPE_FIXED32, // TYPE_FLOAT
98 WireFormatLite::WIRETYPE_VARINT, // TYPE_INT64
99 WireFormatLite::WIRETYPE_VARINT, // TYPE_UINT64
100 WireFormatLite::WIRETYPE_VARINT, // TYPE_INT32
101 WireFormatLite::WIRETYPE_FIXED64, // TYPE_FIXED64
102 WireFormatLite::WIRETYPE_FIXED32, // TYPE_FIXED32
103 WireFormatLite::WIRETYPE_VARINT, // TYPE_BOOL
104 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_STRING
105 WireFormatLite::WIRETYPE_START_GROUP, // TYPE_GROUP
106 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_MESSAGE
107 WireFormatLite::WIRETYPE_LENGTH_DELIMITED, // TYPE_BYTES
108 WireFormatLite::WIRETYPE_VARINT, // TYPE_UINT32
109 WireFormatLite::WIRETYPE_VARINT, // TYPE_ENUM
110 WireFormatLite::WIRETYPE_FIXED32, // TYPE_SFIXED32
111 WireFormatLite::WIRETYPE_FIXED64, // TYPE_SFIXED64
112 WireFormatLite::WIRETYPE_VARINT, // TYPE_SINT32
113 WireFormatLite::WIRETYPE_VARINT, // TYPE_SINT64
114};
115
116bool WireFormatLite::SkipField(
117 io::CodedInputStream* input, uint32 tag) {
118 switch (WireFormatLite::GetTagWireType(tag)) {
119 case WireFormatLite::WIRETYPE_VARINT: {
120 uint64 value;
121 if (!input->ReadVarint64(&value)) return false;
122 return true;
123 }
124 case WireFormatLite::WIRETYPE_FIXED64: {
125 uint64 value;
126 if (!input->ReadLittleEndian64(&value)) return false;
127 return true;
128 }
129 case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
130 uint32 length;
131 if (!input->ReadVarint32(&length)) return false;
132 if (!input->Skip(length)) return false;
133 return true;
134 }
135 case WireFormatLite::WIRETYPE_START_GROUP: {
136 if (!input->IncrementRecursionDepth()) return false;
137 if (!SkipMessage(input)) return false;
138 input->DecrementRecursionDepth();
139 // Check that the ending tag matched the starting tag.
140 if (!input->LastTagWas(WireFormatLite::MakeTag(
141 WireFormatLite::GetTagFieldNumber(tag),
142 WireFormatLite::WIRETYPE_END_GROUP))) {
143 return false;
144 }
145 return true;
146 }
147 case WireFormatLite::WIRETYPE_END_GROUP: {
148 return false;
149 }
150 case WireFormatLite::WIRETYPE_FIXED32: {
151 uint32 value;
152 if (!input->ReadLittleEndian32(&value)) return false;
153 return true;
154 }
155 default: {
156 return false;
157 }
158 }
159}
160
jieluo@google.com4de8f552014-07-18 00:47:59 +0000161bool WireFormatLite::SkipField(
162 io::CodedInputStream* input, uint32 tag, io::CodedOutputStream* output) {
163 switch (WireFormatLite::GetTagWireType(tag)) {
164 case WireFormatLite::WIRETYPE_VARINT: {
165 uint64 value;
166 if (!input->ReadVarint64(&value)) return false;
167 output->WriteVarint32(tag);
168 output->WriteVarint64(value);
169 return true;
170 }
171 case WireFormatLite::WIRETYPE_FIXED64: {
172 uint64 value;
173 if (!input->ReadLittleEndian64(&value)) return false;
174 output->WriteVarint32(tag);
175 output->WriteLittleEndian64(value);
176 return true;
177 }
178 case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
179 uint32 length;
180 if (!input->ReadVarint32(&length)) return false;
181 output->WriteVarint32(tag);
182 output->WriteVarint32(length);
183 // TODO(mkilavuz): Provide API to prevent extra string copying.
184 string temp;
185 if (!input->ReadString(&temp, length)) return false;
186 output->WriteString(temp);
187 return true;
188 }
189 case WireFormatLite::WIRETYPE_START_GROUP: {
190 output->WriteVarint32(tag);
191 if (!input->IncrementRecursionDepth()) return false;
192 if (!SkipMessage(input, output)) return false;
193 input->DecrementRecursionDepth();
194 // Check that the ending tag matched the starting tag.
195 if (!input->LastTagWas(WireFormatLite::MakeTag(
196 WireFormatLite::GetTagFieldNumber(tag),
197 WireFormatLite::WIRETYPE_END_GROUP))) {
198 return false;
199 }
200 return true;
201 }
202 case WireFormatLite::WIRETYPE_END_GROUP: {
203 return false;
204 }
205 case WireFormatLite::WIRETYPE_FIXED32: {
206 uint32 value;
207 if (!input->ReadLittleEndian32(&value)) return false;
208 output->WriteVarint32(tag);
209 output->WriteLittleEndian32(value);
210 return true;
211 }
212 default: {
213 return false;
214 }
215 }
216}
217
kenton@google.com80b1d622009-07-29 01:13:20 +0000218bool WireFormatLite::SkipMessage(io::CodedInputStream* input) {
jieluo@google.com4de8f552014-07-18 00:47:59 +0000219 while (true) {
kenton@google.com80b1d622009-07-29 01:13:20 +0000220 uint32 tag = input->ReadTag();
221 if (tag == 0) {
222 // End of input. This is a valid place to end, so return true.
223 return true;
224 }
225
226 WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
227
228 if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
229 // Must be the end of the message.
230 return true;
231 }
232
233 if (!SkipField(input, tag)) return false;
234 }
235}
236
jieluo@google.com4de8f552014-07-18 00:47:59 +0000237bool WireFormatLite::SkipMessage(io::CodedInputStream* input,
238 io::CodedOutputStream* output) {
239 while (true) {
240 uint32 tag = input->ReadTag();
241 if (tag == 0) {
242 // End of input. This is a valid place to end, so return true.
243 return true;
244 }
245
246 WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag);
247
248 if (wire_type == WireFormatLite::WIRETYPE_END_GROUP) {
249 output->WriteVarint32(tag);
250 // Must be the end of the message.
251 return true;
252 }
253
254 if (!SkipField(input, tag, output)) return false;
255 }
256}
257
kenton@google.com80b1d622009-07-29 01:13:20 +0000258bool FieldSkipper::SkipField(
259 io::CodedInputStream* input, uint32 tag) {
260 return WireFormatLite::SkipField(input, tag);
261}
262
263bool FieldSkipper::SkipMessage(io::CodedInputStream* input) {
264 return WireFormatLite::SkipMessage(input);
265}
266
267void FieldSkipper::SkipUnknownEnum(
liujisi@google.comc5553a32014-05-28 21:48:28 +0000268 int /* field_number */, int /* value */) {
kenton@google.com80b1d622009-07-29 01:13:20 +0000269 // Nothing.
270}
271
jieluo@google.com4de8f552014-07-18 00:47:59 +0000272bool CodedOutputStreamFieldSkipper::SkipField(
273 io::CodedInputStream* input, uint32 tag) {
274 return WireFormatLite::SkipField(input, tag, unknown_fields_);
275}
276
277bool CodedOutputStreamFieldSkipper::SkipMessage(io::CodedInputStream* input) {
278 return WireFormatLite::SkipMessage(input, unknown_fields_);
279}
280
281void CodedOutputStreamFieldSkipper::SkipUnknownEnum(
282 int field_number, int value) {
283 unknown_fields_->WriteVarint32(field_number);
284 unknown_fields_->WriteVarint64(value);
285}
286
kenton@google.comfccb1462009-12-18 02:11:36 +0000287bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input,
288 bool (*is_valid)(int),
289 RepeatedField<int>* values) {
290 uint32 length;
291 if (!input->ReadVarint32(&length)) return false;
292 io::CodedInputStream::Limit limit = input->PushLimit(length);
293 while (input->BytesUntilLimit() > 0) {
294 int value;
295 if (!google::protobuf::internal::WireFormatLite::ReadPrimitive<
296 int, WireFormatLite::TYPE_ENUM>(input, &value)) {
297 return false;
298 }
Feng Xiao6ef984a2014-11-10 17:34:54 -0800299 if (is_valid == NULL || is_valid(value)) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000300 values->Add(value);
301 }
302 }
303 input->PopLimit(limit);
304 return true;
305}
306
Jisi Liu885b6122015-02-28 14:51:22 -0800307bool WireFormatLite::ReadPackedEnumPreserveUnknowns(
308 io::CodedInputStream* input,
309 int field_number,
310 bool (*is_valid)(int),
311 io::CodedOutputStream* unknown_fields_stream,
312 RepeatedField<int>* values) {
313 uint32 length;
314 if (!input->ReadVarint32(&length)) return false;
315 io::CodedInputStream::Limit limit = input->PushLimit(length);
316 while (input->BytesUntilLimit() > 0) {
317 int value;
318 if (!google::protobuf::internal::WireFormatLite::ReadPrimitive<
319 int, WireFormatLite::TYPE_ENUM>(input, &value)) {
320 return false;
321 }
322 if (is_valid == NULL || is_valid(value)) {
323 values->Add(value);
324 } else {
325 uint32 tag = WireFormatLite::MakeTag(field_number,
326 WireFormatLite::WIRETYPE_VARINT);
327 unknown_fields_stream->WriteVarint32(tag);
328 unknown_fields_stream->WriteVarint32(value);
329 }
330 }
331 input->PopLimit(limit);
332 return true;
333}
334
kenton@google.comfccb1462009-12-18 02:11:36 +0000335void WireFormatLite::WriteInt32(int field_number, int32 value,
336 io::CodedOutputStream* output) {
337 WriteTag(field_number, WIRETYPE_VARINT, output);
338 WriteInt32NoTag(value, output);
339}
340void WireFormatLite::WriteInt64(int field_number, int64 value,
341 io::CodedOutputStream* output) {
342 WriteTag(field_number, WIRETYPE_VARINT, output);
343 WriteInt64NoTag(value, output);
344}
345void WireFormatLite::WriteUInt32(int field_number, uint32 value,
346 io::CodedOutputStream* output) {
347 WriteTag(field_number, WIRETYPE_VARINT, output);
348 WriteUInt32NoTag(value, output);
349}
350void WireFormatLite::WriteUInt64(int field_number, uint64 value,
351 io::CodedOutputStream* output) {
352 WriteTag(field_number, WIRETYPE_VARINT, output);
353 WriteUInt64NoTag(value, output);
354}
355void WireFormatLite::WriteSInt32(int field_number, int32 value,
356 io::CodedOutputStream* output) {
357 WriteTag(field_number, WIRETYPE_VARINT, output);
358 WriteSInt32NoTag(value, output);
359}
360void WireFormatLite::WriteSInt64(int field_number, int64 value,
361 io::CodedOutputStream* output) {
362 WriteTag(field_number, WIRETYPE_VARINT, output);
363 WriteSInt64NoTag(value, output);
364}
365void WireFormatLite::WriteFixed32(int field_number, uint32 value,
366 io::CodedOutputStream* output) {
367 WriteTag(field_number, WIRETYPE_FIXED32, output);
368 WriteFixed32NoTag(value, output);
369}
370void WireFormatLite::WriteFixed64(int field_number, uint64 value,
371 io::CodedOutputStream* output) {
372 WriteTag(field_number, WIRETYPE_FIXED64, output);
373 WriteFixed64NoTag(value, output);
374}
375void WireFormatLite::WriteSFixed32(int field_number, int32 value,
376 io::CodedOutputStream* output) {
377 WriteTag(field_number, WIRETYPE_FIXED32, output);
378 WriteSFixed32NoTag(value, output);
379}
380void WireFormatLite::WriteSFixed64(int field_number, int64 value,
381 io::CodedOutputStream* output) {
382 WriteTag(field_number, WIRETYPE_FIXED64, output);
383 WriteSFixed64NoTag(value, output);
384}
385void WireFormatLite::WriteFloat(int field_number, float value,
386 io::CodedOutputStream* output) {
387 WriteTag(field_number, WIRETYPE_FIXED32, output);
388 WriteFloatNoTag(value, output);
389}
390void WireFormatLite::WriteDouble(int field_number, double value,
391 io::CodedOutputStream* output) {
392 WriteTag(field_number, WIRETYPE_FIXED64, output);
393 WriteDoubleNoTag(value, output);
394}
395void WireFormatLite::WriteBool(int field_number, bool value,
396 io::CodedOutputStream* output) {
397 WriteTag(field_number, WIRETYPE_VARINT, output);
398 WriteBoolNoTag(value, output);
399}
400void WireFormatLite::WriteEnum(int field_number, int value,
401 io::CodedOutputStream* output) {
402 WriteTag(field_number, WIRETYPE_VARINT, output);
403 WriteEnumNoTag(value, output);
404}
405
406void WireFormatLite::WriteString(int field_number, const string& value,
407 io::CodedOutputStream* output) {
408 // String is for UTF-8 text only
409 WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000410 GOOGLE_CHECK(value.size() <= kint32max);
kenton@google.comfccb1462009-12-18 02:11:36 +0000411 output->WriteVarint32(value.size());
412 output->WriteString(value);
413}
jieluo@google.com4de8f552014-07-18 00:47:59 +0000414void WireFormatLite::WriteStringMaybeAliased(
415 int field_number, const string& value,
416 io::CodedOutputStream* output) {
417 // String is for UTF-8 text only
418 WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
419 GOOGLE_CHECK(value.size() <= kint32max);
420 output->WriteVarint32(value.size());
421 output->WriteRawMaybeAliased(value.data(), value.size());
422}
kenton@google.comfccb1462009-12-18 02:11:36 +0000423void WireFormatLite::WriteBytes(int field_number, const string& value,
424 io::CodedOutputStream* output) {
425 WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
xiaofeng@google.comb55a20f2012-09-22 02:40:50 +0000426 GOOGLE_CHECK(value.size() <= kint32max);
kenton@google.comfccb1462009-12-18 02:11:36 +0000427 output->WriteVarint32(value.size());
428 output->WriteString(value);
429}
jieluo@google.com4de8f552014-07-18 00:47:59 +0000430void WireFormatLite::WriteBytesMaybeAliased(
431 int field_number, const string& value,
432 io::CodedOutputStream* output) {
433 WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
434 GOOGLE_CHECK(value.size() <= kint32max);
435 output->WriteVarint32(value.size());
436 output->WriteRawMaybeAliased(value.data(), value.size());
437}
kenton@google.comfccb1462009-12-18 02:11:36 +0000438
439
440void WireFormatLite::WriteGroup(int field_number,
441 const MessageLite& value,
442 io::CodedOutputStream* output) {
443 WriteTag(field_number, WIRETYPE_START_GROUP, output);
444 value.SerializeWithCachedSizes(output);
445 WriteTag(field_number, WIRETYPE_END_GROUP, output);
446}
447
448void WireFormatLite::WriteMessage(int field_number,
449 const MessageLite& value,
450 io::CodedOutputStream* output) {
451 WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
452 const int size = value.GetCachedSize();
453 output->WriteVarint32(size);
454 value.SerializeWithCachedSizes(output);
455}
456
457void WireFormatLite::WriteGroupMaybeToArray(int field_number,
458 const MessageLite& value,
459 io::CodedOutputStream* output) {
460 WriteTag(field_number, WIRETYPE_START_GROUP, output);
461 const int size = value.GetCachedSize();
462 uint8* target = output->GetDirectBufferForNBytesAndAdvance(size);
463 if (target != NULL) {
464 uint8* end = value.SerializeWithCachedSizesToArray(target);
465 GOOGLE_DCHECK_EQ(end - target, size);
466 } else {
467 value.SerializeWithCachedSizes(output);
468 }
469 WriteTag(field_number, WIRETYPE_END_GROUP, output);
470}
471
472void WireFormatLite::WriteMessageMaybeToArray(int field_number,
473 const MessageLite& value,
474 io::CodedOutputStream* output) {
475 WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output);
476 const int size = value.GetCachedSize();
477 output->WriteVarint32(size);
478 uint8* target = output->GetDirectBufferForNBytesAndAdvance(size);
479 if (target != NULL) {
480 uint8* end = value.SerializeWithCachedSizesToArray(target);
481 GOOGLE_DCHECK_EQ(end - target, size);
482 } else {
483 value.SerializeWithCachedSizes(output);
484 }
485}
486
Feng Xiao6ef984a2014-11-10 17:34:54 -0800487static inline bool ReadBytesToString(io::CodedInputStream* input,
488 string* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
489static inline bool ReadBytesToString(io::CodedInputStream* input,
490 string* value) {
kenton@google.comfccb1462009-12-18 02:11:36 +0000491 uint32 length;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800492 return input->ReadVarint32(&length) &&
493 input->InternalReadStringInline(value, length);
kenton@google.comfccb1462009-12-18 02:11:36 +0000494}
Feng Xiao6ef984a2014-11-10 17:34:54 -0800495
496bool WireFormatLite::ReadBytes(io::CodedInputStream* input, string* value) {
497 return ReadBytesToString(input, value);
498}
499
500bool WireFormatLite::ReadBytes(io::CodedInputStream* input, string** p) {
501 if (*p == &::google::protobuf::internal::GetEmptyStringAlreadyInited()) {
502 *p = new ::std::string();
503 }
504 return ReadBytesToString(input, *p);
kenton@google.comfccb1462009-12-18 02:11:36 +0000505}
506
kenton@google.com80b1d622009-07-29 01:13:20 +0000507} // namespace internal
508} // namespace protobuf
509} // namespace google