/* -*- 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 "PropertyBagUtils.h" #include "mozilla/SimpleEnumerator.h" #include "mozilla/dom/DOMTypes.h" #include "nsCOMPtr.h" #include "nsHashPropertyBag.h" #include "nsID.h" #include "nsIProperty.h" #include "nsIURI.h" #include "nsVariant.h" using namespace IPC; using namespace mozilla::dom; namespace mozilla::ipc { void IPDLParamTraits::Write(Message* aMsg, IProtocol* aActor, nsIVariant* aParam) { IDPLVariant variant; variant.type() = aParam->GetDataType(); switch (variant.type()) { case nsIDataType::VTYPE_INT8: case nsIDataType::VTYPE_UINT8: case nsIDataType::VTYPE_CHAR: { uint8_t value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsUint8(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_WCHAR: case nsIDataType::VTYPE_INT16: { int16_t value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsInt16(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_UINT16: { uint16_t value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsUint16(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_INT32: { int32_t value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsInt32(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_UINT32: { uint32_t value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsUint32(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_FLOAT: { float value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsFloat(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_DOUBLE: { double value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsDouble(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_BOOL: { bool value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsBool(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_ID: { nsID value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsID(&value)); variant.data() = value; break; } case nsIDataType::VTYPE_ASTRING: case nsIDataType::VTYPE_WCHAR_STR: case nsIDataType::VTYPE_WSTRING_SIZE_IS: { nsString value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsAString(value)); variant.data() = value; break; } case nsIDataType::VTYPE_CSTRING: case nsIDataType::VTYPE_CHAR_STR: case nsIDataType::VTYPE_STRING_SIZE_IS: case nsIDataType::VTYPE_UTF8STRING: { nsCString value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsACString(value)); variant.data() = value; break; } case nsIDataType::VTYPE_INTERFACE: case nsIDataType::VTYPE_INTERFACE_IS: { nsIID* iid; nsCOMPtr value; MOZ_ALWAYS_SUCCEEDS(aParam->GetAsInterface(&iid, getter_AddRefs(value))); free(iid); // We only accept nsIURI and nsIPrincipal interface types, patch welcome. if (nsCOMPtr uri = do_QueryInterface(value)) { variant.data() = uri; } else if (nsCOMPtr principal = do_QueryInterface(value)) { variant.data() = principal; } else if (value) { variant.type() = nsIDataType::VTYPE_EMPTY; variant.data() = false; // because we need something. } else { // Let's pretend like we had a null URI, though how do we know // it wasn't a null principal? variant.data() = (nsIURI*)nullptr; } break; } case nsIDataType::VTYPE_VOID: case nsIDataType::VTYPE_EMPTY: variant.data() = false; // because we need something. break; default: MOZ_CRASH("Non handled variant type, patch welcome"); break; } WriteIPDLParam(aMsg, aActor, variant); } bool IPDLParamTraits::Read(const Message* aMsg, PickleIterator* aIter, IProtocol* aActor, RefPtr* aResult) { IDPLVariant value; if (!ReadIPDLParam(aMsg, aIter, aActor, &value)) { return false; } auto variant = MakeRefPtr(); switch (value.type()) { case nsIDataType::VTYPE_INT8: case nsIDataType::VTYPE_UINT8: if (value.type() == nsIDataType::VTYPE_INT8) { variant->SetAsInt8(value.data().get_uint8_t()); } else { variant->SetAsUint8(value.data().get_uint8_t()); } break; case nsIDataType::VTYPE_INT16: variant->SetAsInt16(value.data().get_int16_t()); break; case nsIDataType::VTYPE_INT32: variant->SetAsInt32(value.data().get_int32_t()); break; case nsIDataType::VTYPE_UINT16: variant->SetAsUint16(value.data().get_uint16_t()); break; case nsIDataType::VTYPE_UINT32: variant->SetAsUint32(value.data().get_uint32_t()); break; case nsIDataType::VTYPE_FLOAT: variant->SetAsFloat(value.data().get_float()); break; case nsIDataType::VTYPE_DOUBLE: variant->SetAsDouble(value.data().get_double()); break; case nsIDataType::VTYPE_BOOL: variant->SetAsBool(value.data().get_bool()); break; case nsIDataType::VTYPE_CHAR: variant->SetAsChar(value.data().get_uint8_t()); break; case nsIDataType::VTYPE_WCHAR: variant->SetAsWChar(value.data().get_int16_t()); break; case nsIDataType::VTYPE_ID: variant->SetAsID(value.data().get_nsID()); break; case nsIDataType::VTYPE_ASTRING: case nsIDataType::VTYPE_WCHAR_STR: case nsIDataType::VTYPE_WSTRING_SIZE_IS: variant->SetAsAString(value.data().get_nsString()); break; case nsIDataType::VTYPE_CSTRING: case nsIDataType::VTYPE_CHAR_STR: case nsIDataType::VTYPE_STRING_SIZE_IS: variant->SetAsACString(value.data().get_nsCString()); break; case nsIDataType::VTYPE_UTF8STRING: variant->SetAsAUTF8String(value.data().get_nsCString()); break; case nsIDataType::VTYPE_INTERFACE: case nsIDataType::VTYPE_INTERFACE_IS: if (value.data().type() == IPDLVariantValue::TnsIURI) { variant->SetAsISupports(value.data().get_nsIURI()); } else if (value.data().type() == IPDLVariantValue::TnsIPrincipal) { variant->SetAsISupports(value.data().get_nsIPrincipal()); } else { MOZ_CRASH("Unexpected interface type"); } break; case nsIDataType::VTYPE_VOID: variant->SetAsVoid(); break; case nsIDataType::VTYPE_EMPTY: break; default: MOZ_CRASH("Non handled variant type, patch welcome"); return false; } *aResult = std::move(variant); return true; } void IPDLParamTraits::Write(Message* aMsg, IProtocol* aActor, nsIPropertyBag2* aParam) { // We send a nsIPropertyBag as an array of IPDLProperty nsTArray bag; nsCOMPtr enumerator; if (aParam && NS_SUCCEEDED(aParam->GetEnumerator(getter_AddRefs(enumerator)))) { for (auto& property : SimpleEnumerator(enumerator)) { nsString name; nsCOMPtr value; MOZ_ALWAYS_SUCCEEDS(property->GetName(name)); MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value))); bag.AppendElement(IPDLProperty{name, value}); } } WriteIPDLParam(aMsg, aActor, bag); } bool IPDLParamTraits::Read(const Message* aMsg, PickleIterator* aIter, IProtocol* aActor, RefPtr* aResult) { nsTArray bag; if (!ReadIPDLParam(aMsg, aIter, aActor, &bag)) { return false; } auto properties = MakeRefPtr(); for (auto& entry : bag) { nsCOMPtr variant = std::move(entry.value()); MOZ_ALWAYS_SUCCEEDS( properties->SetProperty(std::move(entry.name()), variant)); } *aResult = std::move(properties); return true; } } // namespace mozilla::ipc