Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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<nsIVariant*>::Write(MessageWriter* aWriter,
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<nsISupports> value;
MOZ_ALWAYS_SUCCEEDS(aParam->GetAsInterface(&iid, getter_AddRefs(value)));
free(iid);
// We only accept nsIURI and nsIPrincipal interface types, patch welcome.
if (nsCOMPtr<nsIURI> uri = do_QueryInterface(value)) {
variant.data() = uri;
} else if (nsCOMPtr<nsIPrincipal> 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(aWriter, aActor, variant);
}
bool IPDLParamTraits<nsIVariant*>::Read(MessageReader* aReader,
IProtocol* aActor,
RefPtr<nsIVariant>* aResult) {
IDPLVariant value;
if (!ReadIPDLParam(aReader, aActor, &value)) {
return false;
}
auto variant = MakeRefPtr<nsVariant>();
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<nsIPropertyBag2*>::Write(MessageWriter* aWriter,
IProtocol* aActor,
nsIPropertyBag2* aParam) {
// We send a nsIPropertyBag as an array of IPDLProperty
nsTArray<IPDLProperty> bag;
nsCOMPtr<nsISimpleEnumerator> enumerator;
if (aParam &&
NS_SUCCEEDED(aParam->GetEnumerator(getter_AddRefs(enumerator)))) {
for (auto& property : SimpleEnumerator<nsIProperty>(enumerator)) {
nsString name;
nsCOMPtr<nsIVariant> value;
MOZ_ALWAYS_SUCCEEDS(property->GetName(name));
MOZ_ALWAYS_SUCCEEDS(property->GetValue(getter_AddRefs(value)));
bag.AppendElement(IPDLProperty{name, value});
}
}
WriteIPDLParam(aWriter, aActor, bag);
}
bool IPDLParamTraits<nsIPropertyBag2*>::Read(MessageReader* aReader,
IProtocol* aActor,
RefPtr<nsIPropertyBag2>* aResult) {
nsTArray<IPDLProperty> bag;
if (!ReadIPDLParam(aReader, aActor, &bag)) {
return false;
}
auto properties = MakeRefPtr<nsHashPropertyBag>();
for (auto& entry : bag) {
nsCOMPtr<nsIVariant> variant = std::move(entry.value());
MOZ_ALWAYS_SUCCEEDS(
properties->SetProperty(std::move(entry.name()), variant));
}
*aResult = std::move(properties);
return true;
}
} // namespace mozilla::ipc