Bug 1183249: Move PDU helper functions to ipc/hal, r=shuang
authorThomas Zimmermann <tdz@users.sourceforge.net>
Thu, 30 Jul 2015 10:34:51 +0200
changeset 287037 f82cbe9aaa134ad561966fd9821e46f91f3aef04
parent 287036 6275657f07e44342c63e7b9126e7e7d52ef494eb
child 287038 f42f6d74491744491ca35d5d1ee8df872b5cff2b
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1183249
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1183249: Move PDU helper functions to ipc/hal, r=shuang
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
ipc/hal/DaemonSocketPDUHelpers.cpp
ipc/hal/DaemonSocketPDUHelpers.h
ipc/hal/moz.build
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -6,102 +6,39 @@
 
 #include "BluetoothDaemonHelpers.h"
 #include <limits>
 
 #define MAX_UUID_SIZE 16
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+using mozilla::ipc::DaemonSocketPDUHelpers::Convert;
+using mozilla::ipc::DaemonSocketPDUHelpers::PackPDU;
+
 //
 // Conversion
 //
 
 nsresult
-Convert(bool aIn, uint8_t& aOut)
-{
-  static const bool sValue[] = {
-    CONVERT(false, 0x00),
-    CONVERT(true, 0x01)
-  };
-  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
-    aOut = 0;
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = sValue[aIn];
-  return NS_OK;
-}
-
-nsresult
-Convert(bool aIn, int32_t& aOut)
-{
-  static const bool sValue[] = {
-    CONVERT(false, 0x00),
-    CONVERT(true, 0x01)
-  };
-  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
-    aOut = 0;
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = sValue[aIn];
-  return NS_OK;
-}
-
-nsresult
 Convert(bool aIn, BluetoothScanMode& aOut)
 {
   static const BluetoothScanMode sScanMode[] = {
     CONVERT(false, SCAN_MODE_CONNECTABLE),
     CONVERT(true, SCAN_MODE_CONNECTABLE_DISCOVERABLE)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sScanMode))) {
     aOut = SCAN_MODE_NONE; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sScanMode[aIn];
   return NS_OK;
 }
 
 nsresult
-Convert(int aIn, uint8_t& aOut)
-{
-  if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
-      NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
-    aOut = 0; // silences compiler warning
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = static_cast<uint8_t>(aIn);
-  return NS_OK;
-}
-
-nsresult
-Convert(int aIn, int16_t& aOut)
-{
-  if (NS_WARN_IF(aIn < std::numeric_limits<int16_t>::min()) ||
-      NS_WARN_IF(aIn > std::numeric_limits<int16_t>::max())) {
-    aOut = 0; // silences compiler warning
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = static_cast<int16_t>(aIn);
-  return NS_OK;
-}
-
-nsresult
-Convert(int aIn, int32_t& aOut)
-{
-  if (NS_WARN_IF(aIn < std::numeric_limits<int32_t>::min()) ||
-      NS_WARN_IF(aIn > std::numeric_limits<int32_t>::max())) {
-    aOut = 0; // silences compiler warning
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = static_cast<int32_t>(aIn);
-  return NS_OK;
-}
-
-nsresult
 Convert(int32_t aIn, BluetoothTypeOfDevice& aOut)
 {
   static const BluetoothTypeOfDevice sTypeOfDevice[] = {
     CONVERT(0x00, static_cast<BluetoothTypeOfDevice>(0)), // invalid, required by gcc
     CONVERT(0x01, TYPE_OF_DEVICE_BREDR),
     CONVERT(0x02, TYPE_OF_DEVICE_BLE),
     CONVERT(0x03, TYPE_OF_DEVICE_DUAL)
   };
@@ -125,51 +62,16 @@ Convert(int32_t aIn, BluetoothScanMode& 
       NS_WARN_IF(static_cast<size_t>(aIn) >= MOZ_ARRAY_LENGTH(sScanMode))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sScanMode[aIn];
   return NS_OK;
 }
 
 nsresult
-Convert(uint8_t aIn, bool& aOut)
-{
-  static const bool sBool[] = {
-    CONVERT(0x00, false),
-    CONVERT(0x01, true)
-  };
-  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBool))) {
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = sBool[aIn];
-  return NS_OK;
-}
-
-nsresult
-Convert(uint8_t aIn, char& aOut)
-{
-  aOut = static_cast<char>(aIn);
-  return NS_OK;
-}
-
-nsresult
-Convert(uint8_t aIn, int& aOut)
-{
-  aOut = static_cast<int>(aIn);
-  return NS_OK;
-}
-
-nsresult
-Convert(uint8_t aIn, unsigned long& aOut)
-{
-  aOut = static_cast<unsigned long>(aIn);
-  return NS_OK;
-}
-
-nsresult
 Convert(uint8_t aIn, BluetoothA2dpAudioState& aOut)
 {
   static const BluetoothA2dpAudioState sAudioState[] = {
     CONVERT(0x00, A2DP_AUDIO_STATE_REMOTE_SUSPEND),
     CONVERT(0x01, A2DP_AUDIO_STATE_STOPPED),
     CONVERT(0x02, A2DP_AUDIO_STATE_STARTED)
   };
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sAudioState))) {
@@ -543,46 +445,16 @@ Convert(int32_t aIn, BluetoothGattStatus
     aOut = GATT_STATUS_UNKNOWN_ERROR;
   } else {
     aOut = sGattStatus[aIn];
   }
   return NS_OK;
 }
 
 nsresult
-Convert(uint32_t aIn, int& aOut)
-{
-  aOut = static_cast<int>(aIn);
-  return NS_OK;
-}
-
-nsresult
-Convert(uint32_t aIn, uint8_t& aOut)
-{
-  if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
-      NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
-    aOut = 0; // silences compiler warning
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = static_cast<uint8_t>(aIn);
-  return NS_OK;
-}
-
-nsresult
-Convert(size_t aIn, uint16_t& aOut)
-{
-  if (NS_WARN_IF(aIn >= (1ul << 16))) {
-    aOut = 0; // silences compiler warning
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-  aOut = static_cast<uint16_t>(aIn);
-  return NS_OK;
-}
-
-nsresult
 Convert(const nsAString& aIn, BluetoothAddress& aOut)
 {
   NS_ConvertUTF16toUTF8 bdAddressUTF8(aIn);
   const char* str = bdAddressUTF8.get();
 
   for (size_t i = 0; i < MOZ_ARRAY_LENGTH(aOut.mAddr); ++i, ++str) {
     aOut.mAddr[i] =
       static_cast<uint8_t>(strtoul(str, const_cast<char**>(&str), 16));
@@ -1256,22 +1128,16 @@ PackPDU(BluetoothAvrcpStatus aIn, Daemon
 nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, DaemonSocketPDU& aPDU)
 {
   return PackPDU(aIn.mType, aIn.mLength,
                  PackArray<uint8_t>(aIn.mValue.get(), aIn.mLength), aPDU);
 }
 
 nsresult
-PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU)
-{
-  return PackPDU(aIn.mService, aIn.mOpcode, aIn.mLength, aPDU);
-}
-
-nsresult
 PackPDU(const BluetoothHandsfreeAtResponse& aIn, DaemonSocketPDU& aPDU)
 {
   return PackPDU(
     PackConversion<BluetoothHandsfreeAtResponse, uint8_t>(aIn), aPDU);
 }
 
 nsresult
 PackPDU(const BluetoothHandsfreeCallAddressType& aIn, DaemonSocketPDU& aPDU)
@@ -1868,69 +1734,10 @@ UnpackPDU(DaemonSocketPDU& aPDU, Bluetoo
   /* unpack length */
   rv = UnpackPDU(aPDU, aOut.mLength);
   if (NS_FAILED(rv)) {
     return rv;
   }
   /* unpack value */
   return aPDU.Read(aOut.mValue, aOut.mLength);
 }
-nsresult
-UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& aOut)
-{
-  // We get a pointer to the first character in the PDU, a length
-  // of 1 ensures we consume the \0 byte. With 'str' pointing to
-  // the string in the PDU, we can copy the actual bytes.
-
-  const char* str = reinterpret_cast<const char*>(aPDU.Consume(1));
-  if (NS_WARN_IF(!str)) {
-    return NS_ERROR_ILLEGAL_VALUE; // end of PDU
-  }
-
-  const char* end = static_cast<char*>(memchr(str, '\0', aPDU.GetSize() + 1));
-  if (NS_WARN_IF(!end)) {
-    return NS_ERROR_ILLEGAL_VALUE; // no string terminator
-  }
-
-  ptrdiff_t len = end - str;
-
-  const uint8_t* rest = aPDU.Consume(len);
-  if (NS_WARN_IF(!rest)) {
-    // We couldn't consume bytes that should have been there.
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-
-  aOut.Rebind(str, len);
-
-  return NS_OK;
-}
-
-nsresult
-UnpackPDU(DaemonSocketPDU& aPDU, const UnpackCString0& aOut)
-{
-  nsDependentCString cstring;
-
-  nsresult rv = UnpackPDU(aPDU, cstring);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-
-  aOut.mString->AssignASCII(cstring.get(), cstring.Length());
-
-  return NS_OK;
-}
-
-nsresult
-UnpackPDU(DaemonSocketPDU& aPDU, const UnpackString0& aOut)
-{
-  nsDependentCString cstring;
-
-  nsresult rv = UnpackPDU(aPDU, cstring);
-  if (NS_FAILED(rv)) {
-    return NS_ERROR_ILLEGAL_VALUE;
-  }
-
-  *aOut.mString = NS_ConvertUTF8toUTF16(cstring);
-
-  return NS_OK;
-}
 
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
@@ -12,16 +12,21 @@
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/ipc/DaemonSocketPDU.h"
 #include "mozilla/ipc/DaemonSocketPDUHelpers.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 using mozilla::ipc::DaemonSocketPDU;
 using mozilla::ipc::DaemonSocketPDUHeader;
+using mozilla::ipc::DaemonSocketPDUHelpers::Convert;
+using mozilla::ipc::DaemonSocketPDUHelpers::PackPDU;
+using mozilla::ipc::DaemonSocketPDUHelpers::UnpackPDU;
+
+using namespace mozilla::ipc::DaemonSocketPDUHelpers;
 
 //
 // Helper structures
 //
 
 enum BluetoothAclState {
   ACL_STATE_CONNECTED,
   ACL_STATE_DISCONNECTED
@@ -118,60 +123,27 @@ struct BluetoothRemoteName {
 
 struct BluetoothServiceName {
   uint8_t mName[256];
 };
 
 //
 // Conversion
 //
-// PDUs can only store primitive data types, such as intergers or
-// strings. 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(bool aIn, BluetoothScanMode& aOut);
 
 nsresult
-Convert(int aIn, uint8_t& aOut);
-
-nsresult
-Convert(int aIn, int16_t& aOut);
-
-nsresult
-Convert(int aIn, int32_t& aOut);
-
-nsresult
 Convert(int32_t aIn, BluetoothTypeOfDevice& aOut);
 
 nsresult
 Convert(int32_t aIn, BluetoothScanMode& 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(uint8_t aIn, BluetoothA2dpAudioState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothA2dpConnectionState& aOut);
 
 nsresult
 Convert(uint8_t aIn, BluetoothAclState& aOut);
 
@@ -225,25 +197,16 @@ Convert(uint8_t aIn, BluetoothSspVariant
 
 nsresult
 Convert(uint8_t aIn, BluetoothStatus& aOut);
 
 nsresult
 Convert(int32_t aIn, BluetoothGattStatus& aOut);
 
 nsresult
-Convert(uint32_t aIn, int& aOut);
-
-nsresult
-Convert(uint32_t aIn, uint8_t& aOut);
-
-nsresult
-Convert(size_t aIn, uint16_t& aOut);
-
-nsresult
 Convert(const nsAString& aIn, BluetoothAddress& aOut);
 
 nsresult
 Convert(const nsAString& aIn, BluetoothPinCode& aOut);
 
 nsresult
 Convert(const nsAString& aIn, BluetoothPropertyType& aOut);
 
@@ -324,48 +287,19 @@ Convert(BluetoothGattAuthReq aIn, int32_
 
 nsresult
 Convert(BluetoothGattWriteType aIn, int32_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);
-}
-
 nsresult
 PackPDU(const BluetoothAddress& aIn, DaemonSocketPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothAvrcpAttributeTextPairs& aIn,
         DaemonSocketPDU& aPDU);
 
 nsresult
@@ -389,19 +323,16 @@ PackPDU(BluetoothAvrcpPlayerAttribute aI
 
 nsresult
 PackPDU(BluetoothAvrcpStatus aIn, DaemonSocketPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothConfigurationParameter& aIn, DaemonSocketPDU& aPDU);
 
 nsresult
-PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU);
-
-nsresult
 PackPDU(const BluetoothHandsfreeAtResponse& aIn, DaemonSocketPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothHandsfreeCallAddressType& aIn, DaemonSocketPDU& aPDU);
 
 nsresult
 PackPDU(const BluetoothHandsfreeCallDirection& aIn, DaemonSocketPDU& aPDU);
 
@@ -855,51 +786,16 @@ PackPDU(const T1& aIn1, const T2& aIn2, 
   }
   return PackPDU(aIn13, aPDU);
 }
 
 //
 // Unpacking
 //
 
-// introduce link errors on non-handled data types
-template <typename T>
-nsresult
-UnpackPDU(DaemonSocketPDU& aPDU, T& 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);
-}
-
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, bool& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, char& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothA2dpAudioState& aOut);
@@ -929,30 +825,16 @@ nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAvrcpPlayerSettings& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothAvrcpRemoteFeature& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothBondState& 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, BluetoothTypeOfDevice& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeAudioState& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeCallHoldType& aOut);
@@ -1016,19 +898,16 @@ nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattReadParam& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattWriteParam& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattNotifyParam& aOut);
 
-nsresult
-UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& 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)
@@ -1123,54 +1002,16 @@ UnpackPDU(DaemonSocketPDU& aPDU, nsTArra
     nsresult rv = UnpackPDU(aPDU, aOut[i]);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
   return NS_OK;
 }
 
-/* |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);
-
 /* |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)
new file mode 100644
--- /dev/null
+++ b/ipc/hal/DaemonSocketPDUHelpers.cpp
@@ -0,0 +1,235 @@
+/* -*- 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/. */
+
+#include "DaemonSocketPDUHelpers.h"
+#include <limits>
+
+namespace mozilla {
+namespace ipc {
+namespace DaemonSocketPDUHelpers {
+
+//
+// Conversion
+//
+
+nsresult
+Convert(bool aIn, uint8_t& aOut)
+{
+  static const uint8_t sValue[] = {
+    [false] = 0x00,
+    [true] = 0x01
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sValue))) {
+    aOut = 0;
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sValue[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(bool aIn, int32_t& aOut)
+{
+  uint8_t out;
+  nsresult rv = Convert(aIn, out);
+  if (NS_FAILED(rv)) {
+    out = 0; // silence compiler warning
+    return rv;
+  }
+  aOut = static_cast<int32_t>(out);
+  return NS_OK;
+}
+
+nsresult
+Convert(int aIn, uint8_t& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<uint8_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(int aIn, int16_t& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<int16_t>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<int16_t>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<int16_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(int aIn, int32_t& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<int32_t>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<int32_t>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<int32_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, bool& aOut)
+{
+  static const bool sBool[] = {
+    [0x00] = false,
+    [0x01] = true
+  };
+  if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sBool))) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sBool[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, char& aOut)
+{
+  aOut = static_cast<char>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, int& aOut)
+{
+  aOut = static_cast<int>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, unsigned long& aOut)
+{
+  aOut = static_cast<unsigned long>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(uint32_t aIn, int& aOut)
+{
+  aOut = static_cast<int>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(uint32_t aIn, uint8_t& aOut)
+{
+  if (NS_WARN_IF(aIn < std::numeric_limits<uint8_t>::min()) ||
+      NS_WARN_IF(aIn > std::numeric_limits<uint8_t>::max())) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<uint8_t>(aIn);
+  return NS_OK;
+}
+
+nsresult
+Convert(size_t aIn, uint16_t& aOut)
+{
+  if (NS_WARN_IF(aIn >= (1ul << 16))) {
+    aOut = 0; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = static_cast<uint16_t>(aIn);
+  return NS_OK;
+}
+
+//
+// Packing
+//
+
+nsresult
+PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU)
+{
+  nsresult rv = PackPDU(aIn.mService, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn.mOpcode, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = PackPDU(aIn.mLength, aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return NS_OK;
+}
+
+//
+// Unpacking
+//
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, nsDependentCString& aOut)
+{
+  // We get a pointer to the first character in the PDU, a length
+  // of 1 ensures we consume the \0 byte. With 'str' pointing to
+  // the string in the PDU, we can copy the actual bytes.
+
+  const char* str = reinterpret_cast<const char*>(aPDU.Consume(1));
+  if (NS_WARN_IF(!str)) {
+    return NS_ERROR_ILLEGAL_VALUE; // end of PDU
+  }
+
+  const char* end = static_cast<char*>(memchr(str, '\0', aPDU.GetSize() + 1));
+  if (NS_WARN_IF(!end)) {
+    return NS_ERROR_ILLEGAL_VALUE; // no string terminator
+  }
+
+  ptrdiff_t len = end - str;
+
+  const uint8_t* rest = aPDU.Consume(len);
+  if (NS_WARN_IF(!rest)) {
+    // We couldn't consume bytes that should have been there.
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  aOut.Rebind(str, len);
+
+  return NS_OK;
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackCString0& aOut)
+{
+  nsDependentCString cstring;
+
+  nsresult rv = UnpackPDU(aPDU, cstring);
+  if (NS_FAILED(rv)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  aOut.mString->AssignASCII(cstring.get(), cstring.Length());
+
+  return NS_OK;
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, const UnpackString0& aOut)
+{
+  nsDependentCString cstring;
+
+  nsresult rv = UnpackPDU(aPDU, cstring);
+  if (NS_FAILED(rv)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  *aOut.mString = NS_ConvertUTF8toUTF16(cstring);
+
+  return NS_OK;
+}
+
+} // namespace DaemonSocketPDUHelpers
+} // namespace ipc
+} // namespace mozilla
--- a/ipc/hal/DaemonSocketPDUHelpers.h
+++ b/ipc/hal/DaemonSocketPDUHelpers.h
@@ -3,16 +3,18 @@
 /* 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 "nsString.h"
 
 namespace mozilla {
 namespace ipc {
 
 struct DaemonSocketPDUHeader {
   DaemonSocketPDUHeader()
     : mService(0x00)
     , mOpcode(0x00)
@@ -25,12 +27,192 @@ struct DaemonSocketPDUHeader {
     , mLength(aLength)
   { }
 
   uint8_t mService;
   uint8_t mOpcode;
   uint16_t mLength;
 };
 
+namespace DaemonSocketPDUHelpers {
+
+//
+// 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);
+
+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);
+}
+
+nsresult
+PackPDU(const DaemonSocketPDUHeader& aIn, DaemonSocketPDU& aPDU);
+
+//
+// Unpacking
+//
+
+// introduce link errors on non-handled data types
+template <typename T>
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, T& 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, 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);
+
+} // namespace DaemonSocketPDUHelpers
+
 } // namespace ipc
 } // namespace mozilla
 
 #endif // mozilla_ipc_DaemonSocketPDUHelpers_h
--- a/ipc/hal/moz.build
+++ b/ipc/hal/moz.build
@@ -10,16 +10,17 @@ EXPORTS.mozilla.ipc += [
     'DaemonSocketConsumer.h',
     'DaemonSocketPDU.h',
     'DaemonSocketPDUHelpers.h'
 ]
 
 UNIFIED_SOURCES += [
     'DaemonSocket.cpp',
     'DaemonSocketConsumer.cpp',
-    'DaemonSocketPDU.cpp'
+    'DaemonSocketPDU.cpp',
+    'DaemonSocketPDUHelpers.cpp'
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True