1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ipc/ipc_message_utils.h"
7 #include "base/files/file_path.h"
8 #include "base/json/json_writer.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/strings/nullable_string16.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/time/time.h"
14 #include "base/values.h"
15 #include "ipc/ipc_channel_handle.h"
18 #include "ipc/file_descriptor_set_posix.h"
27 const int kMaxRecursionDepth
= 100;
29 template<typename CharType
>
30 void LogBytes(const std::vector
<CharType
>& data
, std::string
* out
) {
32 // Windows has a GUI for logging, which can handle arbitrary binary data.
33 for (size_t i
= 0; i
< data
.size(); ++i
)
34 out
->push_back(data
[i
]);
36 // On POSIX, we log to stdout, which we assume can display ASCII.
37 static const size_t kMaxBytesToLog
= 100;
38 for (size_t i
= 0; i
< std::min(data
.size(), kMaxBytesToLog
); ++i
) {
40 out
->push_back(data
[i
]);
43 base::StringPrintf("[%02X]", static_cast<unsigned char>(data
[i
])));
45 if (data
.size() > kMaxBytesToLog
) {
46 out
->append(base::StringPrintf(
48 static_cast<unsigned>(data
.size() - kMaxBytesToLog
)));
53 bool ReadValue(const Message
* m
, PickleIterator
* iter
, base::Value
** value
,
56 void WriteValue(Message
* m
, const base::Value
* value
, int recursion
) {
58 if (recursion
> kMaxRecursionDepth
) {
59 LOG(WARNING
) << "Max recursion depth hit in WriteValue.";
63 m
->WriteInt(value
->GetType());
65 switch (value
->GetType()) {
66 case base::Value::TYPE_NULL
:
68 case base::Value::TYPE_BOOLEAN
: {
70 result
= value
->GetAsBoolean(&val
);
75 case base::Value::TYPE_INTEGER
: {
77 result
= value
->GetAsInteger(&val
);
82 case base::Value::TYPE_DOUBLE
: {
84 result
= value
->GetAsDouble(&val
);
89 case base::Value::TYPE_STRING
: {
91 result
= value
->GetAsString(&val
);
96 case base::Value::TYPE_BINARY
: {
97 const base::BinaryValue
* binary
=
98 static_cast<const base::BinaryValue
*>(value
);
99 m
->WriteData(binary
->GetBuffer(), static_cast<int>(binary
->GetSize()));
102 case base::Value::TYPE_DICTIONARY
: {
103 const base::DictionaryValue
* dict
=
104 static_cast<const base::DictionaryValue
*>(value
);
106 WriteParam(m
, static_cast<int>(dict
->size()));
108 for (base::DictionaryValue::Iterator
it(*dict
); !it
.IsAtEnd();
110 WriteParam(m
, it
.key());
111 WriteValue(m
, &it
.value(), recursion
+ 1);
115 case base::Value::TYPE_LIST
: {
116 const base::ListValue
* list
= static_cast<const base::ListValue
*>(value
);
117 WriteParam(m
, static_cast<int>(list
->GetSize()));
118 for (base::ListValue::const_iterator it
= list
->begin();
119 it
!= list
->end(); ++it
) {
120 WriteValue(m
, *it
, recursion
+ 1);
127 // Helper for ReadValue that reads a DictionaryValue into a pre-allocated
129 bool ReadDictionaryValue(const Message
* m
, PickleIterator
* iter
,
130 base::DictionaryValue
* value
, int recursion
) {
132 if (!ReadParam(m
, iter
, &size
))
135 for (int i
= 0; i
< size
; ++i
) {
138 if (!ReadParam(m
, iter
, &key
) ||
139 !ReadValue(m
, iter
, &subval
, recursion
+ 1))
141 value
->SetWithoutPathExpansion(key
, subval
);
147 // Helper for ReadValue that reads a ReadListValue into a pre-allocated
149 bool ReadListValue(const Message
* m
, PickleIterator
* iter
,
150 base::ListValue
* value
, int recursion
) {
152 if (!ReadParam(m
, iter
, &size
))
155 for (int i
= 0; i
< size
; ++i
) {
157 if (!ReadValue(m
, iter
, &subval
, recursion
+ 1))
159 value
->Set(i
, subval
);
165 bool ReadValue(const Message
* m
, PickleIterator
* iter
, base::Value
** value
,
167 if (recursion
> kMaxRecursionDepth
) {
168 LOG(WARNING
) << "Max recursion depth hit in ReadValue.";
173 if (!ReadParam(m
, iter
, &type
))
177 case base::Value::TYPE_NULL
:
178 *value
= base::Value::CreateNullValue();
180 case base::Value::TYPE_BOOLEAN
: {
182 if (!ReadParam(m
, iter
, &val
))
184 *value
= new base::FundamentalValue(val
);
187 case base::Value::TYPE_INTEGER
: {
189 if (!ReadParam(m
, iter
, &val
))
191 *value
= new base::FundamentalValue(val
);
194 case base::Value::TYPE_DOUBLE
: {
196 if (!ReadParam(m
, iter
, &val
))
198 *value
= new base::FundamentalValue(val
);
201 case base::Value::TYPE_STRING
: {
203 if (!ReadParam(m
, iter
, &val
))
205 *value
= new base::StringValue(val
);
208 case base::Value::TYPE_BINARY
: {
211 if (!m
->ReadData(iter
, &data
, &length
))
213 *value
= base::BinaryValue::CreateWithCopiedBuffer(data
, length
);
216 case base::Value::TYPE_DICTIONARY
: {
217 scoped_ptr
<base::DictionaryValue
> val(new base::DictionaryValue());
218 if (!ReadDictionaryValue(m
, iter
, val
.get(), recursion
))
220 *value
= val
.release();
223 case base::Value::TYPE_LIST
: {
224 scoped_ptr
<base::ListValue
> val(new base::ListValue());
225 if (!ReadListValue(m
, iter
, val
.get(), recursion
))
227 *value
= val
.release();
239 // -----------------------------------------------------------------------------
249 LogData::~LogData() {
252 void ParamTraits
<bool>::Log(const param_type
& p
, std::string
* l
) {
253 l
->append(p
? "true" : "false");
256 void ParamTraits
<unsigned char>::Write(Message
* m
, const param_type
& p
) {
257 m
->WriteBytes(&p
, sizeof(param_type
));
260 bool ParamTraits
<unsigned char>::Read(const Message
* m
, PickleIterator
* iter
,
263 if (!m
->ReadBytes(iter
, &data
, sizeof(param_type
)))
265 memcpy(r
, data
, sizeof(param_type
));
269 void ParamTraits
<unsigned char>::Log(const param_type
& p
, std::string
* l
) {
270 l
->append(base::UintToString(p
));
273 void ParamTraits
<unsigned short>::Write(Message
* m
, const param_type
& p
) {
274 m
->WriteBytes(&p
, sizeof(param_type
));
277 bool ParamTraits
<unsigned short>::Read(const Message
* m
, PickleIterator
* iter
,
280 if (!m
->ReadBytes(iter
, &data
, sizeof(param_type
)))
282 memcpy(r
, data
, sizeof(param_type
));
286 void ParamTraits
<unsigned short>::Log(const param_type
& p
, std::string
* l
) {
287 l
->append(base::UintToString(p
));
290 void ParamTraits
<int>::Log(const param_type
& p
, std::string
* l
) {
291 l
->append(base::IntToString(p
));
294 void ParamTraits
<unsigned int>::Log(const param_type
& p
, std::string
* l
) {
295 l
->append(base::UintToString(p
));
298 void ParamTraits
<long>::Log(const param_type
& p
, std::string
* l
) {
299 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
302 void ParamTraits
<unsigned long>::Log(const param_type
& p
, std::string
* l
) {
303 l
->append(base::Uint64ToString(static_cast<uint64
>(p
)));
306 void ParamTraits
<long long>::Log(const param_type
& p
, std::string
* l
) {
307 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
310 void ParamTraits
<unsigned long long>::Log(const param_type
& p
, std::string
* l
) {
311 l
->append(base::Uint64ToString(p
));
314 void ParamTraits
<float>::Write(Message
* m
, const param_type
& p
) {
315 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(param_type
));
318 bool ParamTraits
<float>::Read(const Message
* m
, PickleIterator
* iter
,
322 if (!m
->ReadData(iter
, &data
, &data_size
) ||
323 data_size
!= sizeof(param_type
)) {
327 memcpy(r
, data
, sizeof(param_type
));
331 void ParamTraits
<float>::Log(const param_type
& p
, std::string
* l
) {
332 l
->append(base::StringPrintf("%e", p
));
335 void ParamTraits
<double>::Write(Message
* m
, const param_type
& p
) {
336 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(param_type
));
339 bool ParamTraits
<double>::Read(const Message
* m
, PickleIterator
* iter
,
343 if (!m
->ReadData(iter
, &data
, &data_size
) ||
344 data_size
!= sizeof(param_type
)) {
348 memcpy(r
, data
, sizeof(param_type
));
352 void ParamTraits
<double>::Log(const param_type
& p
, std::string
* l
) {
353 l
->append(base::StringPrintf("%e", p
));
357 void ParamTraits
<std::string
>::Log(const param_type
& p
, std::string
* l
) {
361 void ParamTraits
<std::wstring
>::Log(const param_type
& p
, std::string
* l
) {
362 l
->append(WideToUTF8(p
));
365 #if !defined(WCHAR_T_IS_UTF16)
366 void ParamTraits
<string16
>::Log(const param_type
& p
, std::string
* l
) {
367 l
->append(UTF16ToUTF8(p
));
371 void ParamTraits
<std::vector
<char> >::Write(Message
* m
, const param_type
& p
) {
373 m
->WriteData(NULL
, 0);
375 m
->WriteData(&p
.front(), static_cast<int>(p
.size()));
379 bool ParamTraits
<std::vector
<char> >::Read(const Message
* m
,
380 PickleIterator
* iter
,
384 if (!m
->ReadData(iter
, &data
, &data_size
) || data_size
< 0)
386 r
->resize(data_size
);
388 memcpy(&r
->front(), data
, data_size
);
392 void ParamTraits
<std::vector
<char> >::Log(const param_type
& p
, std::string
* l
) {
396 void ParamTraits
<std::vector
<unsigned char> >::Write(Message
* m
,
397 const param_type
& p
) {
399 m
->WriteData(NULL
, 0);
401 m
->WriteData(reinterpret_cast<const char*>(&p
.front()),
402 static_cast<int>(p
.size()));
406 bool ParamTraits
<std::vector
<unsigned char> >::Read(const Message
* m
,
407 PickleIterator
* iter
,
411 if (!m
->ReadData(iter
, &data
, &data_size
) || data_size
< 0)
413 r
->resize(data_size
);
415 memcpy(&r
->front(), data
, data_size
);
419 void ParamTraits
<std::vector
<unsigned char> >::Log(const param_type
& p
,
424 void ParamTraits
<std::vector
<bool> >::Write(Message
* m
, const param_type
& p
) {
425 WriteParam(m
, static_cast<int>(p
.size()));
426 // Cast to bool below is required because libc++'s
427 // vector<bool>::const_reference is different from bool, and we want to avoid
428 // writing an extra specialization of ParamTraits for it.
429 for (size_t i
= 0; i
< p
.size(); i
++)
430 WriteParam(m
, static_cast<bool>(p
[i
]));
433 bool ParamTraits
<std::vector
<bool> >::Read(const Message
* m
,
434 PickleIterator
* iter
,
437 // ReadLength() checks for < 0 itself.
438 if (!m
->ReadLength(iter
, &size
))
441 for (int i
= 0; i
< size
; i
++) {
443 if (!ReadParam(m
, iter
, &value
))
450 void ParamTraits
<std::vector
<bool> >::Log(const param_type
& p
, std::string
* l
) {
451 for (size_t i
= 0; i
< p
.size(); ++i
) {
454 LogParam(static_cast<bool>(p
[i
]), l
);
458 void ParamTraits
<base::DictionaryValue
>::Write(Message
* m
,
459 const param_type
& p
) {
460 WriteValue(m
, &p
, 0);
463 bool ParamTraits
<base::DictionaryValue
>::Read(
464 const Message
* m
, PickleIterator
* iter
, param_type
* r
) {
466 if (!ReadParam(m
, iter
, &type
) || type
!= base::Value::TYPE_DICTIONARY
)
469 return ReadDictionaryValue(m
, iter
, r
, 0);
472 void ParamTraits
<base::DictionaryValue
>::Log(const param_type
& p
,
475 base::JSONWriter::Write(&p
, &json
);
479 #if defined(OS_POSIX)
480 void ParamTraits
<base::FileDescriptor
>::Write(Message
* m
, const param_type
& p
) {
481 const bool valid
= p
.fd
>= 0;
482 WriteParam(m
, valid
);
485 if (!m
->WriteFileDescriptor(p
))
490 bool ParamTraits
<base::FileDescriptor
>::Read(const Message
* m
,
491 PickleIterator
* iter
,
494 if (!ReadParam(m
, iter
, &valid
))
499 r
->auto_close
= false;
503 return m
->ReadFileDescriptor(iter
, r
);
506 void ParamTraits
<base::FileDescriptor
>::Log(const param_type
& p
,
509 l
->append(base::StringPrintf("FD(%d auto-close)", p
.fd
));
511 l
->append(base::StringPrintf("FD(%d)", p
.fd
));
514 #endif // defined(OS_POSIX)
516 void ParamTraits
<base::FilePath
>::Write(Message
* m
, const param_type
& p
) {
520 bool ParamTraits
<base::FilePath
>::Read(const Message
* m
,
521 PickleIterator
* iter
,
523 return r
->ReadFromPickle(iter
);
526 void ParamTraits
<base::FilePath
>::Log(const param_type
& p
, std::string
* l
) {
527 ParamTraits
<base::FilePath::StringType
>::Log(p
.value(), l
);
530 void ParamTraits
<base::ListValue
>::Write(Message
* m
, const param_type
& p
) {
531 WriteValue(m
, &p
, 0);
534 bool ParamTraits
<base::ListValue
>::Read(
535 const Message
* m
, PickleIterator
* iter
, param_type
* r
) {
537 if (!ReadParam(m
, iter
, &type
) || type
!= base::Value::TYPE_LIST
)
540 return ReadListValue(m
, iter
, r
, 0);
543 void ParamTraits
<base::ListValue
>::Log(const param_type
& p
, std::string
* l
) {
545 base::JSONWriter::Write(&p
, &json
);
549 void ParamTraits
<base::NullableString16
>::Write(Message
* m
,
550 const param_type
& p
) {
551 WriteParam(m
, p
.string());
552 WriteParam(m
, p
.is_null());
555 bool ParamTraits
<base::NullableString16
>::Read(const Message
* m
,
556 PickleIterator
* iter
,
559 if (!ReadParam(m
, iter
, &string
))
562 if (!ReadParam(m
, iter
, &is_null
))
564 *r
= base::NullableString16(string
, is_null
);
568 void ParamTraits
<base::NullableString16
>::Log(const param_type
& p
,
571 LogParam(p
.string(), l
);
573 LogParam(p
.is_null(), l
);
577 void ParamTraits
<base::PlatformFileInfo
>::Write(Message
* m
,
578 const param_type
& p
) {
579 WriteParam(m
, p
.size
);
580 WriteParam(m
, p
.is_directory
);
581 WriteParam(m
, p
.last_modified
.ToDoubleT());
582 WriteParam(m
, p
.last_accessed
.ToDoubleT());
583 WriteParam(m
, p
.creation_time
.ToDoubleT());
586 bool ParamTraits
<base::PlatformFileInfo
>::Read(const Message
* m
,
587 PickleIterator
* iter
,
589 double last_modified
;
590 double last_accessed
;
591 double creation_time
;
593 ReadParam(m
, iter
, &p
->size
) &&
594 ReadParam(m
, iter
, &p
->is_directory
) &&
595 ReadParam(m
, iter
, &last_modified
) &&
596 ReadParam(m
, iter
, &last_accessed
) &&
597 ReadParam(m
, iter
, &creation_time
);
599 p
->last_modified
= base::Time::FromDoubleT(last_modified
);
600 p
->last_accessed
= base::Time::FromDoubleT(last_accessed
);
601 p
->creation_time
= base::Time::FromDoubleT(creation_time
);
606 void ParamTraits
<base::PlatformFileInfo
>::Log(const param_type
& p
,
611 LogParam(p
.is_directory
, l
);
613 LogParam(p
.last_modified
.ToDoubleT(), l
);
615 LogParam(p
.last_accessed
.ToDoubleT(), l
);
617 LogParam(p
.creation_time
.ToDoubleT(), l
);
621 void ParamTraits
<base::Time
>::Write(Message
* m
, const param_type
& p
) {
622 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
625 bool ParamTraits
<base::Time
>::Read(const Message
* m
, PickleIterator
* iter
,
628 if (!ParamTraits
<int64
>::Read(m
, iter
, &value
))
630 *r
= base::Time::FromInternalValue(value
);
634 void ParamTraits
<base::Time
>::Log(const param_type
& p
, std::string
* l
) {
635 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
638 void ParamTraits
<base::TimeDelta
>::Write(Message
* m
, const param_type
& p
) {
639 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
642 bool ParamTraits
<base::TimeDelta
>::Read(const Message
* m
,
643 PickleIterator
* iter
,
646 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
648 *r
= base::TimeDelta::FromInternalValue(value
);
653 void ParamTraits
<base::TimeDelta
>::Log(const param_type
& p
, std::string
* l
) {
654 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
657 void ParamTraits
<base::TimeTicks
>::Write(Message
* m
, const param_type
& p
) {
658 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
661 bool ParamTraits
<base::TimeTicks
>::Read(const Message
* m
,
662 PickleIterator
* iter
,
665 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
667 *r
= base::TimeTicks::FromInternalValue(value
);
672 void ParamTraits
<base::TimeTicks
>::Log(const param_type
& p
, std::string
* l
) {
673 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
676 void ParamTraits
<IPC::ChannelHandle
>::Write(Message
* m
, const param_type
& p
) {
678 // On Windows marshalling pipe handle is not supported.
679 DCHECK(p
.pipe
.handle
== NULL
);
680 #endif // defined (OS_WIN)
681 WriteParam(m
, p
.name
);
682 #if defined(OS_POSIX)
683 WriteParam(m
, p
.socket
);
687 bool ParamTraits
<IPC::ChannelHandle
>::Read(const Message
* m
,
688 PickleIterator
* iter
,
690 return ReadParam(m
, iter
, &r
->name
)
691 #if defined(OS_POSIX)
692 && ReadParam(m
, iter
, &r
->socket
)
697 void ParamTraits
<IPC::ChannelHandle
>::Log(const param_type
& p
,
699 l
->append(base::StringPrintf("ChannelHandle(%s", p
.name
.c_str()));
700 #if defined(OS_POSIX)
702 ParamTraits
<base::FileDescriptor
>::Log(p
.socket
, l
);
707 void ParamTraits
<LogData
>::Write(Message
* m
, const param_type
& p
) {
708 WriteParam(m
, p
.channel
);
709 WriteParam(m
, p
.routing_id
);
710 WriteParam(m
, p
.type
);
711 WriteParam(m
, p
.flags
);
712 WriteParam(m
, p
.sent
);
713 WriteParam(m
, p
.receive
);
714 WriteParam(m
, p
.dispatch
);
715 WriteParam(m
, p
.message_name
);
716 WriteParam(m
, p
.params
);
719 bool ParamTraits
<LogData
>::Read(const Message
* m
,
720 PickleIterator
* iter
,
723 ReadParam(m
, iter
, &r
->channel
) &&
724 ReadParam(m
, iter
, &r
->routing_id
) &&
725 ReadParam(m
, iter
, &r
->type
) &&
726 ReadParam(m
, iter
, &r
->flags
) &&
727 ReadParam(m
, iter
, &r
->sent
) &&
728 ReadParam(m
, iter
, &r
->receive
) &&
729 ReadParam(m
, iter
, &r
->dispatch
) &&
730 ReadParam(m
, iter
, &r
->message_name
) &&
731 ReadParam(m
, iter
, &r
->params
);
734 void ParamTraits
<LogData
>::Log(const param_type
& p
, std::string
* l
) {
735 // Doesn't make sense to implement this!
738 void ParamTraits
<Message
>::Write(Message
* m
, const Message
& p
) {
739 #if defined(OS_POSIX)
740 // We don't serialize the file descriptors in the nested message, so there
741 // better not be any.
742 DCHECK(!p
.HasFileDescriptors());
745 // Don't just write out the message. This is used to send messages between
746 // NaCl (Posix environment) and the browser (could be on Windows). The message
747 // header formats differ between these systems (so does handle sharing, but
748 // we already asserted we don't have any handles). So just write out the
749 // parts of the header we use.
751 // Be careful also to use only explicitly-sized types. The NaCl environment
752 // could be 64-bit and the host browser could be 32-bits. The nested message
753 // may or may not be safe to send between 32-bit and 64-bit systems, but we
754 // leave that up to the code sending the message to ensure.
755 m
->WriteUInt32(static_cast<uint32
>(p
.routing_id()));
756 m
->WriteUInt32(p
.type());
757 m
->WriteUInt32(p
.flags());
758 m
->WriteData(p
.payload(), static_cast<uint32
>(p
.payload_size()));
761 bool ParamTraits
<Message
>::Read(const Message
* m
, PickleIterator
* iter
,
763 uint32 routing_id
, type
, flags
;
764 if (!m
->ReadUInt32(iter
, &routing_id
) ||
765 !m
->ReadUInt32(iter
, &type
) ||
766 !m
->ReadUInt32(iter
, &flags
))
771 if (!m
->ReadData(iter
, &payload
, &payload_size
))
774 r
->SetHeaderValues(static_cast<int32
>(routing_id
), type
, flags
);
775 return r
->WriteBytes(payload
, payload_size
);
778 void ParamTraits
<Message
>::Log(const Message
& p
, std::string
* l
) {
779 l
->append("<IPC::Message>");
783 // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
784 // bit systems. That's why we use the Windows macros to convert to 32 bits.
785 void ParamTraits
<HANDLE
>::Write(Message
* m
, const param_type
& p
) {
786 m
->WriteInt(HandleToLong(p
));
789 bool ParamTraits
<HANDLE
>::Read(const Message
* m
, PickleIterator
* iter
,
792 if (!m
->ReadInt(iter
, &temp
))
794 *r
= LongToHandle(temp
);
798 void ParamTraits
<HANDLE
>::Log(const param_type
& p
, std::string
* l
) {
799 l
->append(base::StringPrintf("0x%X", p
));
802 void ParamTraits
<LOGFONT
>::Write(Message
* m
, const param_type
& p
) {
803 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(LOGFONT
));
806 bool ParamTraits
<LOGFONT
>::Read(const Message
* m
, PickleIterator
* iter
,
810 if (m
->ReadData(iter
, &data
, &data_size
) && data_size
== sizeof(LOGFONT
)) {
811 const LOGFONT
*font
= reinterpret_cast<LOGFONT
*>(const_cast<char*>(data
));
812 if (_tcsnlen(font
->lfFaceName
, LF_FACESIZE
) < LF_FACESIZE
) {
813 memcpy(r
, data
, sizeof(LOGFONT
));
822 void ParamTraits
<LOGFONT
>::Log(const param_type
& p
, std::string
* l
) {
823 l
->append(base::StringPrintf("<LOGFONT>"));
826 void ParamTraits
<MSG
>::Write(Message
* m
, const param_type
& p
) {
827 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(MSG
));
830 bool ParamTraits
<MSG
>::Read(const Message
* m
, PickleIterator
* iter
,
834 bool result
= m
->ReadData(iter
, &data
, &data_size
);
835 if (result
&& data_size
== sizeof(MSG
)) {
836 memcpy(r
, data
, sizeof(MSG
));
845 void ParamTraits
<MSG
>::Log(const param_type
& p
, std::string
* l
) {