Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/base/MozQueryInterface.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "ChromeUtils.h"
8
#include "MozQueryInterface.h"
9
10
#include <string.h>
11
12
#include "jsapi.h"
13
14
#include "xpcpublic.h"
15
#include "xpcjsid.h"
16
17
namespace mozilla {
18
namespace dom {
19
20
constexpr size_t IID_SIZE = sizeof(nsIID);
21
22
static_assert(IID_SIZE == 16,
23
              "Size of nsID struct changed. Please ensure this code is still valid.");
24
25
static int
26
CompareIIDs(const nsIID& aA, const nsIID &aB)
27
10
{
28
10
  return memcmp((void*)&aA.m0, (void*)&aB.m0, IID_SIZE);
29
10
}
30
31
/* static */
32
MozQueryInterface*
33
ChromeUtils::GenerateQI(const GlobalObject& aGlobal, const Sequence<OwningStringOrIID>& aInterfaces, ErrorResult& aRv)
34
3
{
35
3
  JSContext* cx = aGlobal.Context();
36
3
  JS::RootedObject xpcIfaces(cx);
37
3
38
3
  nsTArray<nsIID> ifaces;
39
3
40
3
  JS::RootedValue val(cx);
41
4
  for (auto& iface : aInterfaces) {
42
4
    if (iface.IsIID()) {
43
4
      ifaces.AppendElement(*iface.GetAsIID()->GetID());
44
4
      continue;
45
4
    }
46
0
47
0
    // If we have a string value, we need to look up the interface name. The
48
0
    // simplest and most efficient way to do this is to just grab the "Ci"
49
0
    // object from the global scope.
50
0
    if (!xpcIfaces) {
51
0
      JS::RootedObject global(cx, aGlobal.Get());
52
0
      if (!JS_GetProperty(cx, global, "Ci", &val)) {
53
0
        aRv.NoteJSContextException(cx);
54
0
        return nullptr;
55
0
      }
56
0
      if (!val.isObject()) {
57
0
        aRv.Throw(NS_ERROR_UNEXPECTED);
58
0
        return nullptr;
59
0
      }
60
0
      xpcIfaces = &val.toObject();
61
0
    }
62
0
63
0
    auto& name = iface.GetAsString();
64
0
    if (!JS_GetUCProperty(cx, xpcIfaces, name.get(), name.Length(), &val)) {
65
0
      aRv.NoteJSContextException(cx);
66
0
      return nullptr;
67
0
    }
68
0
69
0
    if (val.isNullOrUndefined()) {
70
0
      continue;
71
0
    }
72
0
    if (!val.isObject()) {
73
0
      aRv.Throw(NS_ERROR_INVALID_ARG);
74
0
      return nullptr;
75
0
    }
76
0
77
0
    nsCOMPtr<nsISupports> base = xpc::UnwrapReflectorToISupports(&val.toObject());
78
0
    nsCOMPtr<nsIJSID> iid = do_QueryInterface(base);
79
0
    if (!iid) {
80
0
      aRv.Throw(NS_ERROR_INVALID_ARG);
81
0
      return nullptr;
82
0
    }
83
0
    ifaces.AppendElement(*iid->GetID());
84
0
  }
85
3
86
3
  MOZ_ASSERT(!ifaces.Contains(NS_GET_IID(nsISupports), CompareIIDs));
87
3
  ifaces.AppendElement(NS_GET_IID(nsISupports));
88
3
89
3
  ifaces.Sort(CompareIIDs);
90
3
91
3
  return new MozQueryInterface(std::move(ifaces));
92
3
}
93
94
bool
95
MozQueryInterface::QueriesTo(const nsIID& aIID) const
96
3
{
97
3
  return mInterfaces.ContainsSorted(aIID, CompareIIDs);
98
3
}
99
100
void
101
MozQueryInterface::LegacyCall(JSContext* cx, JS::Handle<JS::Value> thisv,
102
                              nsIJSID* aIID,
103
                              JS::MutableHandle<JS::Value> aResult,
104
                              ErrorResult& aRv) const
105
1
{
106
1
  if (!QueriesTo(*aIID->GetID())) {
107
0
    aRv.Throw(NS_ERROR_NO_INTERFACE);
108
1
  } else {
109
1
    aResult.set(thisv);
110
1
  }
111
1
}
112
113
bool
114
MozQueryInterface::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandle<JSObject*> aReflector)
115
3
{
116
3
  return MozQueryInterface_Binding::Wrap(aCx, this, aGivenProto, aReflector);
117
3
}
118
119
} // namespace dom
120
} // namespace mozilla
121