Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef ScriptPreloader_inl_h
7 : #define ScriptPreloader_inl_h
8 :
9 : #include "mozilla/Attributes.h"
10 : #include "mozilla/Assertions.h"
11 : #include "mozilla/CheckedInt.h"
12 : #include "mozilla/EnumSet.h"
13 : #include "mozilla/Range.h"
14 : #include "mozilla/Result.h"
15 : #include "mozilla/Unused.h"
16 : #include "mozilla/dom/ScriptSettings.h"
17 : #include "nsString.h"
18 : #include "nsTArray.h"
19 :
20 : #include <prio.h>
21 :
22 : namespace mozilla {
23 :
24 : // A specialization of GenericErrorResult which auto-converts to a nsresult.
25 : // This should be removed when bug 1366511 is fixed.
26 : template <>
27 : class MOZ_MUST_USE_TYPE GenericErrorResult<nsresult>
28 : {
29 : nsresult mErrorValue;
30 :
31 : template<typename V, typename E2> friend class Result;
32 :
33 : public:
34 0 : explicit GenericErrorResult(nsresult aErrorValue) : mErrorValue(aErrorValue) {}
35 :
36 0 : operator nsresult() { return mErrorValue; }
37 : };
38 :
39 : namespace loader {
40 :
41 : using mozilla::dom::AutoJSAPI;
42 :
43 5 : struct MOZ_RAII AutoSafeJSAPI : public AutoJSAPI
44 : {
45 5 : AutoSafeJSAPI() { Init(); }
46 : };
47 :
48 : static inline Result<Ok, nsresult>
49 105 : WrapNSResult(PRStatus aRv)
50 : {
51 105 : if (aRv != PR_SUCCESS) {
52 0 : return Err(NS_ERROR_FAILURE);
53 : }
54 105 : return Ok();
55 : }
56 :
57 : static inline Result<Ok, nsresult>
58 115 : WrapNSResult(nsresult aRv)
59 : {
60 115 : if (NS_FAILED(aRv)) {
61 0 : return Err(aRv);
62 : }
63 115 : return Ok();
64 : }
65 :
66 : #define NS_TRY(expr) MOZ_TRY(WrapNSResult(expr))
67 :
68 :
69 0 : class OutputBuffer
70 : {
71 : public:
72 0 : OutputBuffer()
73 0 : {}
74 :
75 : uint8_t*
76 0 : write(size_t size)
77 : {
78 0 : auto buf = data.AppendElements(size);
79 0 : cursor_ += size;
80 0 : return buf;
81 : }
82 :
83 : void
84 0 : codeUint8(const uint8_t& val)
85 : {
86 0 : *write(sizeof val) = val;
87 0 : }
88 :
89 : template<typename T>
90 : void
91 0 : codeUint8(const EnumSet<T>& val)
92 : {
93 : // EnumSets are always represented as uint32_t values, so we need to
94 : // assert that the value actually fits in a uint8 before writing it.
95 0 : uint32_t value = val.serialize();
96 0 : codeUint8(CheckedUint8(value).value());
97 0 : }
98 :
99 : void
100 0 : codeUint16(const uint16_t& val)
101 : {
102 0 : LittleEndian::writeUint16(write(sizeof val), val);
103 0 : }
104 :
105 : void
106 0 : codeUint32(const uint32_t& val)
107 : {
108 0 : LittleEndian::writeUint32(write(sizeof val), val);
109 0 : }
110 :
111 : void
112 0 : codeString(const nsCString& str)
113 : {
114 0 : auto len = CheckedUint16(str.Length()).value();
115 :
116 0 : codeUint16(len);
117 0 : memcpy(write(len), str.BeginReading(), len);
118 0 : }
119 :
120 0 : size_t cursor() const { return cursor_; }
121 :
122 :
123 0 : uint8_t* Get() { return data.Elements(); }
124 :
125 : const uint8_t* Get() const { return data.Elements(); }
126 :
127 : private:
128 : nsTArray<uint8_t> data;
129 : size_t cursor_ = 0;
130 : };
131 :
132 : class InputBuffer
133 : {
134 : public:
135 4 : explicit InputBuffer(const Range<uint8_t>& buffer)
136 4 : : data(buffer)
137 4 : {}
138 :
139 : const uint8_t*
140 1428 : read(size_t size)
141 : {
142 1428 : MOZ_ASSERT(checkCapacity(size));
143 :
144 1428 : auto buf = &data[cursor_];
145 1428 : cursor_ += size;
146 1428 : return buf;
147 : }
148 :
149 : bool
150 204 : codeUint8(uint8_t& val)
151 : {
152 204 : if (checkCapacity(sizeof val)) {
153 204 : val = *read(sizeof val);
154 : }
155 204 : return !error_;
156 : }
157 :
158 : template<typename T>
159 : bool
160 204 : codeUint8(EnumSet<T>& val)
161 : {
162 : uint8_t value;
163 204 : if (codeUint8(value)) {
164 204 : val.deserialize(value);
165 : }
166 204 : return !error_;
167 : }
168 :
169 : bool
170 408 : codeUint16(uint16_t& val)
171 : {
172 408 : if (checkCapacity(sizeof val)) {
173 408 : val = LittleEndian::readUint16(read(sizeof val));
174 : }
175 408 : return !error_;
176 : }
177 :
178 : bool
179 408 : codeUint32(uint32_t& val)
180 : {
181 408 : if (checkCapacity(sizeof val)) {
182 408 : val = LittleEndian::readUint32(read(sizeof val));
183 : }
184 408 : return !error_;
185 : }
186 :
187 : bool
188 408 : codeString(nsCString& str)
189 : {
190 : uint16_t len;
191 408 : if (codeUint16(len)) {
192 408 : if (checkCapacity(len)) {
193 408 : str.SetLength(len);
194 408 : memcpy(str.BeginWriting(), read(len), len);
195 : }
196 : }
197 408 : return !error_;
198 : }
199 :
200 4 : bool error() { return error_; }
201 :
202 208 : bool finished() { return error_ || !remainingCapacity(); }
203 :
204 3064 : size_t remainingCapacity() { return data.length() - cursor_; }
205 :
206 : size_t cursor() const { return cursor_; }
207 :
208 : const uint8_t* Get() const { return data.begin().get(); }
209 :
210 : private:
211 : bool
212 2856 : checkCapacity(size_t size)
213 : {
214 2856 : if (size > remainingCapacity()) {
215 0 : error_ = true;
216 : }
217 2856 : return !error_;
218 : }
219 :
220 : bool error_ = false;
221 :
222 : public:
223 : const Range<uint8_t>& data;
224 : size_t cursor_ = 0;
225 : };
226 :
227 :
228 : template <typename T> struct Matcher;
229 :
230 : // Wraps the iterator for a nsTHashTable so that it may be used as a range
231 : // iterator. Each iterator result acts as a smart pointer to the hash element,
232 : // and has a Remove() method which will remove the element from the hash.
233 : //
234 : // It also accepts an optional Matcher instance against which to filter the
235 : // elements which should be iterated over.
236 : //
237 : // Example:
238 : //
239 : // for (auto& elem : HashElemIter<HashType>(hash)) {
240 : // if (elem->IsDead()) {
241 : // elem.Remove();
242 : // }
243 : // }
244 : template <typename T>
245 3 : class HashElemIter
246 : {
247 : using Iterator = typename T::Iterator;
248 : using ElemType = typename T::UserDataType;
249 :
250 : T& hash_;
251 : Matcher<ElemType>* matcher_;
252 : Maybe<Iterator> iter_;
253 :
254 : public:
255 3 : explicit HashElemIter(T& hash, Matcher<ElemType>* matcher = nullptr)
256 3 : : hash_(hash), matcher_(matcher)
257 : {
258 3 : iter_.emplace(Move(hash.Iter()));
259 3 : }
260 :
261 : class Elem
262 : {
263 : friend class HashElemIter<T>;
264 :
265 : HashElemIter<T>& iter_;
266 : bool done_;
267 :
268 6 : Elem(HashElemIter& iter, bool done)
269 6 : : iter_(iter), done_(done)
270 : {
271 6 : skipNonMatching();
272 6 : }
273 :
274 1125 : Iterator& iter() { return iter_.iter_.ref(); }
275 :
276 293 : void skipNonMatching()
277 : {
278 293 : if (iter_.matcher_) {
279 44 : while (!done_ && !iter_.matcher_->Matches(get())) {
280 0 : iter().Next();
281 0 : done_ = iter().Done();
282 : }
283 : }
284 293 : }
285 :
286 : public:
287 287 : Elem& operator*() { return *this; }
288 :
289 557 : ElemType get()
290 : {
291 557 : if (done_) {
292 6 : return nullptr;
293 : }
294 551 : return iter().Data();
295 : }
296 :
297 509 : ElemType operator->() { return get(); }
298 :
299 0 : operator ElemType() { return get(); }
300 :
301 0 : void Remove() { iter().Remove(); }
302 :
303 287 : Elem& operator++()
304 : {
305 287 : MOZ_ASSERT(!done_);
306 :
307 287 : iter().Next();
308 287 : done_ = iter().Done();
309 :
310 287 : skipNonMatching();
311 287 : return *this;
312 : }
313 :
314 290 : bool operator!=(Elem& other)
315 : {
316 290 : return done_ != other.done_ || this->get() != other.get();
317 : }
318 : };
319 :
320 3 : Elem begin() { return Elem(*this, iter_->Done()); }
321 :
322 3 : Elem end() { return Elem(*this, true); }
323 : };
324 :
325 : template <typename T>
326 3 : HashElemIter<T> IterHash(T& hash, Matcher<typename T::UserDataType>* matcher = nullptr)
327 : {
328 3 : return HashElemIter<T>(hash, matcher);
329 : }
330 :
331 : template <typename T, typename F>
332 : bool
333 : Find(T&& iter, F&& match)
334 : {
335 : for (auto& elem : iter) {
336 : if (match(elem)) {
337 : return true;
338 : }
339 : }
340 : return false;
341 : }
342 :
343 : }; // namespace loader
344 : }; // namespace mozilla
345 :
346 : #endif // ScriptPreloader_inl_h
|