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 275438 f82cbe9aaa134ad561966fd9821e46f91f3aef04
parent 275437 6275657f07e44342c63e7b9126e7e7d52ef494eb
child 275439 f42f6d74491744491ca35d5d1ee8df872b5cff2b
push id8304
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 19:25:01 +0000
treeherdermozilla-aurora@7308dd0a6c3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersshuang
bugs1183249
milestone42.0a1
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