summaryrefslogtreecommitdiffstats
path: root/ipc/hal/DaemonSocketPDUHelpers.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /ipc/hal/DaemonSocketPDUHelpers.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'ipc/hal/DaemonSocketPDUHelpers.h')
-rw-r--r--ipc/hal/DaemonSocketPDUHelpers.h1283
1 files changed, 1283 insertions, 0 deletions
diff --git a/ipc/hal/DaemonSocketPDUHelpers.h b/ipc/hal/DaemonSocketPDUHelpers.h
new file mode 100644
index 000000000..38a848e46
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDUHelpers.h
@@ -0,0 +1,1283 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_ipc_DaemonSocketPDUHelpers_h
+#define mozilla_ipc_DaemonSocketPDUHelpers_h
+
+#include <stdint.h>
+#include "mozilla/ipc/DaemonSocketPDU.h"
+#include "mozilla/UniquePtr.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace ipc {
+
+struct DaemonSocketPDUHeader {
+ DaemonSocketPDUHeader()
+ : mService(0x00)
+ , mOpcode(0x00)
+ , mLength(0x00)
+ { }
+
+ DaemonSocketPDUHeader(uint8_t aService, uint8_t aOpcode, uint16_t aLength)
+ : mService(aService)
+ , mOpcode(aOpcode)
+ , mLength(aLength)
+ { }
+
+ uint8_t mService;
+ uint8_t mOpcode;
+ uint16_t mLength;
+};
+
+namespace DaemonSocketPDUHelpers {
+
+//
+// Logging
+//
+// The HAL IPC logging macros below print clear error messages for
+// failed IPC operations. Use |MOZ_HAL_IPC_CONVERT_WARN_IF|,
+// |MOZ_HAL_IPC_PACK_WARN_IF| and |MOZ_HAL_IPC_UNPACK_WARN_IF| to
+// test for failures when processing PDUs.
+//
+// All macros accept the test condition as their first argument, and
+// additional type information: the convert macro takes the input and
+// output types, the pack macro takes the input type, and the unpack
+// macro takes output type. All macros return the result of the test
+// condition. If the test fails (i.e., the condition is true), they
+// output a warning to the log.
+//
+// Don't call the functions in the detail namespace. They are helpers
+// and not for general use.
+//
+
+namespace detail {
+
+void
+LogProtocolError(const char*, ...);
+
+inline bool
+ConvertWarnIfImpl(const char* aFile, unsigned long aLine,
+ bool aCondition, const char* aExpr, const char* aIn,
+ const char* aOut)
+{
+ if (MOZ_UNLIKELY(aCondition)) {
+ LogProtocolError("%s:%d: Convert('%s' to '%s') failed: %s",
+ aFile, aLine, aIn, aOut, aExpr);
+ }
+ return aCondition;
+}
+
+inline bool
+PackWarnIfImpl(const char* aFile, unsigned long aLine,
+ bool aCondition, const char* aExpr, const char* aIn)
+{
+ if (MOZ_UNLIKELY(aCondition)) {
+ LogProtocolError("%s:%d: Pack('%s') failed: %s",
+ aFile, aLine, aIn, aExpr);
+ }
+ return aCondition;
+}
+
+inline bool
+UnpackWarnIfImpl(const char* aFile, unsigned long aLine,
+ bool aCondition, const char* aExpr, const char* aOut)
+{
+ if (MOZ_UNLIKELY(aCondition)) {
+ LogProtocolError("%s:%d: Unpack('%s') failed: %s",
+ aFile, aLine, aOut, aExpr);
+ }
+ return aCondition;
+}
+
+} // namespace detail
+
+#define MOZ_HAL_IPC_CONVERT_WARN_IF(condition, in, out) \
+ ::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
+ ConvertWarnIfImpl(__FILE__, __LINE__, condition, #condition, #in, #out)
+
+#define MOZ_HAL_IPC_PACK_WARN_IF(condition, in) \
+ ::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
+ PackWarnIfImpl(__FILE__, __LINE__, condition, #condition, #in)
+
+#define MOZ_HAL_IPC_UNPACK_WARN_IF(condition, out) \
+ ::mozilla::ipc::DaemonSocketPDUHelpers::detail:: \
+ UnpackWarnIfImpl(__FILE__, __LINE__, condition, #condition, #out)
+
+//
+// Conversion
+//
+// PDUs can only store primitive data types, such as integers or
+// byte arrays. Gecko often uses more complex data types, such as
+// enumators or stuctures. Conversion functions convert between
+// primitive data and internal Gecko's data types during a PDU's
+// packing and unpacking.
+//
+
+nsresult
+Convert(bool aIn, uint8_t& aOut);
+
+nsresult
+Convert(bool aIn, int32_t& aOut);
+
+nsresult
+Convert(int aIn, uint8_t& aOut);
+
+nsresult
+Convert(int aIn, int16_t& aOut);
+
+nsresult
+Convert(int aIn, int32_t& aOut);
+
+nsresult
+Convert(uint8_t aIn, bool& aOut);
+
+nsresult
+Convert(uint8_t aIn, char& aOut);
+
+nsresult
+Convert(uint8_t aIn, int& aOut);
+
+nsresult
+Convert(uint8_t aIn, unsigned long& aOut);
+
+nsresult
+Convert(uint32_t aIn, int& aOut);
+
+nsresult
+Convert(uint32_t aIn, uint8_t& aOut);
+
+nsresult
+Convert(size_t aIn, uint16_t& aOut);
+
+//
+// Packing
+//
+
+// introduce link errors on non-handled data types
+template <typename T>
+nsresult
+PackPDU(T aIn, DaemonSocketPDU& aPDU);
+
+nsresult
+PackPDU(bool aIn, DaemonSocketPDU& aPDU);
+
+inline nsresult
+PackPDU(uint8_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(uint16_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(int32_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(uint32_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(int64_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(uint64_t aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(float aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+inline nsresult
+PackPDU(double aIn, DaemonSocketPDU& aPDU)
+{
+ return aPDU.Write(aIn);
+}
+
+nsresult
+PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU);
+
+/* |PackConversion| is a helper for packing converted values. Pass
+ * an instance of this structure to |PackPDU| to convert a value from
+ * the input type to the output type and and write it to the PDU.
+ */
+template<typename Tin, typename Tout>
+struct PackConversion {
+ PackConversion(const Tin& aIn)
+ : mIn(aIn)
+ { }
+
+ const Tin& mIn;
+};
+
+template<typename Tin, typename Tout>
+inline nsresult
+PackPDU(const PackConversion<Tin, Tout>& aIn, DaemonSocketPDU& aPDU)
+{
+ Tout out;
+
+ nsresult rv = Convert(aIn.mIn, out);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(out, aPDU);
+}
+
+/* |PackArray| is a helper for packing arrays. Pass an instance
+ * of this structure as the first argument to |PackPDU| to pack
+ * an array. The array's maximum default length is 255 elements.
+ */
+template <typename T>
+struct PackArray
+{
+ PackArray(const T* aData, size_t aLength)
+ : mData(aData)
+ , mLength(aLength)
+ { }
+
+ const T* mData;
+ size_t mLength;
+};
+
+/* This implementation of |PackPDU| packs the length of an array
+ * and the elements of the array one-by-one.
+ */
+template<typename T>
+inline nsresult
+PackPDU(const PackArray<T>& aIn, DaemonSocketPDU& aPDU)
+{
+ for (size_t i = 0; i < aIn.mLength; ++i) {
+ nsresult rv = PackPDU(aIn.mData[i], aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template<>
+inline nsresult
+PackPDU<uint8_t>(const PackArray<uint8_t>& aIn, DaemonSocketPDU& aPDU)
+{
+ /* Write raw bytes in one pass */
+ return aPDU.Write(aIn.mData, aIn.mLength);
+}
+
+template<>
+inline nsresult
+PackPDU<char>(const PackArray<char>& aIn, DaemonSocketPDU& aPDU)
+{
+ /* Write raw bytes in one pass */
+ return aPDU.Write(aIn.mData, aIn.mLength);
+}
+
+/* |PackCString0| is a helper for packing 0-terminated C string,
+ * including the \0 character. Pass an instance of this structure
+ * as the first argument to |PackPDU| to pack a string.
+ */
+struct PackCString0
+{
+ PackCString0(const nsCString& aString)
+ : mString(aString)
+ { }
+
+ const nsCString& mString;
+};
+
+/* This implementation of |PackPDU| packs a 0-terminated C string.
+ */
+inline nsresult
+PackPDU(const PackCString0& aIn, DaemonSocketPDU& aPDU)
+{
+ return PackPDU(
+ PackArray<uint8_t>(reinterpret_cast<const uint8_t*>(aIn.mString.get()),
+ aIn.mString.Length() + 1), aPDU);
+}
+
+/* |PackReversed| is a helper for packing data in reversed order. Pass an
+ * instance of this structure as the first argument to |PackPDU| to pack data
+ * in reversed order.
+ */
+template<typename T>
+struct PackReversed
+{
+ PackReversed(const T& aValue)
+ : mValue(aValue)
+ { }
+
+ const T& mValue;
+};
+
+/* No general rules to pack data in reversed order. Signal a link error if the
+ * type |T| of |PackReversed| is not defined explicitly.
+ */
+template<typename T>
+nsresult
+PackPDU(const PackReversed<T>& aIn, DaemonSocketPDU& aPDU);
+
+/* This implementation of |PackPDU| packs elements in |PackArray| in reversed
+ * order. (ex. reversed GATT UUID, see bug 1171866)
+ */
+template<typename U>
+inline nsresult
+PackPDU(const PackReversed<PackArray<U>>& aIn, DaemonSocketPDU& aPDU)
+{
+ for (size_t i = 0; i < aIn.mValue.mLength; ++i) {
+ nsresult rv = PackPDU(aIn.mValue.mData[aIn.mValue.mLength - i - 1], aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+/* |PackArray<PackReversed<U>>| is a helper for packing data of each element in
+ * the reversed order. Pass an instance of this structure as the first argument
+ * to |PackPDU| to pack data of each array element in the reversed order.
+ *
+ * Unlike |PackReversed<PackArray<U>>| which packed array elements in the
+ * reversed order, here we use |PackReversed<U>| to pack data of each element
+ * of |PackArray| in the reversed order.
+ */
+template<typename U>
+struct PackArray<PackReversed<U>>
+{
+ PackArray(const U* aData, size_t aLength)
+ : mData(aData)
+ , mLength(aLength)
+ { }
+
+ const U* mData;
+ size_t mLength;
+};
+
+/* This implementation of |PackPDU| packs data of each element in |PackArray|
+ * in the reversed order. (ex. reversed GATT UUID, see bug 1171866)
+ */
+template<typename U>
+inline nsresult
+PackPDU(const PackArray<PackReversed<U>>& aIn, DaemonSocketPDU& aPDU)
+{
+ for (size_t i = 0; i < aIn.mLength; ++i) {
+ nsresult rv = PackPDU(PackReversed<U>(aIn.mData[i]), aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template <typename T1, typename T2>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn2, aPDU);
+}
+
+template <typename T1, typename T2, typename T3>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn3, aPDU);
+}
+
+template <typename T1, typename T2, typename T3, typename T4>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3, const T4& aIn4,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn4, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn5, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn6, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6,
+ typename T7>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ const T7& aIn7, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn6, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn7, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6,
+ typename T7, typename T8>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ const T7& aIn7, const T8& aIn8, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn6, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn7, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn8, aPDU);
+}
+
+template <typename T1, typename T2, typename T3,
+ typename T4, typename T5, typename T6,
+ typename T7, typename T8, typename T9,
+ typename T10, typename T11, typename T12,
+ typename T13>
+inline nsresult
+PackPDU(const T1& aIn1, const T2& aIn2, const T3& aIn3,
+ const T4& aIn4, const T5& aIn5, const T6& aIn6,
+ const T7& aIn7, const T8& aIn8, const T9& aIn9,
+ const T10& aIn10, const T11& aIn11, const T12& aIn12,
+ const T13& aIn13, DaemonSocketPDU& aPDU)
+{
+ nsresult rv = PackPDU(aIn1, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn2, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn3, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn4, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn5, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn6, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn7, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn8, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn9, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn10, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn11, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = PackPDU(aIn12, aPDU);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return PackPDU(aIn13, aPDU);
+}
+
+//
+// Unpacking
+//
+
+// introduce link errors on non-handled data types
+template <typename T>
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, T& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, char& aOut);
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, int8_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint8_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint16_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, int32_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint32_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, int64_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, uint64_t& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, float& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, double& aOut)
+{
+ return aPDU.Read(aOut);
+}
+
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, DaemonSocketPDUHeader& aOut)
+{
+ nsresult rv = UnpackPDU(aPDU, aOut.mService);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(aPDU, aOut.mOpcode);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return UnpackPDU(aPDU, aOut.mLength);
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& aOut);
+
+/* |UnpackCString0| is a helper for unpacking 0-terminated C string,
+ * including the \0 character. Pass an instance of this structure
+ * as the first argument to |UnpackPDU| to unpack a string.
+ */
+struct UnpackCString0
+{
+ UnpackCString0(nsCString& aString)
+ : mString(&aString)
+ { }
+
+ nsCString* mString; // non-null by construction
+};
+
+/* This implementation of |UnpackPDU| unpacks a 0-terminated C string.
+ */
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackCString0& aOut);
+
+/* |UnpackString0| is a helper for unpacking 0-terminated C string,
+ * including the \0 character. Pass an instance of this structure
+ * as the first argument to |UnpackPDU| to unpack a C string and convert
+ * it to wide-character encoding.
+ */
+struct UnpackString0
+{
+ UnpackString0(nsString& aString)
+ : mString(&aString)
+ { }
+
+ nsString* mString; // non-null by construction
+};
+
+/* This implementation of |UnpackPDU| unpacks a 0-terminated C string
+ * and converts it to wide-character encoding.
+ */
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackString0& aOut);
+
+/* |UnpackConversion| is a helper for convering unpacked values. Pass
+ * an instance of this structure to |UnpackPDU| to read a value from
+ * the PDU in the input type and convert it to the output type.
+ */
+template<typename Tin, typename Tout>
+struct UnpackConversion {
+ UnpackConversion(Tout& aOut)
+ : mOut(aOut)
+ { }
+
+ Tout& mOut;
+};
+
+template<typename Tin, typename Tout>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackConversion<Tin, Tout>& aOut)
+{
+ Tin in;
+ nsresult rv = UnpackPDU(aPDU, in);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ return Convert(in, aOut.mOut);
+}
+
+/* |UnpackArray| is a helper for unpacking arrays. Pass an instance
+ * of this structure as the second argument to |UnpackPDU| to unpack
+ * an array.
+ */
+template <typename T>
+struct UnpackArray
+{
+ UnpackArray(T* aData, size_t aLength)
+ : mData(aData)
+ , mLength(aLength)
+ { }
+
+ UnpackArray(UniquePtr<T[]>& aData, size_t aLength)
+ : mData(nullptr)
+ , mLength(aLength)
+ {
+ aData.reset(new T[mLength]);
+ mData = aData.get();
+ }
+
+ UnpackArray(UniquePtr<T>& aData, size_t aSize, size_t aElemSize)
+ : mData(nullptr)
+ , mLength(aSize / aElemSize)
+ {
+ aData.reset(new T[mLength]);
+ mData = aData.get();
+ }
+
+ T* mData;
+ size_t mLength;
+};
+
+template<typename T>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackArray<T>& aOut)
+{
+ for (size_t i = 0; i < aOut.mLength; ++i) {
+ nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template<typename T>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, UnpackArray<T>& aOut)
+{
+ for (size_t i = 0; i < aOut.mLength; ++i) {
+ nsresult rv = UnpackPDU(aPDU, aOut.mData[i]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+template<>
+inline nsresult
+UnpackPDU<uint8_t>(DaemonSocketPDU& aPDU, const UnpackArray<uint8_t>& aOut)
+{
+ /* Read raw bytes in one pass */
+ return aPDU.Read(aOut.mData, aOut.mLength);
+}
+
+template<typename T>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, nsTArray<T>& aOut)
+{
+ for (typename nsTArray<T>::size_type i = 0; i < aOut.Length(); ++i) {
+ nsresult rv = UnpackPDU(aPDU, aOut[i]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+/* |UnpackReversed| is a helper for unpacking data in reversed order. Pass an
+ * instance of this structure as the second argument to |UnpackPDU| to unpack
+ * data in reversed order.
+ */
+template<typename T>
+struct UnpackReversed
+{
+ UnpackReversed(T& aValue)
+ : mValue(&aValue)
+ { }
+
+ UnpackReversed(T&& aValue)
+ : mValue(&aValue)
+ { }
+
+ T* mValue;
+};
+
+/* No general rules to unpack data in reversed order. Signal a link error if
+ * the type |T| of |UnpackReversed| is not defined explicitly.
+ */
+template<typename T>
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<T>& aOut);
+
+template<typename U>
+inline nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<UnpackArray<U>>& aOut)
+{
+ for (size_t i = 0; i < aOut.mValue->mLength; ++i) {
+ nsresult rv = UnpackPDU(aPDU,
+ aOut.mValue->mData[aOut.mValue->mLength - i - 1]);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+ return NS_OK;
+}
+
+//
+// Init operators
+//
+
+//
+// Below are general-purpose init operators for Bluetooth. The classes
+// of type |ConstantInitOp[1..3]| initialize results or notifications
+// with constant values.
+//
+
+template <typename T1>
+class ConstantInitOp1 final
+{
+public:
+ ConstantInitOp1(const T1& aArg1)
+ : mArg1(aArg1)
+ { }
+
+ nsresult operator () (T1& aArg1) const
+ {
+ aArg1 = mArg1;
+
+ return NS_OK;
+ }
+
+private:
+ const T1& mArg1;
+};
+
+template <typename T1, typename T2>
+class ConstantInitOp2 final
+{
+public:
+ ConstantInitOp2(const T1& aArg1, const T2& aArg2)
+ : mArg1(aArg1)
+ , mArg2(aArg2)
+ { }
+
+ nsresult operator () (T1& aArg1, T2& aArg2) const
+ {
+ aArg1 = mArg1;
+ aArg2 = mArg2;
+
+ return NS_OK;
+ }
+
+private:
+ const T1& mArg1;
+ const T2& mArg2;
+};
+
+template <typename T1, typename T2, typename T3>
+class ConstantInitOp3 final
+{
+public:
+ ConstantInitOp3(const T1& aArg1, const T2& aArg2, const T3& aArg3)
+ : mArg1(aArg1)
+ , mArg2(aArg2)
+ , mArg3(aArg3)
+ { }
+
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const
+ {
+ aArg1 = mArg1;
+ aArg2 = mArg2;
+ aArg3 = mArg3;
+
+ return NS_OK;
+ }
+
+private:
+ const T1& mArg1;
+ const T2& mArg2;
+ const T3& mArg3;
+};
+
+// |PDUInitOP| provides functionality for init operators that unpack PDUs.
+class PDUInitOp
+{
+protected:
+ PDUInitOp(DaemonSocketPDU& aPDU)
+ : mPDU(&aPDU)
+ { }
+
+ DaemonSocketPDU& GetPDU() const
+ {
+ return *mPDU; // cannot be nullptr
+ }
+
+ void WarnAboutTrailingData() const;
+
+private:
+ DaemonSocketPDU* mPDU; // Hold pointer to allow for constant instances
+};
+
+// |UnpackPDUInitOp| is a general-purpose init operator for all variants
+// of |DaemonResultRunnable| and |DaemonNotificationRunnable|. The call
+// operators of |UnpackPDUInitOp| unpack a PDU into the supplied
+// arguments.
+class UnpackPDUInitOp final : private PDUInitOp
+{
+public:
+ UnpackPDUInitOp(DaemonSocketPDU& aPDU)
+ : PDUInitOp(aPDU)
+ { }
+
+ nsresult operator () () const
+ {
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1>
+ nsresult operator () (T1& aArg1) const
+ {
+ nsresult rv = UnpackPDU(GetPDU(), aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2>
+ nsresult operator () (T1& aArg1, T2& aArg2) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4,
+ typename T5, typename T6>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6, T7& aArg7) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg7);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6, T7& aArg7, T8& aArg8) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg7);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg8);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+
+ template<typename T1, typename T2, typename T3, typename T4, typename T5,
+ typename T6, typename T7, typename T8, typename T9>
+ nsresult operator () (T1& aArg1, T2& aArg2, T3& aArg3, T4& aArg4,
+ T5& aArg5, T6& aArg6, T7& aArg7, T8& aArg8,
+ T9& aArg9) const
+ {
+ DaemonSocketPDU& pdu = GetPDU();
+
+ nsresult rv = UnpackPDU(pdu, aArg1);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg2);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg3);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg4);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg5);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg6);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg7);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg8);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = UnpackPDU(pdu, aArg9);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ WarnAboutTrailingData();
+ return NS_OK;
+ }
+};
+
+} // namespace DaemonSocketPDUHelpers
+
+} // namespace ipc
+} // namespace mozilla
+
+#endif // mozilla_ipc_DaemonSocketPDUHelpers_h