Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      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 (at) google.com (Wink Saville),
     32 //          kenton (at) 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_lite.h>
     41 #include <google/protobuf/stubs/stl_util.h>
     42 
     43 namespace google {
     44 namespace protobuf {
     45 
     46 MessageLite::~MessageLite() {}
     47 
     48 string MessageLite::InitializationErrorString() const {
     49   return "(cannot determine missing fields for lite message)";
     50 }
     51 
     52 namespace {
     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.
     60 void 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 
     72 string 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.
    103 inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
    104                                        MessageLite* message)
    105                                        GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
    106 inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
    107                                        MessageLite* message)
    108                                        GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
    109 inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
    110                                               MessageLite* message)
    111                                               GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
    112 inline bool InlineParseFromArray(const void* data, int size,
    113                                  MessageLite* message)
    114                                  GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
    115 inline bool InlineParsePartialFromArray(const void* data, int size,
    116                                         MessageLite* message)
    117                                         GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
    118 
    119 bool 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 
    129 bool InlineParseFromCodedStream(io::CodedInputStream* input,
    130                                 MessageLite* message) {
    131   message->Clear();
    132   return InlineMergeFromCodedStream(input, message);
    133 }
    134 
    135 bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
    136                                        MessageLite* message) {
    137   message->Clear();
    138   return message->MergePartialFromCodedStream(input);
    139 }
    140 
    141 bool 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 
    147 bool 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 
    156 bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
    157   return InlineMergeFromCodedStream(input, this);
    158 }
    159 
    160 bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
    161   return InlineParseFromCodedStream(input, this);
    162 }
    163 
    164 bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
    165   return InlineParsePartialFromCodedStream(input, this);
    166 }
    167 
    168 bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
    169   io::CodedInputStream decoder(input);
    170   return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
    171 }
    172 
    173 bool MessageLite::ParsePartialFromZeroCopyStream(
    174     io::ZeroCopyInputStream* input) {
    175   io::CodedInputStream decoder(input);
    176   return ParsePartialFromCodedStream(&decoder) &&
    177          decoder.ConsumedEntireMessage();
    178 }
    179 
    180 bool 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 
    189 bool 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 
    198 bool MessageLite::ParseFromString(const string& data) {
    199   return InlineParseFromArray(data.data(), data.size(), this);
    200 }
    201 
    202 bool MessageLite::ParsePartialFromString(const string& data) {
    203   return InlineParsePartialFromArray(data.data(), data.size(), this);
    204 }
    205 
    206 bool MessageLite::ParseFromArray(const void* data, int size) {
    207   return InlineParseFromArray(data, size, this);
    208 }
    209 
    210 bool MessageLite::ParsePartialFromArray(const void* data, int size) {
    211   return InlineParsePartialFromArray(data, size, this);
    212 }
    213 
    214 
    215 // ===================================================================
    216 
    217 uint8* 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 
    228 bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
    229   GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
    230   return SerializePartialToCodedStream(output);
    231 }
    232 
    233 bool 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 
    260 bool MessageLite::SerializeToZeroCopyStream(
    261     io::ZeroCopyOutputStream* output) const {
    262   io::CodedOutputStream encoder(output);
    263   return SerializeToCodedStream(&encoder);
    264 }
    265 
    266 bool MessageLite::SerializePartialToZeroCopyStream(
    267     io::ZeroCopyOutputStream* output) const {
    268   io::CodedOutputStream encoder(output);
    269   return SerializePartialToCodedStream(&encoder);
    270 }
    271 
    272 bool MessageLite::AppendToString(string* output) const {
    273   GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
    274   return AppendPartialToString(output);
    275 }
    276 
    277 bool 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 =
    282       reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
    283   uint8* end = SerializeWithCachedSizesToArray(start);
    284   if (end - start != byte_size) {
    285     ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
    286   }
    287   return true;
    288 }
    289 
    290 bool MessageLite::SerializeToString(string* output) const {
    291   output->clear();
    292   return AppendToString(output);
    293 }
    294 
    295 bool MessageLite::SerializePartialToString(string* output) const {
    296   output->clear();
    297   return AppendPartialToString(output);
    298 }
    299 
    300 bool MessageLite::SerializeToArray(void* data, int size) const {
    301   GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
    302   return SerializePartialToArray(data, size);
    303 }
    304 
    305 bool MessageLite::SerializePartialToArray(void* data, int size) const {
    306   int byte_size = ByteSize();
    307   if (size < byte_size) return false;
    308   uint8* start = reinterpret_cast<uint8*>(data);
    309   uint8* end = SerializeWithCachedSizesToArray(start);
    310   if (end - start != byte_size) {
    311     ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
    312   }
    313   return true;
    314 }
    315 
    316 string MessageLite::SerializeAsString() const {
    317   // If the compiler implements the (Named) Return Value Optimization,
    318   // the local variable 'result' will not actually reside on the stack
    319   // of this function, but will be overlaid with the object that the
    320   // caller supplied for the return value to be constructed in.
    321   string output;
    322   if (!AppendToString(&output))
    323     output.clear();
    324   return output;
    325 }
    326 
    327 string MessageLite::SerializePartialAsString() const {
    328   string output;
    329   if (!AppendPartialToString(&output))
    330     output.clear();
    331   return output;
    332 }
    333 
    334 }  // namespace protobuf
    335 }  // namespace google
    336