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 <google/protobuf/arena.h>
     38 #include <google/protobuf/repeated_field.h>
     39 #include <string>
     40 #include <google/protobuf/stubs/logging.h>
     41 #include <google/protobuf/stubs/common.h>
     42 #include <google/protobuf/io/coded_stream.h>
     43 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
     44 #include <google/protobuf/stubs/stl_util.h>
     45 
     46 namespace google {
     47 namespace protobuf {
     48 
     49 MessageLite::~MessageLite() {}
     50 
     51 string MessageLite::InitializationErrorString() const {
     52   return "(cannot determine missing fields for lite message)";
     53 }
     54 
     55 namespace {
     56 
     57 // When serializing, we first compute the byte size, then serialize the message.
     58 // If serialization produces a different number of bytes than expected, we
     59 // call this function, which crashes.  The problem could be due to a bug in the
     60 // protobuf implementation but is more likely caused by concurrent modification
     61 // of the message.  This function attempts to distinguish between the two and
     62 // provide a useful error message.
     63 void ByteSizeConsistencyError(int byte_size_before_serialization,
     64                               int byte_size_after_serialization,
     65                               int bytes_produced_by_serialization,
     66                               const MessageLite& message) {
     67   GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
     68       << message.GetTypeName()
     69       << " was modified concurrently during serialization.";
     70   GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
     71       << "Byte size calculation and serialization were inconsistent.  This "
     72          "may indicate a bug in protocol buffers or it may be caused by "
     73          "concurrent modification of " << message.GetTypeName() << ".";
     74   GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
     75 }
     76 
     77 string InitializationErrorMessage(const char* action,
     78                                   const MessageLite& message) {
     79   // Note:  We want to avoid depending on strutil in the lite library, otherwise
     80   //   we'd use:
     81   //
     82   // return strings::Substitute(
     83   //   "Can't $0 message of type \"$1\" because it is missing required "
     84   //   "fields: $2",
     85   //   action, message.GetTypeName(),
     86   //   message.InitializationErrorString());
     87 
     88   string result;
     89   result += "Can't ";
     90   result += action;
     91   result += " message of type \"";
     92   result += message.GetTypeName();
     93   result += "\" because it is missing required fields: ";
     94   result += message.InitializationErrorString();
     95   return result;
     96 }
     97 
     98 // Several of the Parse methods below just do one thing and then call another
     99 // method.  In a naive implementation, we might have ParseFromString() call
    100 // ParseFromArray() which would call ParseFromZeroCopyStream() which would call
    101 // ParseFromCodedStream() which would call MergeFromCodedStream() which would
    102 // call MergePartialFromCodedStream().  However, when parsing very small
    103 // messages, every function call introduces significant overhead.  To avoid
    104 // this without reproducing code, we use these forced-inline helpers.
    105 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineMergeFromCodedStream(
    106     io::CodedInputStream* input, MessageLite* message);
    107 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromCodedStream(
    108     io::CodedInputStream* input, MessageLite* message);
    109 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromCodedStream(
    110     io::CodedInputStream* input, MessageLite* message);
    111 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParseFromArray(
    112     const void* data, int size, MessageLite* message);
    113 GOOGLE_ATTRIBUTE_ALWAYS_INLINE bool InlineParsePartialFromArray(
    114     const void* data, int size, MessageLite* message);
    115 
    116 inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
    117                                        MessageLite* message) {
    118   if (!message->MergePartialFromCodedStream(input)) return false;
    119   if (!message->IsInitialized()) {
    120     GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
    121     return false;
    122   }
    123   return true;
    124 }
    125 
    126 inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
    127                                        MessageLite* message) {
    128   message->Clear();
    129   return InlineMergeFromCodedStream(input, message);
    130 }
    131 
    132 inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
    133                                               MessageLite* message) {
    134   message->Clear();
    135   return message->MergePartialFromCodedStream(input);
    136 }
    137 
    138 inline bool InlineParseFromArray(
    139     const void* data, int size, MessageLite* message) {
    140   io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
    141   return InlineParseFromCodedStream(&input, message) &&
    142          input.ConsumedEntireMessage();
    143 }
    144 
    145 inline bool InlineParsePartialFromArray(
    146     const void* data, int size, MessageLite* message) {
    147   io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
    148   return InlineParsePartialFromCodedStream(&input, message) &&
    149          input.ConsumedEntireMessage();
    150 }
    151 
    152 }  // namespace
    153 
    154 
    155 MessageLite* MessageLite::New(::google::protobuf::Arena* arena) const {
    156   MessageLite* message = New();
    157   if (arena != NULL) {
    158     arena->Own(message);
    159   }
    160   return message;
    161 }
    162 
    163 bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
    164   return InlineMergeFromCodedStream(input, this);
    165 }
    166 
    167 bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
    168   return InlineParseFromCodedStream(input, this);
    169 }
    170 
    171 bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
    172   return InlineParsePartialFromCodedStream(input, this);
    173 }
    174 
    175 bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
    176   io::CodedInputStream decoder(input);
    177   return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
    178 }
    179 
    180 bool MessageLite::ParsePartialFromZeroCopyStream(
    181     io::ZeroCopyInputStream* input) {
    182   io::CodedInputStream decoder(input);
    183   return ParsePartialFromCodedStream(&decoder) &&
    184          decoder.ConsumedEntireMessage();
    185 }
    186 
    187 bool MessageLite::ParseFromBoundedZeroCopyStream(
    188     io::ZeroCopyInputStream* input, int size) {
    189   io::CodedInputStream decoder(input);
    190   decoder.PushLimit(size);
    191   return ParseFromCodedStream(&decoder) &&
    192          decoder.ConsumedEntireMessage() &&
    193          decoder.BytesUntilLimit() == 0;
    194 }
    195 
    196 bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
    197     io::ZeroCopyInputStream* input, int size) {
    198   io::CodedInputStream decoder(input);
    199   decoder.PushLimit(size);
    200   return ParsePartialFromCodedStream(&decoder) &&
    201          decoder.ConsumedEntireMessage() &&
    202          decoder.BytesUntilLimit() == 0;
    203 }
    204 
    205 bool MessageLite::ParseFromString(const string& data) {
    206   return InlineParseFromArray(data.data(), data.size(), this);
    207 }
    208 
    209 bool MessageLite::ParsePartialFromString(const string& data) {
    210   return InlineParsePartialFromArray(data.data(), data.size(), this);
    211 }
    212 
    213 bool MessageLite::ParseFromArray(const void* data, int size) {
    214   return InlineParseFromArray(data, size, this);
    215 }
    216 
    217 bool MessageLite::ParsePartialFromArray(const void* data, int size) {
    218   return InlineParsePartialFromArray(data, size, this);
    219 }
    220 
    221 
    222 // ===================================================================
    223 
    224 uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
    225   // We only optimize this when using optimize_for = SPEED.  In other cases
    226   // we just use the CodedOutputStream path.
    227   int size = GetCachedSize();
    228   io::ArrayOutputStream out(target, size);
    229   io::CodedOutputStream coded_out(&out);
    230   SerializeWithCachedSizes(&coded_out);
    231   GOOGLE_CHECK(!coded_out.HadError());
    232   return target + size;
    233 }
    234 
    235 bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
    236   GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
    237   return SerializePartialToCodedStream(output);
    238 }
    239 
    240 bool MessageLite::SerializePartialToCodedStream(
    241     io::CodedOutputStream* output) const {
    242   const int size = ByteSize();  // Force size to be cached.
    243   if (size < 0) {
    244     // Messages >2G cannot be serialized due to overflow computing ByteSize.
    245     GOOGLE_LOG(ERROR) << "Error computing ByteSize (possible overflow?).";
    246     return false;
    247   }
    248 
    249   uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
    250   if (buffer != NULL) {
    251     uint8* end = SerializeWithCachedSizesToArray(buffer);
    252     if (end - buffer != size) {
    253       ByteSizeConsistencyError(size, ByteSize(), end - buffer, *this);
    254     }
    255     return true;
    256   } else {
    257     int original_byte_count = output->ByteCount();
    258     SerializeWithCachedSizes(output);
    259     if (output->HadError()) {
    260       return false;
    261     }
    262     int final_byte_count = output->ByteCount();
    263 
    264     if (final_byte_count - original_byte_count != size) {
    265       ByteSizeConsistencyError(size, ByteSize(),
    266                                final_byte_count - original_byte_count, *this);
    267     }
    268 
    269     return true;
    270   }
    271 }
    272 
    273 bool MessageLite::SerializeToZeroCopyStream(
    274     io::ZeroCopyOutputStream* output) const {
    275   io::CodedOutputStream encoder(output);
    276   return SerializeToCodedStream(&encoder);
    277 }
    278 
    279 bool MessageLite::SerializePartialToZeroCopyStream(
    280     io::ZeroCopyOutputStream* output) const {
    281   io::CodedOutputStream encoder(output);
    282   return SerializePartialToCodedStream(&encoder);
    283 }
    284 
    285 bool MessageLite::AppendToString(string* output) const {
    286   GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
    287   return AppendPartialToString(output);
    288 }
    289 
    290 bool MessageLite::AppendPartialToString(string* output) const {
    291   int old_size = output->size();
    292   int byte_size = ByteSize();
    293   if (byte_size < 0) {
    294     // Messages >2G cannot be serialized due to overflow computing ByteSize.
    295     GOOGLE_LOG(ERROR) << "Error computing ByteSize (possible overflow?).";
    296     return false;
    297   }
    298 
    299   STLStringResizeUninitialized(output, old_size + byte_size);
    300   uint8* start =
    301       reinterpret_cast<uint8*>(io::mutable_string_data(output) + old_size);
    302   uint8* end = SerializeWithCachedSizesToArray(start);
    303   if (end - start != byte_size) {
    304     ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this);
    305   }
    306   return true;
    307 }
    308 
    309 bool MessageLite::SerializeToString(string* output) const {
    310   output->clear();
    311   return AppendToString(output);
    312 }
    313 
    314 bool MessageLite::SerializePartialToString(string* output) const {
    315   output->clear();
    316   return AppendPartialToString(output);
    317 }
    318 
    319 bool MessageLite::SerializeToArray(void* data, int size) const {
    320   GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
    321   return SerializePartialToArray(data, size);
    322 }
    323 
    324 bool MessageLite::SerializePartialToArray(void* data, int size) const {
    325   int byte_size = ByteSize();
    326   if (size < byte_size) return false;
    327   uint8* start = reinterpret_cast<uint8*>(data);
    328   uint8* end = SerializeWithCachedSizesToArray(start);
    329   if (end - start != byte_size) {
    330     ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this);
    331   }
    332   return true;
    333 }
    334 
    335 string MessageLite::SerializeAsString() const {
    336   // If the compiler implements the (Named) Return Value Optimization,
    337   // the local variable 'output' will not actually reside on the stack
    338   // of this function, but will be overlaid with the object that the
    339   // caller supplied for the return value to be constructed in.
    340   string output;
    341   if (!AppendToString(&output))
    342     output.clear();
    343   return output;
    344 }
    345 
    346 string MessageLite::SerializePartialAsString() const {
    347   string output;
    348   if (!AppendPartialToString(&output))
    349     output.clear();
    350   return output;
    351 }
    352 
    353 namespace internal {
    354 template<>
    355 MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
    356     const MessageLite* prototype, google::protobuf::Arena* arena) {
    357   return prototype->New(arena);
    358 }
    359 template <>
    360 void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
    361                                             MessageLite* to) {
    362   to->CheckTypeAndMergeFrom(from);
    363 }
    364 template<>
    365 void GenericTypeHandler<string>::Merge(const string& from,
    366                                               string* to) {
    367   *to = from;
    368 }
    369 }  // namespace internal
    370 
    371 }  // namespace protobuf
    372 }  // namespace google
    373