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// Author: kenton@google.com (Kenton Varda) 32// Based on original Protocol Buffers design by 33// Sanjay Ghemawat, Jeff Dean, and others. 34 35#include <google/protobuf/reflection_ops.h> 36#include <google/protobuf/descriptor.h> 37#include <google/protobuf/unknown_field_set.h> 38#include <google/protobuf/stubs/strutil.h> 39 40namespace google { 41namespace protobuf { 42namespace internal { 43 44void ReflectionOps::Copy(const Message& from, Message* to) { 45 if (&from == to) return; 46 Clear(to); 47 Merge(from, to); 48} 49 50void ReflectionOps::Merge(const Message& from, Message* to) { 51 GOOGLE_CHECK_NE(&from, to); 52 53 const Descriptor* descriptor = from.GetDescriptor(); 54 GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor) 55 << "Tried to merge messages of different types."; 56 57 const Reflection* from_reflection = from.GetReflection(); 58 const Reflection* to_reflection = to->GetReflection(); 59 60 vector<const FieldDescriptor*> fields; 61 from_reflection->ListFields(from, &fields); 62 for (int i = 0; i < fields.size(); i++) { 63 const FieldDescriptor* field = fields[i]; 64 65 if (field->is_repeated()) { 66 int count = from_reflection->FieldSize(from, field); 67 for (int j = 0; j < count; j++) { 68 switch (field->cpp_type()) { 69#define HANDLE_TYPE(CPPTYPE, METHOD) \ 70 case FieldDescriptor::CPPTYPE_##CPPTYPE: \ 71 to_reflection->Add##METHOD(to, field, \ 72 from_reflection->GetRepeated##METHOD(from, field, j)); \ 73 break; 74 75 HANDLE_TYPE(INT32 , Int32 ); 76 HANDLE_TYPE(INT64 , Int64 ); 77 HANDLE_TYPE(UINT32, UInt32); 78 HANDLE_TYPE(UINT64, UInt64); 79 HANDLE_TYPE(FLOAT , Float ); 80 HANDLE_TYPE(DOUBLE, Double); 81 HANDLE_TYPE(BOOL , Bool ); 82 HANDLE_TYPE(STRING, String); 83 HANDLE_TYPE(ENUM , Enum ); 84#undef HANDLE_TYPE 85 86 case FieldDescriptor::CPPTYPE_MESSAGE: 87 to_reflection->AddMessage(to, field)->MergeFrom( 88 from_reflection->GetRepeatedMessage(from, field, j)); 89 break; 90 } 91 } 92 } else { 93 switch (field->cpp_type()) { 94#define HANDLE_TYPE(CPPTYPE, METHOD) \ 95 case FieldDescriptor::CPPTYPE_##CPPTYPE: \ 96 to_reflection->Set##METHOD(to, field, \ 97 from_reflection->Get##METHOD(from, field)); \ 98 break; 99 100 HANDLE_TYPE(INT32 , Int32 ); 101 HANDLE_TYPE(INT64 , Int64 ); 102 HANDLE_TYPE(UINT32, UInt32); 103 HANDLE_TYPE(UINT64, UInt64); 104 HANDLE_TYPE(FLOAT , Float ); 105 HANDLE_TYPE(DOUBLE, Double); 106 HANDLE_TYPE(BOOL , Bool ); 107 HANDLE_TYPE(STRING, String); 108 HANDLE_TYPE(ENUM , Enum ); 109#undef HANDLE_TYPE 110 111 case FieldDescriptor::CPPTYPE_MESSAGE: 112 to_reflection->MutableMessage(to, field)->MergeFrom( 113 from_reflection->GetMessage(from, field)); 114 break; 115 } 116 } 117 } 118 119 to_reflection->MutableUnknownFields(to)->MergeFrom( 120 from_reflection->GetUnknownFields(from)); 121} 122 123void ReflectionOps::Clear(Message* message) { 124 const Reflection* reflection = message->GetReflection(); 125 126 vector<const FieldDescriptor*> fields; 127 reflection->ListFields(*message, &fields); 128 for (int i = 0; i < fields.size(); i++) { 129 reflection->ClearField(message, fields[i]); 130 } 131 132 reflection->MutableUnknownFields(message)->Clear(); 133} 134 135bool ReflectionOps::IsInitialized(const Message& message) { 136 const Descriptor* descriptor = message.GetDescriptor(); 137 const Reflection* reflection = message.GetReflection(); 138 139 // Check required fields of this message. 140 for (int i = 0; i < descriptor->field_count(); i++) { 141 if (descriptor->field(i)->is_required()) { 142 if (!reflection->HasField(message, descriptor->field(i))) { 143 return false; 144 } 145 } 146 } 147 148 // Check that sub-messages are initialized. 149 vector<const FieldDescriptor*> fields; 150 reflection->ListFields(message, &fields); 151 for (int i = 0; i < fields.size(); i++) { 152 const FieldDescriptor* field = fields[i]; 153 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 154 if (field->is_repeated()) { 155 int size = reflection->FieldSize(message, field); 156 157 for (int i = 0; i < size; i++) { 158 if (!reflection->GetRepeatedMessage(message, field, i) 159 .IsInitialized()) { 160 return false; 161 } 162 } 163 } else { 164 if (!reflection->GetMessage(message, field).IsInitialized()) { 165 return false; 166 } 167 } 168 } 169 } 170 171 return true; 172} 173 174void ReflectionOps::DiscardUnknownFields(Message* message) { 175 const Reflection* reflection = message->GetReflection(); 176 177 reflection->MutableUnknownFields(message)->Clear(); 178 179 vector<const FieldDescriptor*> fields; 180 reflection->ListFields(*message, &fields); 181 for (int i = 0; i < fields.size(); i++) { 182 const FieldDescriptor* field = fields[i]; 183 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 184 if (field->is_repeated()) { 185 int size = reflection->FieldSize(*message, field); 186 for (int i = 0; i < size; i++) { 187 reflection->MutableRepeatedMessage(message, field, i) 188 ->DiscardUnknownFields(); 189 } 190 } else { 191 reflection->MutableMessage(message, field)->DiscardUnknownFields(); 192 } 193 } 194 } 195} 196 197static string SubMessagePrefix(const string& prefix, 198 const FieldDescriptor* field, 199 int index) { 200 string result(prefix); 201 if (field->is_extension()) { 202 result.append("("); 203 result.append(field->full_name()); 204 result.append(")"); 205 } else { 206 result.append(field->name()); 207 } 208 if (index != -1) { 209 result.append("["); 210 result.append(SimpleItoa(index)); 211 result.append("]"); 212 } 213 result.append("."); 214 return result; 215} 216 217void ReflectionOps::FindInitializationErrors( 218 const Message& message, 219 const string& prefix, 220 vector<string>* errors) { 221 const Descriptor* descriptor = message.GetDescriptor(); 222 const Reflection* reflection = message.GetReflection(); 223 224 // Check required fields of this message. 225 for (int i = 0; i < descriptor->field_count(); i++) { 226 if (descriptor->field(i)->is_required()) { 227 if (!reflection->HasField(message, descriptor->field(i))) { 228 errors->push_back(prefix + descriptor->field(i)->name()); 229 } 230 } 231 } 232 233 // Check sub-messages. 234 vector<const FieldDescriptor*> fields; 235 reflection->ListFields(message, &fields); 236 for (int i = 0; i < fields.size(); i++) { 237 const FieldDescriptor* field = fields[i]; 238 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { 239 240 if (field->is_repeated()) { 241 int size = reflection->FieldSize(message, field); 242 243 for (int i = 0; i < size; i++) { 244 const Message& sub_message = 245 reflection->GetRepeatedMessage(message, field, i); 246 FindInitializationErrors(sub_message, 247 SubMessagePrefix(prefix, field, i), 248 errors); 249 } 250 } else { 251 const Message& sub_message = reflection->GetMessage(message, field); 252 FindInitializationErrors(sub_message, 253 SubMessagePrefix(prefix, field, -1), 254 errors); 255 } 256 } 257 } 258} 259 260} // namespace internal 261} // namespace protobuf 262} // namespace google 263