1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__
8 #define __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__
14 #include <type_traits>
15 #include <unordered_map>
18 #include "chrome/common/ipc_message.h"
19 #include "chrome/common/ipc_message_utils.h"
20 #include "ipc/EnumSerializer.h"
21 #include "ipc/IPCMessageUtils.h"
22 #include "mozilla/Assertions.h"
23 #include "mozilla/BitSet.h"
24 #include "mozilla/EnumSet.h"
25 #include "mozilla/EnumTypeTraits.h"
26 #include "mozilla/IntegerRange.h"
27 #include "mozilla/Maybe.h"
28 #include "mozilla/TimeStamp.h"
30 # include "mozilla/TimeStamp_windows.h"
32 #include "mozilla/Tuple.h"
33 #include "mozilla/UniquePtr.h"
34 #include "mozilla/Unused.h"
35 #include "mozilla/Vector.h"
36 #include "mozilla/dom/ipc/StructuredCloneData.h"
37 #include "nsCSSPropertyID.h"
39 #include "nsIContentPolicy.h"
41 #include "nsILoadInfo.h"
42 #include "nsIThread.h"
43 #include "nsLiteralString.h"
46 #include "nsTHashSet.h"
48 // XXX Includes that are only required by implementations which could be moved
50 #include "base/string_util.h" // for StringPrintf
51 #include "mozilla/ArrayUtils.h" // for ArrayLength
52 #include "mozilla/CheckedInt.h"
55 # pragma warning(disable : 4800)
59 template <typename
... Ts
>
63 template <typename
... Ts
>
66 } // namespace mozilla
68 namespace mozilla::dom
{
78 struct ParamTraits
<nsTSubstring
<T
>> {
79 typedef nsTSubstring
<T
> paramType
;
81 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
82 bool isVoid
= aParam
.IsVoid();
83 aWriter
->WriteBool(isVoid
);
86 // represents a nullptr pointer
90 WriteSequenceParam
<const T
&>(aWriter
, aParam
.BeginReading(),
94 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
96 if (!aReader
->ReadBool(&isVoid
)) {
101 aResult
->SetIsVoid(true);
105 return ReadSequenceParam(aReader
, [&](uint32_t aLength
) -> T
* {
107 aResult
->GetMutableData(&data
, aLength
);
114 struct ParamTraits
<nsTString
<T
>> : ParamTraits
<nsTSubstring
<T
>> {};
117 struct ParamTraits
<nsTLiteralString
<T
>> : ParamTraits
<nsTSubstring
<T
>> {};
119 template <class T
, size_t N
>
120 struct ParamTraits
<nsTAutoStringN
<T
, N
>> : ParamTraits
<nsTSubstring
<T
>> {};
123 struct ParamTraits
<nsTDependentString
<T
>> : ParamTraits
<nsTSubstring
<T
>> {};
125 // XXX While this has no special dependencies, it's currently only used in
126 // GfxMessageUtils and could be moved there, or generalized to potentially work
127 // with any nsTHashSet.
129 struct ParamTraits
<nsTHashSet
<uint64_t>> {
130 typedef nsTHashSet
<uint64_t> paramType
;
132 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
133 uint32_t count
= aParam
.Count();
134 WriteParam(aWriter
, count
);
135 for (const auto& key
: aParam
) {
136 WriteParam(aWriter
, key
);
140 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
142 if (!ReadParam(aReader
, &count
)) {
145 paramType
table(count
);
146 for (uint32_t i
= 0; i
< count
; ++i
) {
148 if (!ReadParam(aReader
, &key
)) {
153 *aResult
= std::move(table
);
158 template <typename E
>
159 struct ParamTraits
<nsTArray
<E
>> {
160 typedef nsTArray
<E
> paramType
;
162 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
163 WriteSequenceParam
<const E
&>(aWriter
, aParam
.Elements(), aParam
.Length());
166 static void Write(MessageWriter
* aWriter
, paramType
&& aParam
) {
167 WriteSequenceParam
<E
&&>(aWriter
, aParam
.Elements(), aParam
.Length());
170 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
171 return ReadSequenceParam(aReader
, [&](uint32_t aLength
) -> E
* {
172 return aResult
->AppendElements(aLength
);
177 template <typename E
>
178 struct ParamTraits
<CopyableTArray
<E
>> : ParamTraits
<nsTArray
<E
>> {};
180 template <typename E
>
181 struct ParamTraits
<FallibleTArray
<E
>> {
182 typedef FallibleTArray
<E
> paramType
;
184 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
185 WriteSequenceParam
<const E
&>(aWriter
, aParam
.Elements(), aParam
.Length());
188 static void Write(MessageWriter
* aWriter
, paramType
&& aParam
) {
189 WriteSequenceParam
<E
&&>(aWriter
, aParam
.Elements(), aParam
.Length());
192 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
193 return ReadSequenceParam(aReader
, [&](uint32_t aLength
) -> E
* {
194 return aResult
->AppendElements(aLength
, mozilla::fallible
);
199 template <typename E
, size_t N
>
200 struct ParamTraits
<AutoTArray
<E
, N
>> : ParamTraits
<nsTArray
<E
>> {
201 typedef AutoTArray
<E
, N
> paramType
;
204 template <typename E
, size_t N
>
205 struct ParamTraits
<CopyableAutoTArray
<E
, N
>> : ParamTraits
<AutoTArray
<E
, N
>> {};
207 template <typename T
>
208 struct ParamTraits
<mozilla::dom::Sequence
<T
>> : ParamTraits
<FallibleTArray
<T
>> {
211 template <typename E
, size_t N
, typename AP
>
212 struct ParamTraits
<mozilla::Vector
<E
, N
, AP
>> {
213 typedef mozilla::Vector
<E
, N
, AP
> paramType
;
215 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
216 WriteSequenceParam
<const E
&>(aWriter
, aParam
.Elements(), aParam
.Length());
219 static void Write(MessageWriter
* aWriter
, paramType
&& aParam
) {
220 WriteSequenceParam
<E
&&>(aWriter
, aParam
.Elements(), aParam
.Length());
223 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
224 return ReadSequenceParam(aReader
, [&](uint32_t aLength
) -> E
* {
225 if (!aResult
->resize(aLength
)) {
226 // So that OOM failure shows up as OOM crash instead of IPC FatalError.
227 NS_ABORT_OOM(aLength
* sizeof(E
));
229 return aResult
->begin();
234 template <typename E
>
235 struct ParamTraits
<std::vector
<E
>> {
236 typedef std::vector
<E
> paramType
;
238 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
239 WriteSequenceParam
<const E
&>(aWriter
, aParam
.data(), aParam
.size());
241 static void Write(MessageWriter
* aWriter
, paramType
&& aParam
) {
242 WriteSequenceParam
<E
&&>(aWriter
, aParam
.data(), aParam
.size());
245 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
246 return ReadSequenceParam(aReader
, [&](uint32_t aLength
) -> E
* {
247 aResult
->resize(aLength
);
248 return aResult
->data();
253 template <typename K
, typename V
>
254 struct ParamTraits
<std::unordered_map
<K
, V
>> final
{
255 using T
= std::unordered_map
<K
, V
>;
257 static void Write(MessageWriter
* const writer
, const T
& in
) {
258 WriteParam(writer
, in
.size());
259 for (const auto& pair
: in
) {
260 WriteParam(writer
, pair
.first
);
261 WriteParam(writer
, pair
.second
);
265 static bool Read(MessageReader
* const reader
, T
* const out
) {
267 if (!ReadParam(reader
, &size
)) return false;
270 for (const auto i
: mozilla::IntegerRange(size
)) {
271 std::pair
<K
, V
> pair
;
272 mozilla::Unused
<< i
;
273 if (!ReadParam(reader
, &(pair
.first
)) ||
274 !ReadParam(reader
, &(pair
.second
))) {
277 map
.insert(std::move(pair
));
279 *out
= std::move(map
);
285 struct ParamTraits
<float> {
286 typedef float paramType
;
288 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
289 aWriter
->WriteBytes(&aParam
, sizeof(paramType
));
292 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
293 return aReader
->ReadBytesInto(aResult
, sizeof(*aResult
));
298 struct ParamTraits
<nsCSSPropertyID
>
299 : public ContiguousEnumSerializer
<nsCSSPropertyID
, eCSSProperty_UNKNOWN
,
300 eCSSProperty_COUNT
> {};
303 struct ParamTraits
<nsID
> {
304 typedef nsID paramType
;
306 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
307 WriteParam(aWriter
, aParam
.m0
);
308 WriteParam(aWriter
, aParam
.m1
);
309 WriteParam(aWriter
, aParam
.m2
);
310 for (unsigned int i
= 0; i
< mozilla::ArrayLength(aParam
.m3
); i
++) {
311 WriteParam(aWriter
, aParam
.m3
[i
]);
315 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
316 if (!ReadParam(aReader
, &(aResult
->m0
)) ||
317 !ReadParam(aReader
, &(aResult
->m1
)) ||
318 !ReadParam(aReader
, &(aResult
->m2
)))
321 for (unsigned int i
= 0; i
< mozilla::ArrayLength(aResult
->m3
); i
++)
322 if (!ReadParam(aReader
, &(aResult
->m3
[i
]))) return false;
329 struct ParamTraits
<nsContentPolicyType
>
330 : public ContiguousEnumSerializerInclusive
<
331 nsContentPolicyType
, nsIContentPolicy::TYPE_INVALID
,
332 nsIContentPolicy::TYPE_WEB_IDENTITY
> {};
335 struct ParamTraits
<mozilla::TimeDuration
> {
336 typedef mozilla::TimeDuration paramType
;
337 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
338 WriteParam(aWriter
, aParam
.mValue
);
340 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
341 return ReadParam(aReader
, &aResult
->mValue
);
346 struct ParamTraits
<mozilla::TimeStamp
> {
347 typedef mozilla::TimeStamp paramType
;
348 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
349 WriteParam(aWriter
, aParam
.mValue
);
351 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
352 return ReadParam(aReader
, &aResult
->mValue
);
359 struct ParamTraits
<mozilla::TimeStampValue
> {
360 typedef mozilla::TimeStampValue paramType
;
361 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
362 WriteParam(aWriter
, aParam
.mGTC
);
363 WriteParam(aWriter
, aParam
.mQPC
);
364 WriteParam(aWriter
, aParam
.mIsNull
);
365 WriteParam(aWriter
, aParam
.mHasQPC
);
367 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
368 return (ReadParam(aReader
, &aResult
->mGTC
) &&
369 ReadParam(aReader
, &aResult
->mQPC
) &&
370 ReadParam(aReader
, &aResult
->mIsNull
) &&
371 ReadParam(aReader
, &aResult
->mHasQPC
));
378 struct ParamTraits
<mozilla::dom::ipc::StructuredCloneData
> {
379 typedef mozilla::dom::ipc::StructuredCloneData paramType
;
381 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
382 aParam
.WriteIPCParams(aWriter
);
385 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
386 return aResult
->ReadIPCParams(aReader
);
391 struct ParamTraits
<mozilla::Maybe
<T
>> {
392 typedef mozilla::Maybe
<T
> paramType
;
394 static void Write(MessageWriter
* writer
, const paramType
& param
) {
395 if (param
.isSome()) {
396 WriteParam(writer
, true);
397 WriteParam(writer
, param
.ref());
399 WriteParam(writer
, false);
403 static void Write(MessageWriter
* writer
, paramType
&& param
) {
404 if (param
.isSome()) {
405 WriteParam(writer
, true);
406 WriteParam(writer
, std::move(param
.ref()));
408 WriteParam(writer
, false);
412 static bool Read(MessageReader
* reader
, paramType
* result
) {
414 if (!ReadParam(reader
, &isSome
)) {
419 if (!ReadParam(reader
, &tmp
)) {
422 *result
= mozilla::Some(std::move(tmp
));
424 *result
= mozilla::Nothing();
430 template <typename T
, typename U
>
431 struct ParamTraits
<mozilla::EnumSet
<T
, U
>> {
432 typedef mozilla::EnumSet
<T
, U
> paramType
;
433 typedef U serializedType
;
435 static void Write(MessageWriter
* writer
, const paramType
& param
) {
436 MOZ_RELEASE_ASSERT(IsLegalValue(param
.serialize()));
437 WriteParam(writer
, param
.serialize());
440 static bool Read(MessageReader
* reader
, paramType
* result
) {
443 if (ReadParam(reader
, &tmp
)) {
444 if (IsLegalValue(tmp
)) {
445 result
->deserialize(tmp
);
453 static constexpr serializedType
AllEnumBits() {
454 return ~serializedType(0) >> (std::numeric_limits
<serializedType
>::digits
-
455 (mozilla::MaxEnumValue
<T
>::value
+ 1));
458 static constexpr bool IsLegalValue(const serializedType value
) {
459 static_assert(mozilla::MaxEnumValue
<T
>::value
<
460 std::numeric_limits
<serializedType
>::digits
,
461 "Enum max value is not in the range!");
463 std::is_unsigned
<decltype(mozilla::MaxEnumValue
<T
>::value
)>::value
,
464 "Type of MaxEnumValue<T>::value specialization should be unsigned!");
466 return (value
& AllEnumBits()) == value
;
470 template <class... Ts
>
471 struct ParamTraits
<mozilla::Variant
<Ts
...>> {
472 typedef mozilla::Variant
<Ts
...> paramType
;
473 using Tag
= typename
mozilla::detail::VariantTag
<Ts
...>::Type
;
475 static void Write(MessageWriter
* writer
, const paramType
& param
) {
476 WriteParam(writer
, param
.tag
);
477 param
.match([writer
](const auto& t
) { WriteParam(writer
, t
); });
480 // Because VariantReader is a nested struct, we need the dummy template
481 // parameter to avoid making VariantReader<0> an explicit specialization,
482 // which is not allowed for a nested class template
483 template <size_t N
, typename dummy
= void>
484 struct VariantReader
{
485 using Next
= VariantReader
<N
- 1>;
487 static bool Read(MessageReader
* reader
, Tag tag
, paramType
* result
) {
488 // Since the VariantReader specializations start at N , we need to
489 // subtract one to look at N - 1, the first valid tag. This means our
490 // comparisons are off by 1. If we get to N = 0 then we have failed to
491 // find a match to the tag.
493 // Recall, even though the template parameter is N, we are
494 // actually interested in the N - 1 tag.
495 // Default construct our field within the result outparameter and
496 // directly deserialize into the variant. Note that this means that
497 // every type in Ts needs to be default constructible
498 return ReadParam(reader
, &result
->template emplace
<N
- 1>());
500 return Next::Read(reader
, tag
, result
);
504 }; // VariantReader<N>
506 // Since we are conditioning on tag = N - 1 in the preceding specialization,
507 // if we get to `VariantReader<0, dummy>` we have failed to find
509 template <typename dummy
>
510 struct VariantReader
<0, dummy
> {
511 static bool Read(MessageReader
* reader
, Tag tag
, paramType
* result
) {
516 static bool Read(MessageReader
* reader
, paramType
* result
) {
518 if (ReadParam(reader
, &tag
)) {
519 return VariantReader
<sizeof...(Ts
)>::Read(reader
, tag
, result
);
525 template <typename T
>
526 struct ParamTraits
<mozilla::dom::Optional
<T
>> {
527 typedef mozilla::dom::Optional
<T
> paramType
;
529 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
530 if (aParam
.WasPassed()) {
531 WriteParam(aWriter
, true);
532 WriteParam(aWriter
, aParam
.Value());
536 WriteParam(aWriter
, false);
539 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
540 bool wasPassed
= false;
542 if (!ReadParam(aReader
, &wasPassed
)) {
549 if (!ReadParam(aReader
, &aResult
->Construct())) {
559 struct ParamTraits
<nsAtom
*> {
560 typedef nsAtom paramType
;
562 static void Write(MessageWriter
* aWriter
, const paramType
* aParam
);
563 static bool Read(MessageReader
* aReader
, RefPtr
<paramType
>* aResult
);
566 struct CrossOriginOpenerPolicyValidator
{
568 std::underlying_type_t
<nsILoadInfo::CrossOriginOpenerPolicy
>;
570 static bool IsLegalValue(const IntegralType e
) {
571 return AreIntegralValuesEqual(e
, nsILoadInfo::OPENER_POLICY_UNSAFE_NONE
) ||
572 AreIntegralValuesEqual(e
, nsILoadInfo::OPENER_POLICY_SAME_ORIGIN
) ||
573 AreIntegralValuesEqual(
574 e
, nsILoadInfo::OPENER_POLICY_SAME_ORIGIN_ALLOW_POPUPS
) ||
575 AreIntegralValuesEqual(
577 OPENER_POLICY_SAME_ORIGIN_EMBEDDER_POLICY_REQUIRE_CORP
);
581 static bool AreIntegralValuesEqual(
582 const IntegralType aLhs
,
583 const nsILoadInfo::CrossOriginOpenerPolicy aRhs
) {
584 return aLhs
== static_cast<IntegralType
>(aRhs
);
589 struct ParamTraits
<nsILoadInfo::CrossOriginOpenerPolicy
>
590 : EnumSerializer
<nsILoadInfo::CrossOriginOpenerPolicy
,
591 CrossOriginOpenerPolicyValidator
> {};
593 struct CrossOriginEmbedderPolicyValidator
{
595 std::underlying_type_t
<nsILoadInfo::CrossOriginEmbedderPolicy
>;
597 static bool IsLegalValue(const IntegralType e
) {
598 return AreIntegralValuesEqual(e
, nsILoadInfo::EMBEDDER_POLICY_NULL
) ||
599 AreIntegralValuesEqual(e
,
600 nsILoadInfo::EMBEDDER_POLICY_REQUIRE_CORP
) ||
601 AreIntegralValuesEqual(e
,
602 nsILoadInfo::EMBEDDER_POLICY_CREDENTIALLESS
);
606 static bool AreIntegralValuesEqual(
607 const IntegralType aLhs
,
608 const nsILoadInfo::CrossOriginEmbedderPolicy aRhs
) {
609 return aLhs
== static_cast<IntegralType
>(aRhs
);
614 struct ParamTraits
<nsILoadInfo::CrossOriginEmbedderPolicy
>
615 : EnumSerializer
<nsILoadInfo::CrossOriginEmbedderPolicy
,
616 CrossOriginEmbedderPolicyValidator
> {};
618 template <size_t N
, typename Word
>
619 struct ParamTraits
<mozilla::BitSet
<N
, Word
>> {
620 typedef mozilla::BitSet
<N
, Word
> paramType
;
622 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
623 for (Word word
: aParam
.Storage()) {
624 WriteParam(aWriter
, word
);
628 static bool Read(MessageReader
* aReader
, paramType
* aResult
) {
629 for (Word
& word
: aResult
->Storage()) {
630 if (!ReadParam(aReader
, &word
)) {
638 template <typename T
>
639 struct ParamTraits
<mozilla::UniquePtr
<T
>> {
640 typedef mozilla::UniquePtr
<T
> paramType
;
642 static void Write(MessageWriter
* aWriter
, const paramType
& aParam
) {
643 bool isNull
= aParam
== nullptr;
644 WriteParam(aWriter
, isNull
);
647 WriteParam(aWriter
, *aParam
.get());
651 static bool Read(IPC::MessageReader
* aReader
, paramType
* aResult
) {
653 if (!ReadParam(aReader
, &isNull
)) {
660 *aResult
= mozilla::MakeUnique
<T
>();
661 if (!ReadParam(aReader
, aResult
->get())) {
669 template <typename
... Ts
>
670 struct ParamTraits
<mozilla::Tuple
<Ts
...>> {
671 typedef mozilla::Tuple
<Ts
...> paramType
;
673 template <typename U
>
674 static void Write(IPC::MessageWriter
* aWriter
, U
&& aParam
) {
675 WriteInternal(aWriter
, std::forward
<U
>(aParam
),
676 std::index_sequence_for
<Ts
...>{});
679 static bool Read(IPC::MessageReader
* aReader
,
680 mozilla::Tuple
<Ts
...>* aResult
) {
681 return ReadInternal(aReader
, *aResult
, std::index_sequence_for
<Ts
...>{});
685 template <size_t... Is
>
686 static void WriteInternal(IPC::MessageWriter
* aWriter
,
687 const mozilla::Tuple
<Ts
...>& aParam
,
688 std::index_sequence
<Is
...>) {
689 WriteParams(aWriter
, mozilla::Get
<Is
>(aParam
)...);
692 template <size_t... Is
>
693 static void WriteInternal(IPC::MessageWriter
* aWriter
,
694 mozilla::Tuple
<Ts
...>&& aParam
,
695 std::index_sequence
<Is
...>) {
696 WriteParams(aWriter
, std::move(mozilla::Get
<Is
>(aParam
))...);
699 template <size_t... Is
>
700 static bool ReadInternal(IPC::MessageReader
* aReader
,
701 mozilla::Tuple
<Ts
...>& aResult
,
702 std::index_sequence
<Is
...>) {
703 return ReadParams(aReader
, mozilla::Get
<Is
>(aResult
)...);
707 } /* namespace IPC */
709 #endif /* __IPC_GLUE_IPCMESSAGEUTILSSPECIALIZATIONS_H__ */