1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 // Adapted from the patch of kenton@google.com (Kenton Varda)
9 // See https://github.com/protocolbuffers/protobuf/pull/710 for details.
10
11 #include "google/protobuf/util/delimited_message_util.h"
12
13 #include "google/protobuf/io/coded_stream.h"
14
15 namespace google {
16 namespace protobuf {
17 namespace util {
18
SerializeDelimitedToFileDescriptor(const MessageLite & message,int file_descriptor)19 bool SerializeDelimitedToFileDescriptor(const MessageLite& message,
20 int file_descriptor) {
21 io::FileOutputStream output(file_descriptor);
22 return SerializeDelimitedToZeroCopyStream(message, &output);
23 }
24
SerializeDelimitedToOstream(const MessageLite & message,std::ostream * output)25 bool SerializeDelimitedToOstream(const MessageLite& message,
26 std::ostream* output) {
27 {
28 io::OstreamOutputStream zero_copy_output(output);
29 if (!SerializeDelimitedToZeroCopyStream(message, &zero_copy_output))
30 return false;
31 }
32 return output->good();
33 }
34
ParseDelimitedFromZeroCopyStream(MessageLite * message,io::ZeroCopyInputStream * input,bool * clean_eof)35 bool ParseDelimitedFromZeroCopyStream(MessageLite* message,
36 io::ZeroCopyInputStream* input,
37 bool* clean_eof) {
38 io::CodedInputStream coded_input(input);
39 return ParseDelimitedFromCodedStream(message, &coded_input, clean_eof);
40 }
41
ParseDelimitedFromCodedStream(MessageLite * message,io::CodedInputStream * input,bool * clean_eof)42 bool ParseDelimitedFromCodedStream(MessageLite* message,
43 io::CodedInputStream* input,
44 bool* clean_eof) {
45 if (clean_eof != nullptr) *clean_eof = false;
46 int start = input->CurrentPosition();
47
48 // Read the size.
49 uint32_t size;
50 if (!input->ReadVarint32(&size)) {
51 if (clean_eof != nullptr) *clean_eof = input->CurrentPosition() == start;
52 return false;
53 }
54
55 // Get the position after any size bytes have been read (and only the message
56 // itself remains).
57 int position_after_size = input->CurrentPosition();
58
59 // Tell the stream not to read beyond that size.
60 io::CodedInputStream::Limit limit = input->PushLimit(static_cast<int>(size));
61
62 // Parse the message.
63 if (!message->MergeFromCodedStream(input)) return false;
64 if (!input->ConsumedEntireMessage()) return false;
65 if (input->CurrentPosition() - position_after_size != static_cast<int>(size))
66 return false;
67
68 // Release the limit.
69 input->PopLimit(limit);
70
71 return true;
72 }
73
SerializeDelimitedToZeroCopyStream(const MessageLite & message,io::ZeroCopyOutputStream * output)74 bool SerializeDelimitedToZeroCopyStream(const MessageLite& message,
75 io::ZeroCopyOutputStream* output) {
76 io::CodedOutputStream coded_output(output);
77 return SerializeDelimitedToCodedStream(message, &coded_output);
78 }
79
SerializeDelimitedToCodedStream(const MessageLite & message,io::CodedOutputStream * output)80 bool SerializeDelimitedToCodedStream(const MessageLite& message,
81 io::CodedOutputStream* output) {
82 // Write the size.
83 size_t size = message.ByteSizeLong();
84 if (size > INT_MAX) return false;
85
86 output->WriteVarint32(static_cast<uint32_t>(size));
87
88 // Write the content.
89 uint8_t* buffer =
90 output->GetDirectBufferForNBytesAndAdvance(static_cast<int>(size));
91 if (buffer != nullptr) {
92 // Optimization: The message fits in one buffer, so use the faster
93 // direct-to-array serialization path.
94 message.SerializeWithCachedSizesToArray(buffer);
95 } else {
96 // Slightly-slower path when the message is multiple buffers.
97 message.SerializeWithCachedSizes(output);
98 if (output->HadError()) return false;
99 }
100
101 return true;
102 }
103
104 } // namespace util
105 } // namespace protobuf
106 } // namespace google
107