aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/message.cc
diff options
context:
space:
mode:
authorGravatar temporal <temporal@630680e5-0e50-0410-840e-4b1c322b438d>2008-07-10 02:12:20 +0000
committerGravatar temporal <temporal@630680e5-0e50-0410-840e-4b1c322b438d>2008-07-10 02:12:20 +0000
commit40ee551715c3a784ea6132dbf604b0e665ca2def (patch)
tree6e3ea9674be5b0f59106f88f3afa1313854beebf /src/google/protobuf/message.cc
Initial checkin.
Diffstat (limited to 'src/google/protobuf/message.cc')
-rw-r--r--src/google/protobuf/message.cc345
1 files changed, 345 insertions, 0 deletions
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
new file mode 100644
index 00000000..f740ef18
--- /dev/null
+++ b/src/google/protobuf/message.cc
@@ -0,0 +1,345 @@
+// 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 <stack>
+#include <google/protobuf/stubs/hash.h>
+
+#include <google/protobuf/message.h>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+#include <google/protobuf/stubs/map-util.h>
+
+namespace google {
+namespace protobuf {
+
+using internal::WireFormat;
+using internal::ReflectionOps;
+
+static string InitializationErrorMessage(const char* action,
+ const Message& message) {
+ return strings::Substitute(
+ "Can't $0 message of type \"$1\" because it is missing required "
+ "fields: $2",
+ action, message.GetDescriptor()->full_name(),
+ message.InitializationErrorString());
+}
+
+Message::~Message() {}
+Message::Reflection::~Reflection() {}
+
+void Message::MergeFrom(const Message& from) {
+ const Descriptor* descriptor = GetDescriptor();
+ GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
+ << ": Tried to merge from a message with a different type. "
+ "to: " << descriptor->full_name() << ", "
+ "from:" << from.GetDescriptor()->full_name();
+ ReflectionOps::Merge(descriptor, *from.GetReflection(), GetReflection());
+}
+
+void Message::CopyFrom(const Message& from) {
+ const Descriptor* descriptor = GetDescriptor();
+ GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
+ << ": Tried to copy from a message with a different type."
+ "to: " << descriptor->full_name() << ", "
+ "from:" << from.GetDescriptor()->full_name();
+ ReflectionOps::Copy(descriptor, *from.GetReflection(), GetReflection());
+}
+
+void Message::Clear() {
+ ReflectionOps::Clear(GetDescriptor(), GetReflection());
+}
+
+bool Message::IsInitialized() const {
+ return ReflectionOps::IsInitialized(GetDescriptor(), *GetReflection());
+}
+
+void Message::FindInitializationErrors(vector<string>* errors) const {
+ return ReflectionOps::FindInitializationErrors(
+ GetDescriptor(), *GetReflection(), "", errors);
+}
+
+string Message::InitializationErrorString() const {
+ vector<string> errors;
+ FindInitializationErrors(&errors);
+ return JoinStrings(errors, ", ");
+}
+
+void Message::CheckInitialized() const {
+ GOOGLE_CHECK(IsInitialized())
+ << "Message of type \"" << GetDescriptor()->full_name()
+ << "\" is missing required fields: " << InitializationErrorString();
+}
+
+void Message::DiscardUnknownFields() {
+ return ReflectionOps::DiscardUnknownFields(GetDescriptor(), GetReflection());
+}
+
+bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) {
+ return WireFormat::ParseAndMergePartial(
+ GetDescriptor(), input, GetReflection());
+}
+
+bool Message::MergeFromCodedStream(io::CodedInputStream* input) {
+ if (!MergePartialFromCodedStream(input)) return false;
+ if (!IsInitialized()) {
+ GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *this);
+ return false;
+ }
+ return true;
+}
+
+bool Message::ParseFromCodedStream(io::CodedInputStream* input) {
+ Clear();
+ return MergeFromCodedStream(input);
+}
+
+bool Message::ParsePartialFromCodedStream(io::CodedInputStream* input) {
+ Clear();
+ return MergePartialFromCodedStream(input);
+}
+
+bool Message::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+ io::CodedInputStream decoder(input);
+ return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
+}
+
+bool Message::ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input) {
+ io::CodedInputStream decoder(input);
+ return ParsePartialFromCodedStream(&decoder) &&
+ decoder.ConsumedEntireMessage();
+}
+
+bool Message::ParseFromString(const string& data) {
+ io::ArrayInputStream input(data.data(), data.size());
+ return ParseFromZeroCopyStream(&input);
+}
+
+bool Message::ParsePartialFromString(const string& data) {
+ io::ArrayInputStream input(data.data(), data.size());
+ return ParsePartialFromZeroCopyStream(&input);
+}
+
+bool Message::ParseFromArray(const void* data, int size) {
+ io::ArrayInputStream input(data, size);
+ return ParseFromZeroCopyStream(&input);
+}
+
+bool Message::ParsePartialFromArray(const void* data, int size) {
+ io::ArrayInputStream input(data, size);
+ return ParsePartialFromZeroCopyStream(&input);
+}
+
+bool Message::ParseFromFileDescriptor(int file_descriptor) {
+ io::FileInputStream input(file_descriptor);
+ return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool Message::ParsePartialFromFileDescriptor(int file_descriptor) {
+ io::FileInputStream input(file_descriptor);
+ return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
+}
+
+bool Message::ParseFromIstream(istream* input) {
+ io::IstreamInputStream zero_copy_input(input);
+ return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+bool Message::ParsePartialFromIstream(istream* input) {
+ io::IstreamInputStream zero_copy_input(input);
+ return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
+}
+
+
+
+bool Message::SerializeWithCachedSizes(
+ io::CodedOutputStream* output) const {
+ return WireFormat::SerializeWithCachedSizes(
+ GetDescriptor(), GetReflection(), GetCachedSize(), output);
+}
+
+int Message::ByteSize() const {
+ int size = WireFormat::ByteSize(GetDescriptor(), GetReflection());
+ SetCachedSize(size);
+ return size;
+}
+
+void Message::SetCachedSize(int size) const {
+ GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
+ << "\" implements neither SetCachedSize() nor ByteSize(). "
+ "Must implement one or the other.";
+}
+
+bool Message::SerializeToCodedStream(io::CodedOutputStream* output) const {
+ GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+ return SerializePartialToCodedStream(output);
+}
+
+bool Message::SerializePartialToCodedStream(
+ io::CodedOutputStream* output) const {
+ ByteSize(); // Force size to be cached.
+ if (!SerializeWithCachedSizes(output)) return false;
+ return true;
+}
+
+bool Message::SerializeToZeroCopyStream(
+ io::ZeroCopyOutputStream* output) const {
+ io::CodedOutputStream encoder(output);
+ return SerializeToCodedStream(&encoder);
+}
+
+bool Message::SerializePartialToZeroCopyStream(
+ io::ZeroCopyOutputStream* output) const {
+ io::CodedOutputStream encoder(output);
+ return SerializePartialToCodedStream(&encoder);
+}
+
+bool Message::AppendToString(string* output) const {
+ GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
+ return AppendPartialToString(output);
+}
+
+bool Message::AppendPartialToString(string* output) const {
+ // For efficiency, we'd like to reserve the exact amount of space we need
+ // in the string.
+ int total_size = output->size() + ByteSize();
+ output->reserve(total_size);
+
+ io::StringOutputStream output_stream(output);
+
+ {
+ io::CodedOutputStream encoder(&output_stream);
+ if (!SerializeWithCachedSizes(&encoder)) return false;
+ }
+
+ GOOGLE_CHECK_EQ(output_stream.ByteCount(), total_size);
+ return true;
+}
+
+bool Message::SerializeToString(string* output) const {
+ output->clear();
+ return AppendToString(output);
+}
+
+bool Message::SerializePartialToString(string* output) const {
+ output->clear();
+ return AppendPartialToString(output);
+}
+
+bool Message::SerializeToArray(void* data, int size) const {
+ io::ArrayOutputStream output_stream(data, size);
+ return SerializeToZeroCopyStream(&output_stream);
+}
+
+bool Message::SerializePartialToArray(void* data, int size) const {
+ io::ArrayOutputStream output_stream(data, size);
+ return SerializePartialToZeroCopyStream(&output_stream);
+}
+
+bool Message::SerializeToFileDescriptor(int file_descriptor) const {
+ io::FileOutputStream output(file_descriptor);
+ return SerializeToZeroCopyStream(&output);
+}
+
+bool Message::SerializePartialToFileDescriptor(int file_descriptor) const {
+ io::FileOutputStream output(file_descriptor);
+ return SerializePartialToZeroCopyStream(&output);
+}
+
+bool Message::SerializeToOstream(ostream* output) const {
+ io::OstreamOutputStream zero_copy_output(output);
+ return SerializeToZeroCopyStream(&zero_copy_output);
+}
+
+bool Message::SerializePartialToOstream(ostream* output) const {
+ io::OstreamOutputStream zero_copy_output(output);
+ return SerializePartialToZeroCopyStream(&zero_copy_output);
+}
+
+
+// ===================================================================
+// MessageFactory
+
+MessageFactory::~MessageFactory() {}
+
+namespace {
+
+class GeneratedMessageFactory : public MessageFactory {
+ public:
+ GeneratedMessageFactory();
+ ~GeneratedMessageFactory();
+
+ static GeneratedMessageFactory* singleton();
+
+ void RegisterType(const Descriptor* descriptor, const Message* prototype);
+
+ // implements MessageFactory ---------------------------------------
+ const Message* GetPrototype(const Descriptor* type);
+
+ private:
+ hash_map<const Descriptor*, const Message*> type_map_;
+};
+
+GeneratedMessageFactory::GeneratedMessageFactory() {}
+GeneratedMessageFactory::~GeneratedMessageFactory() {}
+
+GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
+ // No need for thread-safety here because this will be called at static
+ // initialization time. (And GCC4 makes this thread-safe anyway.)
+ static GeneratedMessageFactory singleton;
+ return &singleton;
+}
+
+void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
+ const Message* prototype) {
+ GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
+ << "Tried to register a non-generated type with the generated "
+ "type registry.";
+
+ if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
+ GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
+ }
+}
+
+const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
+ return FindPtrOrNull(type_map_, type);
+}
+
+} // namespace
+
+MessageFactory* MessageFactory::generated_factory() {
+ return GeneratedMessageFactory::singleton();
+}
+
+void MessageFactory::InternalRegisterGeneratedMessage(
+ const Descriptor* descriptor, const Message* prototype) {
+ GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
+}
+
+
+} // namespace protobuf
+} // namespace google