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"
16 #include "ipc/ipc_message_attachment.h"
17 #include "ipc/ipc_message_attachment_set.h"
20 #include "ipc/ipc_platform_file_attachment_posix.h"
31 const int kMaxRecursionDepth
= 100;
33 template<typename CharType
>
34 void LogBytes(const std::vector
<CharType
>& data
, std::string
* out
) {
36 // Windows has a GUI for logging, which can handle arbitrary binary data.
37 for (size_t i
= 0; i
< data
.size(); ++i
)
38 out
->push_back(data
[i
]);
40 // On POSIX, we log to stdout, which we assume can display ASCII.
41 static const size_t kMaxBytesToLog
= 100;
42 for (size_t i
= 0; i
< std::min(data
.size(), kMaxBytesToLog
); ++i
) {
44 out
->push_back(data
[i
]);
47 base::StringPrintf("[%02X]", static_cast<unsigned char>(data
[i
])));
49 if (data
.size() > kMaxBytesToLog
) {
50 out
->append(base::StringPrintf(
52 static_cast<unsigned>(data
.size() - kMaxBytesToLog
)));
57 bool ReadValue(const Message
* m
,
58 base::PickleIterator
* iter
,
62 void WriteValue(Message
* m
, const base::Value
* value
, int recursion
) {
64 if (recursion
> kMaxRecursionDepth
) {
65 LOG(WARNING
) << "Max recursion depth hit in WriteValue.";
69 m
->WriteInt(value
->GetType());
71 switch (value
->GetType()) {
72 case base::Value::TYPE_NULL
:
74 case base::Value::TYPE_BOOLEAN
: {
76 result
= value
->GetAsBoolean(&val
);
81 case base::Value::TYPE_INTEGER
: {
83 result
= value
->GetAsInteger(&val
);
88 case base::Value::TYPE_DOUBLE
: {
90 result
= value
->GetAsDouble(&val
);
95 case base::Value::TYPE_STRING
: {
97 result
= value
->GetAsString(&val
);
102 case base::Value::TYPE_BINARY
: {
103 const base::BinaryValue
* binary
=
104 static_cast<const base::BinaryValue
*>(value
);
105 m
->WriteData(binary
->GetBuffer(), static_cast<int>(binary
->GetSize()));
108 case base::Value::TYPE_DICTIONARY
: {
109 const base::DictionaryValue
* dict
=
110 static_cast<const base::DictionaryValue
*>(value
);
112 WriteParam(m
, static_cast<int>(dict
->size()));
114 for (base::DictionaryValue::Iterator
it(*dict
); !it
.IsAtEnd();
116 WriteParam(m
, it
.key());
117 WriteValue(m
, &it
.value(), recursion
+ 1);
121 case base::Value::TYPE_LIST
: {
122 const base::ListValue
* list
= static_cast<const base::ListValue
*>(value
);
123 WriteParam(m
, static_cast<int>(list
->GetSize()));
124 for (base::ListValue::const_iterator it
= list
->begin();
125 it
!= list
->end(); ++it
) {
126 WriteValue(m
, *it
, recursion
+ 1);
133 // Helper for ReadValue that reads a DictionaryValue into a pre-allocated
135 bool ReadDictionaryValue(const Message
* m
,
136 base::PickleIterator
* iter
,
137 base::DictionaryValue
* value
,
140 if (!ReadParam(m
, iter
, &size
))
143 for (int i
= 0; i
< size
; ++i
) {
146 if (!ReadParam(m
, iter
, &key
) ||
147 !ReadValue(m
, iter
, &subval
, recursion
+ 1))
149 value
->SetWithoutPathExpansion(key
, subval
);
155 // Helper for ReadValue that reads a ReadListValue into a pre-allocated
157 bool ReadListValue(const Message
* m
,
158 base::PickleIterator
* iter
,
159 base::ListValue
* value
,
162 if (!ReadParam(m
, iter
, &size
))
165 for (int i
= 0; i
< size
; ++i
) {
167 if (!ReadValue(m
, iter
, &subval
, recursion
+ 1))
169 value
->Set(i
, subval
);
175 bool ReadValue(const Message
* m
,
176 base::PickleIterator
* iter
,
179 if (recursion
> kMaxRecursionDepth
) {
180 LOG(WARNING
) << "Max recursion depth hit in ReadValue.";
185 if (!ReadParam(m
, iter
, &type
))
189 case base::Value::TYPE_NULL
:
190 *value
= base::Value::CreateNullValue().release();
192 case base::Value::TYPE_BOOLEAN
: {
194 if (!ReadParam(m
, iter
, &val
))
196 *value
= new base::FundamentalValue(val
);
199 case base::Value::TYPE_INTEGER
: {
201 if (!ReadParam(m
, iter
, &val
))
203 *value
= new base::FundamentalValue(val
);
206 case base::Value::TYPE_DOUBLE
: {
208 if (!ReadParam(m
, iter
, &val
))
210 *value
= new base::FundamentalValue(val
);
213 case base::Value::TYPE_STRING
: {
215 if (!ReadParam(m
, iter
, &val
))
217 *value
= new base::StringValue(val
);
220 case base::Value::TYPE_BINARY
: {
223 if (!iter
->ReadData(&data
, &length
))
225 *value
= base::BinaryValue::CreateWithCopiedBuffer(data
, length
);
228 case base::Value::TYPE_DICTIONARY
: {
229 scoped_ptr
<base::DictionaryValue
> val(new base::DictionaryValue());
230 if (!ReadDictionaryValue(m
, iter
, val
.get(), recursion
))
232 *value
= val
.release();
235 case base::Value::TYPE_LIST
: {
236 scoped_ptr
<base::ListValue
> val(new base::ListValue());
237 if (!ReadListValue(m
, iter
, val
.get(), recursion
))
239 *value
= val
.release();
251 // -----------------------------------------------------------------------------
261 LogData::~LogData() {
264 void ParamTraits
<bool>::Log(const param_type
& p
, std::string
* l
) {
265 l
->append(p
? "true" : "false");
268 void ParamTraits
<unsigned char>::Write(Message
* m
, const param_type
& p
) {
269 m
->WriteBytes(&p
, sizeof(param_type
));
272 bool ParamTraits
<unsigned char>::Read(const Message
* m
,
273 base::PickleIterator
* iter
,
276 if (!iter
->ReadBytes(&data
, sizeof(param_type
)))
278 memcpy(r
, data
, sizeof(param_type
));
282 void ParamTraits
<unsigned char>::Log(const param_type
& p
, std::string
* l
) {
283 l
->append(base::UintToString(p
));
286 void ParamTraits
<unsigned short>::Write(Message
* m
, const param_type
& p
) {
287 m
->WriteBytes(&p
, sizeof(param_type
));
290 bool ParamTraits
<unsigned short>::Read(const Message
* m
,
291 base::PickleIterator
* iter
,
294 if (!iter
->ReadBytes(&data
, sizeof(param_type
)))
296 memcpy(r
, data
, sizeof(param_type
));
300 void ParamTraits
<unsigned short>::Log(const param_type
& p
, std::string
* l
) {
301 l
->append(base::UintToString(p
));
304 void ParamTraits
<int>::Log(const param_type
& p
, std::string
* l
) {
305 l
->append(base::IntToString(p
));
308 void ParamTraits
<unsigned int>::Log(const param_type
& p
, std::string
* l
) {
309 l
->append(base::UintToString(p
));
312 void ParamTraits
<long>::Log(const param_type
& p
, std::string
* l
) {
313 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
316 void ParamTraits
<unsigned long>::Log(const param_type
& p
, std::string
* l
) {
317 l
->append(base::Uint64ToString(static_cast<uint64
>(p
)));
320 void ParamTraits
<long long>::Log(const param_type
& p
, std::string
* l
) {
321 l
->append(base::Int64ToString(static_cast<int64
>(p
)));
324 void ParamTraits
<unsigned long long>::Log(const param_type
& p
, std::string
* l
) {
325 l
->append(base::Uint64ToString(p
));
328 void ParamTraits
<float>::Log(const param_type
& p
, std::string
* l
) {
329 l
->append(base::StringPrintf("%e", p
));
332 void ParamTraits
<double>::Write(Message
* m
, const param_type
& p
) {
333 m
->WriteBytes(reinterpret_cast<const char*>(&p
), sizeof(param_type
));
336 bool ParamTraits
<double>::Read(const Message
* m
,
337 base::PickleIterator
* iter
,
340 if (!iter
->ReadBytes(&data
, sizeof(*r
))) {
344 memcpy(r
, data
, sizeof(param_type
));
348 void ParamTraits
<double>::Log(const param_type
& p
, std::string
* l
) {
349 l
->append(base::StringPrintf("%e", p
));
353 void ParamTraits
<std::string
>::Log(const param_type
& p
, std::string
* l
) {
357 void ParamTraits
<base::string16
>::Log(const param_type
& p
, std::string
* l
) {
358 l
->append(base::UTF16ToUTF8(p
));
361 void ParamTraits
<std::vector
<char> >::Write(Message
* m
, const param_type
& p
) {
363 m
->WriteData(NULL
, 0);
365 m
->WriteData(&p
.front(), static_cast<int>(p
.size()));
369 bool ParamTraits
<std::vector
<char>>::Read(const Message
* m
,
370 base::PickleIterator
* iter
,
374 if (!iter
->ReadData(&data
, &data_size
) || data_size
< 0)
376 r
->resize(data_size
);
378 memcpy(&r
->front(), data
, data_size
);
382 void ParamTraits
<std::vector
<char> >::Log(const param_type
& p
, std::string
* l
) {
386 void ParamTraits
<std::vector
<unsigned char> >::Write(Message
* m
,
387 const param_type
& p
) {
389 m
->WriteData(NULL
, 0);
391 m
->WriteData(reinterpret_cast<const char*>(&p
.front()),
392 static_cast<int>(p
.size()));
396 bool ParamTraits
<std::vector
<unsigned char>>::Read(const Message
* m
,
397 base::PickleIterator
* iter
,
401 if (!iter
->ReadData(&data
, &data_size
) || data_size
< 0)
403 r
->resize(data_size
);
405 memcpy(&r
->front(), data
, data_size
);
409 void ParamTraits
<std::vector
<unsigned char> >::Log(const param_type
& p
,
414 void ParamTraits
<std::vector
<bool> >::Write(Message
* m
, const param_type
& p
) {
415 WriteParam(m
, static_cast<int>(p
.size()));
416 // Cast to bool below is required because libc++'s
417 // vector<bool>::const_reference is different from bool, and we want to avoid
418 // writing an extra specialization of ParamTraits for it.
419 for (size_t i
= 0; i
< p
.size(); i
++)
420 WriteParam(m
, static_cast<bool>(p
[i
]));
423 bool ParamTraits
<std::vector
<bool>>::Read(const Message
* m
,
424 base::PickleIterator
* iter
,
427 // ReadLength() checks for < 0 itself.
428 if (!iter
->ReadLength(&size
))
431 for (int i
= 0; i
< size
; i
++) {
433 if (!ReadParam(m
, iter
, &value
))
440 void ParamTraits
<std::vector
<bool> >::Log(const param_type
& p
, std::string
* l
) {
441 for (size_t i
= 0; i
< p
.size(); ++i
) {
444 LogParam(static_cast<bool>(p
[i
]), l
);
448 void ParamTraits
<base::DictionaryValue
>::Write(Message
* m
,
449 const param_type
& p
) {
450 WriteValue(m
, &p
, 0);
453 bool ParamTraits
<base::DictionaryValue
>::Read(const Message
* m
,
454 base::PickleIterator
* iter
,
457 if (!ReadParam(m
, iter
, &type
) || type
!= base::Value::TYPE_DICTIONARY
)
460 return ReadDictionaryValue(m
, iter
, r
, 0);
463 void ParamTraits
<base::DictionaryValue
>::Log(const param_type
& p
,
466 base::JSONWriter::Write(p
, &json
);
470 #if defined(OS_POSIX)
471 void ParamTraits
<base::FileDescriptor
>::Write(Message
* m
, const param_type
& p
) {
472 const bool valid
= p
.fd
>= 0;
473 WriteParam(m
, valid
);
479 if (!m
->WriteAttachment(
480 new internal::PlatformFileAttachment(base::ScopedFD(p
.fd
))))
483 if (!m
->WriteAttachment(new internal::PlatformFileAttachment(p
.fd
)))
488 bool ParamTraits
<base::FileDescriptor
>::Read(const Message
* m
,
489 base::PickleIterator
* iter
,
491 *r
= base::FileDescriptor();
494 if (!ReadParam(m
, iter
, &valid
))
497 // TODO(morrita): Seems like this should return false.
501 scoped_refptr
<MessageAttachment
> attachment
;
502 if (!m
->ReadAttachment(iter
, &attachment
))
505 *r
= base::FileDescriptor(attachment
->TakePlatformFile(), true);
509 void ParamTraits
<base::FileDescriptor
>::Log(const param_type
& p
,
512 l
->append(base::StringPrintf("FD(%d auto-close)", p
.fd
));
514 l
->append(base::StringPrintf("FD(%d)", p
.fd
));
517 #endif // defined(OS_POSIX)
519 void ParamTraits
<base::FilePath
>::Write(Message
* m
, const param_type
& p
) {
523 bool ParamTraits
<base::FilePath
>::Read(const Message
* m
,
524 base::PickleIterator
* iter
,
526 return r
->ReadFromPickle(iter
);
529 void ParamTraits
<base::FilePath
>::Log(const param_type
& p
, std::string
* l
) {
530 ParamTraits
<base::FilePath::StringType
>::Log(p
.value(), l
);
533 void ParamTraits
<base::ListValue
>::Write(Message
* m
, const param_type
& p
) {
534 WriteValue(m
, &p
, 0);
537 bool ParamTraits
<base::ListValue
>::Read(const Message
* m
,
538 base::PickleIterator
* iter
,
541 if (!ReadParam(m
, iter
, &type
) || type
!= base::Value::TYPE_LIST
)
544 return ReadListValue(m
, iter
, r
, 0);
547 void ParamTraits
<base::ListValue
>::Log(const param_type
& p
, std::string
* l
) {
549 base::JSONWriter::Write(p
, &json
);
553 void ParamTraits
<base::NullableString16
>::Write(Message
* m
,
554 const param_type
& p
) {
555 WriteParam(m
, p
.string());
556 WriteParam(m
, p
.is_null());
559 bool ParamTraits
<base::NullableString16
>::Read(const Message
* m
,
560 base::PickleIterator
* iter
,
562 base::string16 string
;
563 if (!ReadParam(m
, iter
, &string
))
566 if (!ReadParam(m
, iter
, &is_null
))
568 *r
= base::NullableString16(string
, is_null
);
572 void ParamTraits
<base::NullableString16
>::Log(const param_type
& p
,
575 LogParam(p
.string(), l
);
577 LogParam(p
.is_null(), l
);
581 void ParamTraits
<base::File::Info
>::Write(Message
* m
,
582 const param_type
& p
) {
583 WriteParam(m
, p
.size
);
584 WriteParam(m
, p
.is_directory
);
585 WriteParam(m
, p
.last_modified
.ToDoubleT());
586 WriteParam(m
, p
.last_accessed
.ToDoubleT());
587 WriteParam(m
, p
.creation_time
.ToDoubleT());
590 bool ParamTraits
<base::File::Info
>::Read(const Message
* m
,
591 base::PickleIterator
* iter
,
593 double last_modified
, last_accessed
, creation_time
;
594 if (!ReadParam(m
, iter
, &p
->size
) ||
595 !ReadParam(m
, iter
, &p
->is_directory
) ||
596 !ReadParam(m
, iter
, &last_modified
) ||
597 !ReadParam(m
, iter
, &last_accessed
) ||
598 !ReadParam(m
, iter
, &creation_time
))
600 p
->last_modified
= base::Time::FromDoubleT(last_modified
);
601 p
->last_accessed
= base::Time::FromDoubleT(last_accessed
);
602 p
->creation_time
= base::Time::FromDoubleT(creation_time
);
606 void ParamTraits
<base::File::Info
>::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
,
626 base::PickleIterator
* iter
,
629 if (!ParamTraits
<int64
>::Read(m
, iter
, &value
))
631 *r
= base::Time::FromInternalValue(value
);
635 void ParamTraits
<base::Time
>::Log(const param_type
& p
, std::string
* l
) {
636 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
639 void ParamTraits
<base::TimeDelta
>::Write(Message
* m
, const param_type
& p
) {
640 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
643 bool ParamTraits
<base::TimeDelta
>::Read(const Message
* m
,
644 base::PickleIterator
* iter
,
647 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
649 *r
= base::TimeDelta::FromInternalValue(value
);
654 void ParamTraits
<base::TimeDelta
>::Log(const param_type
& p
, std::string
* l
) {
655 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
658 void ParamTraits
<base::TimeTicks
>::Write(Message
* m
, const param_type
& p
) {
659 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
662 bool ParamTraits
<base::TimeTicks
>::Read(const Message
* m
,
663 base::PickleIterator
* iter
,
666 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
668 *r
= base::TimeTicks::FromInternalValue(value
);
673 void ParamTraits
<base::TimeTicks
>::Log(const param_type
& p
, std::string
* l
) {
674 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
677 void ParamTraits
<base::TraceTicks
>::Write(Message
* m
, const param_type
& p
) {
678 ParamTraits
<int64
>::Write(m
, p
.ToInternalValue());
681 bool ParamTraits
<base::TraceTicks
>::Read(const Message
* m
,
682 base::PickleIterator
* iter
,
685 bool ret
= ParamTraits
<int64
>::Read(m
, iter
, &value
);
687 *r
= base::TraceTicks::FromInternalValue(value
);
692 void ParamTraits
<base::TraceTicks
>::Log(const param_type
& p
, std::string
* l
) {
693 ParamTraits
<int64
>::Log(p
.ToInternalValue(), l
);
696 void ParamTraits
<IPC::ChannelHandle
>::Write(Message
* m
, const param_type
& p
) {
698 // On Windows marshalling pipe handle is not supported.
699 DCHECK(p
.pipe
.handle
== NULL
);
700 #endif // defined (OS_WIN)
701 WriteParam(m
, p
.name
);
702 #if defined(OS_POSIX)
703 WriteParam(m
, p
.socket
);
707 bool ParamTraits
<IPC::ChannelHandle
>::Read(const Message
* m
,
708 base::PickleIterator
* iter
,
710 return ReadParam(m
, iter
, &r
->name
)
711 #if defined(OS_POSIX)
712 && ReadParam(m
, iter
, &r
->socket
)
717 void ParamTraits
<IPC::ChannelHandle
>::Log(const param_type
& p
,
719 l
->append(base::StringPrintf("ChannelHandle(%s", p
.name
.c_str()));
720 #if defined(OS_POSIX)
722 ParamTraits
<base::FileDescriptor
>::Log(p
.socket
, l
);
727 void ParamTraits
<LogData
>::Write(Message
* m
, const param_type
& p
) {
728 WriteParam(m
, p
.channel
);
729 WriteParam(m
, p
.routing_id
);
730 WriteParam(m
, p
.type
);
731 WriteParam(m
, p
.flags
);
732 WriteParam(m
, p
.sent
);
733 WriteParam(m
, p
.receive
);
734 WriteParam(m
, p
.dispatch
);
735 WriteParam(m
, p
.message_name
);
736 WriteParam(m
, p
.params
);
739 bool ParamTraits
<LogData
>::Read(const Message
* m
,
740 base::PickleIterator
* iter
,
743 ReadParam(m
, iter
, &r
->channel
) &&
744 ReadParam(m
, iter
, &r
->routing_id
) &&
745 ReadParam(m
, iter
, &r
->type
) &&
746 ReadParam(m
, iter
, &r
->flags
) &&
747 ReadParam(m
, iter
, &r
->sent
) &&
748 ReadParam(m
, iter
, &r
->receive
) &&
749 ReadParam(m
, iter
, &r
->dispatch
) &&
750 ReadParam(m
, iter
, &r
->message_name
) &&
751 ReadParam(m
, iter
, &r
->params
);
754 void ParamTraits
<LogData
>::Log(const param_type
& p
, std::string
* l
) {
755 // Doesn't make sense to implement this!
758 void ParamTraits
<Message
>::Write(Message
* m
, const Message
& p
) {
759 #if defined(OS_POSIX)
760 // We don't serialize the file descriptors in the nested message, so there
761 // better not be any.
762 DCHECK(!p
.HasAttachments());
765 // Don't just write out the message. This is used to send messages between
766 // NaCl (Posix environment) and the browser (could be on Windows). The message
767 // header formats differ between these systems (so does handle sharing, but
768 // we already asserted we don't have any handles). So just write out the
769 // parts of the header we use.
771 // Be careful also to use only explicitly-sized types. The NaCl environment
772 // could be 64-bit and the host browser could be 32-bits. The nested message
773 // may or may not be safe to send between 32-bit and 64-bit systems, but we
774 // leave that up to the code sending the message to ensure.
775 m
->WriteUInt32(static_cast<uint32
>(p
.routing_id()));
776 m
->WriteUInt32(p
.type());
777 m
->WriteUInt32(p
.flags());
778 m
->WriteData(p
.payload(), static_cast<uint32
>(p
.payload_size()));
781 bool ParamTraits
<Message
>::Read(const Message
* m
,
782 base::PickleIterator
* iter
,
784 uint32 routing_id
, type
, flags
;
785 if (!iter
->ReadUInt32(&routing_id
) ||
786 !iter
->ReadUInt32(&type
) ||
787 !iter
->ReadUInt32(&flags
))
792 if (!iter
->ReadData(&payload
, &payload_size
))
795 r
->SetHeaderValues(static_cast<int32
>(routing_id
), type
, flags
);
796 return r
->WriteBytes(payload
, payload_size
);
799 void ParamTraits
<Message
>::Log(const Message
& p
, std::string
* l
) {
800 l
->append("<IPC::Message>");
804 // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
805 // bit systems. That's why we use the Windows macros to convert to 32 bits.
806 void ParamTraits
<HANDLE
>::Write(Message
* m
, const param_type
& p
) {
807 m
->WriteInt(HandleToLong(p
));
810 bool ParamTraits
<HANDLE
>::Read(const Message
* m
,
811 base::PickleIterator
* iter
,
814 if (!iter
->ReadInt(&temp
))
816 *r
= LongToHandle(temp
);
820 void ParamTraits
<HANDLE
>::Log(const param_type
& p
, std::string
* l
) {
821 l
->append(base::StringPrintf("0x%X", p
));
824 void ParamTraits
<LOGFONT
>::Write(Message
* m
, const param_type
& p
) {
825 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(LOGFONT
));
828 bool ParamTraits
<LOGFONT
>::Read(const Message
* m
,
829 base::PickleIterator
* iter
,
833 if (iter
->ReadData(&data
, &data_size
) && data_size
== sizeof(LOGFONT
)) {
834 const LOGFONT
*font
= reinterpret_cast<LOGFONT
*>(const_cast<char*>(data
));
835 if (_tcsnlen(font
->lfFaceName
, LF_FACESIZE
) < LF_FACESIZE
) {
836 memcpy(r
, data
, sizeof(LOGFONT
));
845 void ParamTraits
<LOGFONT
>::Log(const param_type
& p
, std::string
* l
) {
846 l
->append(base::StringPrintf("<LOGFONT>"));
849 void ParamTraits
<MSG
>::Write(Message
* m
, const param_type
& p
) {
850 m
->WriteData(reinterpret_cast<const char*>(&p
), sizeof(MSG
));
853 bool ParamTraits
<MSG
>::Read(const Message
* m
,
854 base::PickleIterator
* iter
,
858 bool result
= iter
->ReadData(&data
, &data_size
);
859 if (result
&& data_size
== sizeof(MSG
)) {
860 memcpy(r
, data
, sizeof(MSG
));
869 void ParamTraits
<MSG
>::Log(const param_type
& p
, std::string
* l
) {