| 981 | } |
| 982 | |
| 983 | void WriteAMFObject(const google::protobuf::Message& message, |
| 984 | AMFOutputStream* stream) { |
| 985 | stream->put_u8(AMF_MARKER_OBJECT); |
| 986 | const google::protobuf::Descriptor* desc = message.GetDescriptor(); |
| 987 | const google::protobuf::Reflection* reflection = message.GetReflection(); |
| 988 | for (int i = 0; i < desc->field_count(); ++i) { |
| 989 | const google::protobuf::FieldDescriptor* field = desc->field(i); |
| 990 | if (field->is_repeated()) { |
| 991 | LOG(ERROR) << "Repeated fields are not supported yet"; |
| 992 | return stream->set_bad(); |
| 993 | } |
| 994 | const bool has_field = reflection->HasField(message, field); |
| 995 | if (!has_field) { |
| 996 | if (field->is_required()) { |
| 997 | LOG(ERROR) << "Missing required field=" << field->full_name(); |
| 998 | return stream->set_bad(); |
| 999 | } else { |
| 1000 | continue; |
| 1001 | } |
| 1002 | } |
| 1003 | const auto& name = field->name(); |
| 1004 | if (name.size() >= 65536u) { |
| 1005 | LOG(ERROR) << "name is too long!"; |
| 1006 | return stream->set_bad(); |
| 1007 | } |
| 1008 | stream->put_u16(name.size()); |
| 1009 | stream->putn(name.data(), name.size()); |
| 1010 | switch (field->cpp_type()) { |
| 1011 | case google::protobuf::FieldDescriptor::CPPTYPE_INT32: |
| 1012 | case google::protobuf::FieldDescriptor::CPPTYPE_INT64: |
| 1013 | case google::protobuf::FieldDescriptor::CPPTYPE_UINT32: |
| 1014 | case google::protobuf::FieldDescriptor::CPPTYPE_UINT64: |
| 1015 | LOG(ERROR) << "AMF does not have integers"; |
| 1016 | return stream->set_bad(); |
| 1017 | case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: { |
| 1018 | stream->put_u8(AMF_MARKER_NUMBER); |
| 1019 | const double val = reflection->GetDouble(message, field); |
| 1020 | uint64_t* uptr = (uint64_t*)&val; |
| 1021 | stream->put_u64(*uptr); |
| 1022 | } break; |
| 1023 | case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: |
| 1024 | LOG(ERROR) << "AMF does not have float, use double instead"; |
| 1025 | return stream->set_bad(); |
| 1026 | case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: { |
| 1027 | stream->put_u8(AMF_MARKER_BOOLEAN); |
| 1028 | const bool val = reflection->GetBool(message, field); |
| 1029 | stream->put_u8(val); |
| 1030 | } break; |
| 1031 | case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: |
| 1032 | LOG(ERROR) << "AMF does not have enum"; |
| 1033 | return stream->set_bad(); |
| 1034 | case google::protobuf::FieldDescriptor::CPPTYPE_STRING: { |
| 1035 | const std::string val = reflection->GetString(message, field); |
| 1036 | if (val.size() < 65536u) { |
| 1037 | stream->put_u8(AMF_MARKER_STRING); |
| 1038 | stream->put_u16(val.size()); |
| 1039 | stream->putn(val.data(), val.size()); |
| 1040 | } else { |