| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. |
| // http://code.google.com/p/protobuf/ |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| // Author: kenton@google.com (Kenton Varda) |
| // Based on original Protocol Buffers design by |
| // Sanjay Ghemawat, Jeff Dean, and others. |
| |
| #include <google/protobuf/reflection_ops.h> |
| #include <google/protobuf/descriptor.h> |
| #include <google/protobuf/unknown_field_set.h> |
| #include <google/protobuf/stubs/strutil.h> |
| |
| namespace google { |
| namespace protobuf { |
| namespace internal { |
| |
| void ReflectionOps::Copy(const Descriptor* descriptor, |
| const Message::Reflection& from, |
| Message::Reflection* to) { |
| if (&from == to) return; |
| Clear(descriptor, to); |
| Merge(descriptor, from, to); |
| } |
| |
| void ReflectionOps::Merge(const Descriptor* descriptor, |
| const Message::Reflection& from, |
| Message::Reflection* to) { |
| GOOGLE_CHECK_NE(&from, to); |
| vector<const FieldDescriptor*> fields; |
| from.ListFields(&fields); |
| for (int i = 0; i < fields.size(); i++) { |
| const FieldDescriptor* field = fields[i]; |
| |
| if (field->is_repeated()) { |
| int count = from.FieldSize(field); |
| for (int j = 0; j < count; j++) { |
| switch (field->cpp_type()) { |
| #define HANDLE_TYPE(CPPTYPE, METHOD) \ |
| case FieldDescriptor::CPPTYPE_##CPPTYPE: \ |
| to->Add##METHOD(field, \ |
| from.GetRepeated##METHOD(field, j)); \ |
| break; |
| |
| HANDLE_TYPE(INT32 , Int32 ); |
| HANDLE_TYPE(INT64 , Int64 ); |
| HANDLE_TYPE(UINT32, UInt32); |
| HANDLE_TYPE(UINT64, UInt64); |
| HANDLE_TYPE(FLOAT , Float ); |
| HANDLE_TYPE(DOUBLE, Double); |
| HANDLE_TYPE(BOOL , Bool ); |
| HANDLE_TYPE(STRING, String); |
| HANDLE_TYPE(ENUM , Enum ); |
| #undef HANDLE_TYPE |
| |
| case FieldDescriptor::CPPTYPE_MESSAGE: |
| to->AddMessage(field)->MergeFrom( |
| from.GetRepeatedMessage(field, j)); |
| break; |
| } |
| } |
| } else if (from.HasField(field)) { |
| switch (field->cpp_type()) { |
| #define HANDLE_TYPE(CPPTYPE, METHOD) \ |
| case FieldDescriptor::CPPTYPE_##CPPTYPE: \ |
| to->Set##METHOD(field, from.Get##METHOD(field)); \ |
| break; |
| |
| HANDLE_TYPE(INT32 , Int32 ); |
| HANDLE_TYPE(INT64 , Int64 ); |
| HANDLE_TYPE(UINT32, UInt32); |
| HANDLE_TYPE(UINT64, UInt64); |
| HANDLE_TYPE(FLOAT , Float ); |
| HANDLE_TYPE(DOUBLE, Double); |
| HANDLE_TYPE(BOOL , Bool ); |
| HANDLE_TYPE(STRING, String); |
| HANDLE_TYPE(ENUM , Enum ); |
| #undef HANDLE_TYPE |
| |
| case FieldDescriptor::CPPTYPE_MESSAGE: |
| to->MutableMessage(field)->MergeFrom( |
| from.GetMessage(field)); |
| break; |
| } |
| } |
| } |
| |
| to->MutableUnknownFields()->MergeFrom(from.GetUnknownFields()); |
| } |
| |
| void ReflectionOps::Clear(const Descriptor* descriptor, |
| Message::Reflection* reflection) { |
| vector<const FieldDescriptor*> fields; |
| reflection->ListFields(&fields); |
| for (int i = 0; i < fields.size(); i++) { |
| reflection->ClearField(fields[i]); |
| } |
| |
| reflection->MutableUnknownFields()->Clear(); |
| } |
| |
| bool ReflectionOps::IsInitialized(const Descriptor* descriptor, |
| const Message::Reflection& reflection) { |
| // Check required fields of this message. |
| for (int i = 0; i < descriptor->field_count(); i++) { |
| if (descriptor->field(i)->is_required()) { |
| if (!reflection.HasField(descriptor->field(i))) { |
| return false; |
| } |
| } |
| } |
| |
| // Check that sub-messages are initialized. |
| vector<const FieldDescriptor*> fields; |
| reflection.ListFields(&fields); |
| for (int i = 0; i < fields.size(); i++) { |
| const FieldDescriptor* field = fields[i]; |
| if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| if (field->is_repeated()) { |
| int size = reflection.FieldSize(field); |
| |
| for (int i = 0; i < size; i++) { |
| if (!reflection.GetRepeatedMessage(field, i).IsInitialized()) { |
| return false; |
| } |
| } |
| } else { |
| if (reflection.HasField(field) && |
| !reflection.GetMessage(field).IsInitialized()) { |
| return false; |
| } |
| } |
| } |
| } |
| |
| return true; |
| } |
| |
| void ReflectionOps::DiscardUnknownFields( |
| const Descriptor* descriptor, |
| Message::Reflection* reflection) { |
| reflection->MutableUnknownFields()->Clear(); |
| |
| vector<const FieldDescriptor*> fields; |
| reflection->ListFields(&fields); |
| for (int i = 0; i < fields.size(); i++) { |
| const FieldDescriptor* field = fields[i]; |
| if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| if (field->is_repeated()) { |
| int size = reflection->FieldSize(field); |
| for (int i = 0; i < size; i++) { |
| reflection->MutableRepeatedMessage(field, i)->DiscardUnknownFields(); |
| } |
| } else { |
| if (reflection->HasField(field)) { |
| reflection->MutableMessage(field)->DiscardUnknownFields(); |
| } |
| } |
| } |
| } |
| } |
| |
| static string SubMessagePrefix(const string& prefix, |
| const FieldDescriptor* field, |
| int index) { |
| string result(prefix); |
| if (field->is_extension()) { |
| result.append("("); |
| result.append(field->full_name()); |
| result.append(")"); |
| } else { |
| result.append(field->name()); |
| } |
| if (index != -1) { |
| result.append("["); |
| result.append(SimpleItoa(index)); |
| result.append("]"); |
| } |
| result.append("."); |
| return result; |
| } |
| |
| void ReflectionOps::FindInitializationErrors( |
| const Descriptor* descriptor, |
| const Message::Reflection& reflection, |
| const string& prefix, |
| vector<string>* errors) { |
| // Check required fields of this message. |
| for (int i = 0; i < descriptor->field_count(); i++) { |
| if (descriptor->field(i)->is_required()) { |
| if (!reflection.HasField(descriptor->field(i))) { |
| errors->push_back(prefix + descriptor->field(i)->name()); |
| } |
| } |
| } |
| |
| // Check sub-messages. |
| vector<const FieldDescriptor*> fields; |
| reflection.ListFields(&fields); |
| for (int i = 0; i < fields.size(); i++) { |
| const FieldDescriptor* field = fields[i]; |
| if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| |
| if (field->is_repeated()) { |
| int size = reflection.FieldSize(field); |
| |
| for (int i = 0; i < size; i++) { |
| const Message& sub_message = reflection.GetRepeatedMessage(field, i); |
| FindInitializationErrors(field->message_type(), |
| *sub_message.GetReflection(), |
| SubMessagePrefix(prefix, field, i), |
| errors); |
| } |
| } else { |
| if (reflection.HasField(field)) { |
| const Message& sub_message = reflection.GetMessage(field); |
| FindInitializationErrors(field->message_type(), |
| *sub_message.GetReflection(), |
| SubMessagePrefix(prefix, field, -1), |
| errors); |
| } |
| } |
| } |
| } |
| } |
| |
| } // namespace internal |
| } // namespace protobuf |
| } // namespace google |