xpctest_params.cpp (15586B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "xpctest_private.h" 6 #include "xpctest_interfaces.h" 7 #include "mozilla/Casting.h" 8 #include "js/Value.h" 9 10 #include "nsCOMPtr.h" 11 #include "nsComponentManagerUtils.h" 12 #include "nsIURI.h" 13 14 using namespace mozilla; 15 16 NS_IMPL_ISUPPORTS(nsXPCTestParams, nsIXPCTestParams) 17 18 #define GENERIC_METHOD_IMPL \ 19 { \ 20 *_retval = *b; \ 21 *b = a; \ 22 return NS_OK; \ 23 } 24 25 #define STRING_METHOD_IMPL \ 26 { \ 27 _retval.Assign(b); \ 28 b.Assign(a); \ 29 return NS_OK; \ 30 } 31 32 #define SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP) \ 33 { \ 34 _retval = std::move(b); \ 35 b = a.Clone(); \ 36 for (uint32_t i = 0; i < b.Length(); ++i) TAKE_OWNERSHIP(b[i]); \ 37 return NS_OK; \ 38 } 39 40 #define TAKE_OWNERSHIP_NOOP(val) \ 41 { \ 42 } 43 #define TAKE_OWNERSHIP_INTERFACE(val) \ 44 { \ 45 static_cast<nsISupports*>(val)->AddRef(); \ 46 } 47 #define TAKE_OWNERSHIP_STRING(val) \ 48 { \ 49 nsDependentCString vprime(val); \ 50 val = ToNewCString(vprime); \ 51 } 52 #define TAKE_OWNERSHIP_WSTRING(val) \ 53 { \ 54 nsDependentString vprime(val); \ 55 val = ToNewUnicode(vprime); \ 56 } 57 58 // Macro for our buffer-oriented types: 59 // 'type' is the type of element that the buffer contains. 60 // 'padding' is an offset added to length, allowing us to handle 61 // null-terminated strings. 62 // 'TAKE_OWNERSHIP' is one of the macros above. 63 #define BUFFER_METHOD_IMPL(type, padding, TAKE_OWNERSHIP) \ 64 { \ 65 uint32_t elemSize = sizeof(type); \ 66 \ 67 /* Copy b into rv. */ \ 68 *rvLength = *bLength; \ 69 *rv = static_cast<type*>(moz_xmalloc(elemSize * (*bLength + padding))); \ 70 memcpy(*rv, *b, elemSize*(*bLength + padding)); \ 71 \ 72 /* Copy a into b. */ \ 73 *bLength = aLength; \ 74 free(*b); \ 75 *b = static_cast<type*>(moz_xmalloc(elemSize * (aLength + padding))); \ 76 memcpy(*b, a, elemSize*(aLength + padding)); \ 77 \ 78 /* We need to take ownership of the data we got from a, \ 79 since the caller owns it. */ \ 80 for (unsigned i = 0; i < *bLength + padding; ++i) TAKE_OWNERSHIP((*b)[i]); \ 81 \ 82 return NS_OK; \ 83 } 84 85 NS_IMETHODIMP nsXPCTestParams::TestBoolean(bool a, bool* b, bool* _retval) { 86 GENERIC_METHOD_IMPL; 87 } 88 89 NS_IMETHODIMP nsXPCTestParams::TestOctet(uint8_t a, uint8_t* b, 90 uint8_t* _retval) { 91 GENERIC_METHOD_IMPL; 92 } 93 94 NS_IMETHODIMP nsXPCTestParams::TestShort(int16_t a, int16_t* b, 95 int16_t* _retval) { 96 GENERIC_METHOD_IMPL; 97 } 98 99 NS_IMETHODIMP nsXPCTestParams::TestLong(int32_t a, int32_t* b, 100 int32_t* _retval) { 101 GENERIC_METHOD_IMPL; 102 } 103 104 NS_IMETHODIMP nsXPCTestParams::TestLongLong(int64_t a, int64_t* b, 105 int64_t* _retval) { 106 GENERIC_METHOD_IMPL; 107 } 108 109 NS_IMETHODIMP nsXPCTestParams::TestUnsignedShort(uint16_t a, uint16_t* b, 110 uint16_t* _retval) { 111 GENERIC_METHOD_IMPL; 112 } 113 114 NS_IMETHODIMP nsXPCTestParams::TestUnsignedLong(uint32_t a, uint32_t* b, 115 uint32_t* _retval) { 116 GENERIC_METHOD_IMPL; 117 } 118 119 NS_IMETHODIMP nsXPCTestParams::TestUnsignedLongLong(uint64_t a, uint64_t* b, 120 uint64_t* _retval) { 121 GENERIC_METHOD_IMPL; 122 } 123 124 NS_IMETHODIMP nsXPCTestParams::TestFloat(float a, float* b, float* _retval) { 125 GENERIC_METHOD_IMPL; 126 } 127 128 NS_IMETHODIMP nsXPCTestParams::TestDouble(double a, float* b, double* _retval) { 129 GENERIC_METHOD_IMPL; 130 } 131 132 NS_IMETHODIMP nsXPCTestParams::TestChar(char a, char* b, char* _retval) { 133 GENERIC_METHOD_IMPL; 134 } 135 136 NS_IMETHODIMP nsXPCTestParams::TestString(const char* a, char** b, 137 char** _retval) { 138 nsDependentCString aprime(a); 139 nsDependentCString bprime(*b); 140 *_retval = ToNewCString(bprime); 141 *b = ToNewCString(aprime); 142 143 // XPCOM ownership rules dictate that overwritten inout params must be 144 // callee-freed. See https://developer.mozilla.org/en/XPIDL 145 free(const_cast<char*>(bprime.get())); 146 147 return NS_OK; 148 } 149 150 NS_IMETHODIMP nsXPCTestParams::TestWchar(char16_t a, char16_t* b, 151 char16_t* _retval) { 152 GENERIC_METHOD_IMPL; 153 } 154 155 NS_IMETHODIMP nsXPCTestParams::TestWstring(const char16_t* a, char16_t** b, 156 char16_t** _retval) { 157 nsDependentString aprime(a); 158 nsDependentString bprime(*b); 159 *_retval = ToNewUnicode(bprime); 160 *b = ToNewUnicode(aprime); 161 162 // XPCOM ownership rules dictate that overwritten inout params must be 163 // callee-freed. See https://developer.mozilla.org/en/XPIDL 164 free((void*)bprime.get()); 165 166 return NS_OK; 167 } 168 169 NS_IMETHODIMP nsXPCTestParams::TestAString(const nsAString& a, nsAString& b, 170 nsAString& _retval) { 171 STRING_METHOD_IMPL; 172 } 173 174 NS_IMETHODIMP nsXPCTestParams::TestAUTF8String(const nsACString& a, 175 nsACString& b, 176 nsACString& _retval) { 177 STRING_METHOD_IMPL; 178 } 179 180 NS_IMETHODIMP nsXPCTestParams::TestACString(const nsACString& a, nsACString& b, 181 nsACString& _retval) { 182 STRING_METHOD_IMPL; 183 } 184 185 NS_IMETHODIMP nsXPCTestParams::TestJsval(JS::Handle<JS::Value> a, 186 JS::MutableHandle<JS::Value> b, 187 JS::MutableHandle<JS::Value> _retval) { 188 _retval.set(b); 189 b.set(a); 190 return NS_OK; 191 } 192 193 NS_IMETHODIMP nsXPCTestParams::TestShortArray(uint32_t aLength, int16_t* a, 194 uint32_t* bLength, int16_t** b, 195 uint32_t* rvLength, 196 int16_t** rv) { 197 BUFFER_METHOD_IMPL(int16_t, 0, TAKE_OWNERSHIP_NOOP); 198 } 199 200 NS_IMETHODIMP nsXPCTestParams::TestDoubleArray(uint32_t aLength, double* a, 201 uint32_t* bLength, double** b, 202 uint32_t* rvLength, 203 double** rv) { 204 BUFFER_METHOD_IMPL(double, 0, TAKE_OWNERSHIP_NOOP); 205 } 206 207 NS_IMETHODIMP nsXPCTestParams::TestByteArrayOptionalLength(uint8_t* a, 208 uint32_t aLength, 209 uint32_t* rv) { 210 *rv = aLength; 211 return NS_OK; 212 } 213 214 NS_IMETHODIMP nsXPCTestParams::TestStringArray(uint32_t aLength, const char** a, 215 uint32_t* bLength, char*** b, 216 uint32_t* rvLength, char*** rv) { 217 BUFFER_METHOD_IMPL(char*, 0, TAKE_OWNERSHIP_STRING); 218 } 219 220 NS_IMETHODIMP nsXPCTestParams::TestWstringArray( 221 uint32_t aLength, const char16_t** a, uint32_t* bLength, char16_t*** b, 222 uint32_t* rvLength, char16_t*** rv) { 223 BUFFER_METHOD_IMPL(char16_t*, 0, TAKE_OWNERSHIP_WSTRING); 224 } 225 226 NS_IMETHODIMP nsXPCTestParams::TestInterfaceArray( 227 uint32_t aLength, nsIXPCTestInterfaceA** a, uint32_t* bLength, 228 nsIXPCTestInterfaceA*** b, uint32_t* rvLength, nsIXPCTestInterfaceA*** rv) { 229 BUFFER_METHOD_IMPL(nsIXPCTestInterfaceA*, 0, TAKE_OWNERSHIP_INTERFACE); 230 } 231 232 NS_IMETHODIMP nsXPCTestParams::TestJsvalArray(uint32_t aLength, JS::Value* a, 233 uint32_t* bLength, JS::Value** b, 234 uint32_t* rvLength, 235 JS::Value** rv) { 236 BUFFER_METHOD_IMPL(JS::Value, 0, TAKE_OWNERSHIP_NOOP); 237 } 238 239 NS_IMETHODIMP nsXPCTestParams::TestSizedString(uint32_t aLength, const char* a, 240 uint32_t* bLength, char** b, 241 uint32_t* rvLength, char** rv) { 242 BUFFER_METHOD_IMPL(char, 1, TAKE_OWNERSHIP_NOOP); 243 } 244 245 NS_IMETHODIMP nsXPCTestParams::TestSizedWstring(uint32_t aLength, 246 const char16_t* a, 247 uint32_t* bLength, char16_t** b, 248 uint32_t* rvLength, 249 char16_t** rv) { 250 BUFFER_METHOD_IMPL(char16_t, 1, TAKE_OWNERSHIP_NOOP); 251 } 252 253 NS_IMETHODIMP nsXPCTestParams::TestInterfaceIs(const nsIID* aIID, void* a, 254 nsIID** bIID, void** b, 255 nsIID** rvIID, void** rv) { 256 // 257 // Getting the buffers and ownership right here can be a little tricky. 258 // 259 260 // The interface pointers are heap-allocated, and b has been AddRef'd 261 // by XPConnect for the duration of the call. If we snatch it away from b 262 // and leave no trace, XPConnect won't Release it. Since we also need to 263 // return an already-AddRef'd pointer in rv, we don't need to do anything 264 // special here. 265 *rv = *b; 266 267 // rvIID is out-only, so nobody allocated an IID buffer for us. Do that now, 268 // and store b's IID in the new buffer. 269 *rvIID = static_cast<nsIID*>(moz_xmalloc(sizeof(nsID))); 270 **rvIID = **bIID; 271 272 // Copy the interface pointer from a to b. Since a is in-only, XPConnect will 273 // release it upon completion of the call. AddRef it for b. 274 *b = a; 275 static_cast<nsISupports*>(*b)->AddRef(); 276 277 // We already had a buffer allocated for b's IID, so we can re-use it. 278 **bIID = *aIID; 279 280 return NS_OK; 281 } 282 283 NS_IMETHODIMP nsXPCTestParams::TestInterfaceIsArray( 284 uint32_t aLength, const nsIID* aIID, void** a, uint32_t* bLength, 285 nsIID** bIID, void*** b, uint32_t* rvLength, nsIID** rvIID, void*** rv) { 286 // Transfer the IIDs. See the comments in TestInterfaceIs (above) for an 287 // explanation of what we're doing. 288 *rvIID = static_cast<nsIID*>(moz_xmalloc(sizeof(nsID))); 289 **rvIID = **bIID; 290 **bIID = *aIID; 291 292 // The macro is agnostic to the actual interface types, so we can re-use code 293 // here. 294 // 295 // Do this second, since the macro returns. 296 BUFFER_METHOD_IMPL(void*, 0, TAKE_OWNERSHIP_INTERFACE); 297 } 298 299 NS_IMETHODIMP nsXPCTestParams::TestOutAString(nsAString& o) { 300 o.AssignLiteral("out"); 301 return NS_OK; 302 } 303 304 NS_IMETHODIMP nsXPCTestParams::TestStringArrayOptionalSize(const char** a, 305 uint32_t length, 306 nsACString& out) { 307 out.Truncate(); 308 for (uint32_t i = 0; i < length; ++i) { 309 out.Append(a[i]); 310 } 311 312 return NS_OK; 313 } 314 315 NS_IMETHODIMP 316 nsXPCTestParams::TestShortSequence(const nsTArray<short>& a, nsTArray<short>& b, 317 nsTArray<short>& _retval) { 318 SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP); 319 } 320 321 NS_IMETHODIMP 322 nsXPCTestParams::TestDoubleSequence(const nsTArray<double>& a, 323 nsTArray<double>& b, 324 nsTArray<double>& _retval) { 325 SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP); 326 } 327 328 NS_IMETHODIMP 329 nsXPCTestParams::TestInterfaceSequence( 330 const nsTArray<RefPtr<nsIXPCTestInterfaceA>>& a, 331 nsTArray<RefPtr<nsIXPCTestInterfaceA>>& b, 332 nsTArray<RefPtr<nsIXPCTestInterfaceA>>& _retval) { 333 SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP); 334 } 335 336 NS_IMETHODIMP 337 nsXPCTestParams::TestAStringSequence(const nsTArray<nsString>& a, 338 nsTArray<nsString>& b, 339 nsTArray<nsString>& _retval) { 340 SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP); 341 } 342 343 NS_IMETHODIMP 344 nsXPCTestParams::TestACStringSequence(const nsTArray<nsCString>& a, 345 nsTArray<nsCString>& b, 346 nsTArray<nsCString>& _retval) { 347 SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP); 348 } 349 350 NS_IMETHODIMP 351 nsXPCTestParams::TestJsvalSequence(const nsTArray<JS::Value>& a, 352 nsTArray<JS::Value>& b, 353 nsTArray<JS::Value>& _retval) { 354 SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_NOOP); 355 } 356 357 NS_IMETHODIMP 358 nsXPCTestParams::TestSequenceSequence(const nsTArray<nsTArray<short>>& a, 359 nsTArray<nsTArray<short>>& b, 360 nsTArray<nsTArray<short>>& _retval) { 361 _retval = std::move(b); 362 for (const auto& element : a) { 363 b.AppendElement(element.Clone()); 364 } 365 return NS_OK; 366 } 367 368 NS_IMETHODIMP 369 nsXPCTestParams::TestInterfaceIsSequence(const nsIID* aIID, 370 const nsTArray<void*>& a, nsIID** bIID, 371 nsTArray<void*>& b, nsIID** rvIID, 372 nsTArray<void*>& _retval) { 373 // Shuffle around our nsIIDs 374 *rvIID = (*bIID)->Clone(); 375 *bIID = aIID->Clone(); 376 377 // Perform the generic sequence shuffle. 378 SEQUENCE_METHOD_IMPL(TAKE_OWNERSHIP_INTERFACE); 379 } 380 381 NS_IMETHODIMP 382 nsXPCTestParams::TestOptionalSequence(const nsTArray<uint8_t>& aInArr, 383 nsTArray<uint8_t>& aReturnArr) { 384 aReturnArr = aInArr.Clone(); 385 return NS_OK; 386 } 387 388 NS_IMETHODIMP 389 nsXPCTestParams::TestOmittedOptionalOut(nsIXPCTestParams* aJSObj, 390 nsIURI** aOut) { 391 MOZ_ASSERT(!(*aOut), "Unexpected value received"); 392 // Call the js component, to check XPConnect won't crash when passing nullptr 393 // as the optional out parameter, and that the out object is built regardless. 394 nsresult rv; 395 // Invoke it directly passing nullptr. 396 rv = aJSObj->TestOmittedOptionalOut(nullptr, nullptr); 397 NS_ENSURE_SUCCESS(rv, rv); 398 // Also invoke it with a ref pointer. 399 nsCOMPtr<nsIURI> someURI; 400 rv = aJSObj->TestOmittedOptionalOut(nullptr, getter_AddRefs(someURI)); 401 NS_ENSURE_SUCCESS(rv, rv); 402 nsAutoCString spec; 403 rv = someURI->GetSpec(spec); 404 if (!spec.EqualsLiteral("http://example.com/")) { 405 return NS_ERROR_UNEXPECTED; 406 } 407 someURI.forget(aOut); 408 return NS_OK; 409 } 410 411 NS_IMETHODIMP 412 nsXPCTestParams::GetTestNaN(double* aResult) { 413 *aResult = 414 BitwiseCast<double>((uint64_t(JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT) + 1); 415 return NS_OK; 416 }