1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=78:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is SpiderMonkey string object code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * the Mozilla Foundation.
21 : * Portions created by the Initial Developer are Copyright (C) 2011
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #ifndef Xdr_h___
41 : #define Xdr_h___
42 :
43 : #include "jsapi.h"
44 : #include "jsprvtd.h"
45 : #include "jsnum.h"
46 :
47 : namespace js {
48 :
49 : /*
50 : * Bytecode version number. Increment the subtrahend whenever JS bytecode
51 : * changes incompatibly.
52 : *
53 : * This version number is XDR'd near the front of xdr bytecode and
54 : * aborts deserialization if there is a mismatch between the current
55 : * and saved versions. If deserialization fails, the data should be
56 : * invalidated if possible.
57 : */
58 : static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 113);
59 :
60 : class XDRBuffer {
61 : public:
62 4780 : XDRBuffer(JSContext *cx)
63 4780 : : context(cx), base(NULL), cursor(NULL), limit(NULL) { }
64 :
65 25523 : JSContext *cx() const {
66 25523 : return context;
67 : }
68 :
69 2390 : void *getData(uint32_t *lengthp) const {
70 : JS_ASSERT(size_t(cursor - base) <= size_t(UINT32_MAX));
71 2390 : *lengthp = uint32_t(cursor - base);
72 2390 : return base;
73 : }
74 :
75 2411 : void setData(const void *data, uint32_t length) {
76 2411 : base = static_cast<uint8_t *>(const_cast<void *>(data));
77 2411 : cursor = base;
78 2411 : limit = base + length;
79 2411 : }
80 :
81 71531 : const uint8_t *read(size_t n) {
82 71531 : JS_ASSERT(n <= size_t(limit - cursor));
83 71531 : uint8_t *ptr = cursor;
84 71531 : cursor += n;
85 71531 : return ptr;
86 : }
87 :
88 2496 : const char *readCString() {
89 2496 : char *ptr = reinterpret_cast<char *>(cursor);
90 2496 : cursor = reinterpret_cast<uint8_t *>(strchr(ptr, '\0')) + 1;
91 2496 : JS_ASSERT(base < cursor);
92 2496 : JS_ASSERT(cursor <= limit);
93 2496 : return ptr;
94 : }
95 :
96 74027 : uint8_t *write(size_t n) {
97 74027 : if (n > size_t(limit - cursor)) {
98 2390 : if (!grow(n))
99 0 : return NULL;
100 : }
101 74027 : uint8_t *ptr = cursor;
102 74027 : cursor += n;
103 74027 : return ptr;
104 : }
105 :
106 2390 : static bool isUint32Overflow(size_t n) {
107 2390 : return size_t(-1) > size_t(UINT32_MAX) && n > size_t(UINT32_MAX);
108 : }
109 :
110 : void freeBuffer();
111 :
112 : private:
113 : bool grow(size_t n);
114 :
115 : JSContext *const context;
116 : uint8_t *base;
117 : uint8_t *cursor;
118 : uint8_t *limit;
119 : };
120 :
121 : /* We use little-endian byteorder for all encoded data */
122 :
123 : #if defined IS_LITTLE_ENDIAN
124 :
125 : inline uint32_t
126 117336 : NormalizeByteOrder32(uint32_t x)
127 : {
128 117336 : return x;
129 : }
130 :
131 : inline uint16_t
132 0 : NormalizeByteOrder16(uint16_t x)
133 : {
134 0 : return x;
135 : }
136 :
137 : #elif defined IS_BIG_ENDIAN
138 :
139 : inline uint32_t
140 : NormalizeByteOrder32(uint32_t x)
141 : {
142 : return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
143 : }
144 :
145 : inline uint16_t
146 : NormalizeByteOrder16(uint16_t x)
147 : {
148 : return (x >> 8) | (x << 8);
149 : }
150 :
151 : #else
152 : #error "unknown byte order"
153 : #endif
154 :
155 : template <XDRMode mode>
156 : class XDRState {
157 : public:
158 : XDRBuffer buf;
159 :
160 : protected:
161 : JSPrincipals *principals;
162 : JSPrincipals *originPrincipals;
163 :
164 4780 : XDRState(JSContext *cx)
165 4780 : : buf(cx), principals(NULL), originPrincipals(NULL) {
166 4780 : }
167 :
168 : public:
169 25523 : JSContext *cx() const {
170 25523 : return buf.cx();
171 : }
172 :
173 0 : bool codeUint8(uint8_t *n) {
174 : if (mode == XDR_ENCODE) {
175 0 : uint8_t *ptr = buf.write(sizeof *n);
176 0 : if (!ptr)
177 0 : return false;
178 0 : *ptr = *n;
179 : } else {
180 0 : *n = *buf.read(sizeof *n);
181 : }
182 0 : return true;
183 : }
184 :
185 0 : bool codeUint16(uint16_t *n) {
186 : uint16_t tmp;
187 : if (mode == XDR_ENCODE) {
188 0 : uint8_t *ptr = buf.write(sizeof tmp);
189 0 : if (!ptr)
190 0 : return false;
191 0 : tmp = NormalizeByteOrder16(*n);
192 0 : memcpy(ptr, &tmp, sizeof tmp);
193 : } else {
194 0 : memcpy(&tmp, buf.read(sizeof tmp), sizeof tmp);
195 0 : *n = NormalizeByteOrder16(tmp);
196 : }
197 0 : return true;
198 : }
199 :
200 117336 : bool codeUint32(uint32_t *n) {
201 : uint32_t tmp;
202 : if (mode == XDR_ENCODE) {
203 58668 : uint8_t *ptr = buf.write(sizeof tmp);
204 58668 : if (!ptr)
205 0 : return false;
206 58668 : tmp = NormalizeByteOrder32(*n);
207 58668 : memcpy(ptr, &tmp, sizeof tmp);
208 : } else {
209 58668 : memcpy(&tmp, buf.read(sizeof tmp), sizeof tmp);
210 58668 : *n = NormalizeByteOrder32(tmp);
211 : }
212 117336 : return true;
213 : }
214 :
215 0 : bool codeDouble(double *dp) {
216 : jsdpun tmp;
217 : if (mode == XDR_ENCODE) {
218 0 : uint8_t *ptr = buf.write(sizeof tmp);
219 0 : if (!ptr)
220 0 : return false;
221 0 : tmp.d = *dp;
222 0 : tmp.s.lo = NormalizeByteOrder32(tmp.s.lo);
223 0 : tmp.s.hi = NormalizeByteOrder32(tmp.s.hi);
224 0 : memcpy(ptr, &tmp.s.lo, sizeof tmp.s.lo);
225 0 : memcpy(ptr + sizeof tmp.s.lo, &tmp.s.hi, sizeof tmp.s.hi);
226 : } else {
227 0 : const uint8_t *ptr = buf.read(sizeof tmp);
228 0 : memcpy(&tmp.s.lo, ptr, sizeof tmp.s.lo);
229 0 : memcpy(&tmp.s.hi, ptr + sizeof tmp.s.lo, sizeof tmp.s.hi);
230 0 : tmp.s.lo = NormalizeByteOrder32(tmp.s.lo);
231 0 : tmp.s.hi = NormalizeByteOrder32(tmp.s.hi);
232 0 : *dp = tmp.d;
233 : }
234 0 : return true;
235 : }
236 :
237 9984 : bool codeBytes(void *bytes, size_t len) {
238 : if (mode == XDR_ENCODE) {
239 4992 : uint8_t *ptr = buf.write(len);
240 4992 : if (!ptr)
241 0 : return false;
242 4992 : memcpy(ptr, bytes, len);
243 : } else {
244 4992 : memcpy(bytes, buf.read(len), len);
245 : }
246 9984 : return true;
247 : }
248 :
249 : /*
250 : * During encoding the string is written into the buffer together with its
251 : * terminating '\0'. During decoding the method returns a pointer into the
252 : * decoding buffer and the caller must copy the string if it will outlive
253 : * the decoding buffer.
254 : */
255 4992 : bool codeCString(const char **sp) {
256 : if (mode == XDR_ENCODE) {
257 2496 : size_t n = strlen(*sp) + 1;
258 2496 : uint8_t *ptr = buf.write(n);
259 2496 : if (!ptr)
260 0 : return false;
261 2496 : memcpy(ptr, *sp, n);
262 : } else {
263 2496 : *sp = buf.readCString();
264 : }
265 4992 : return true;
266 : }
267 :
268 7871 : bool codeChars(jschar *chars, size_t nchars);
269 7871 : bool codeString(JSString **strp);
270 :
271 12 : bool codeFunction(JSObject **objp);
272 30 : bool codeScript(JSScript **scriptp);
273 :
274 2496 : void initScriptPrincipals(JSScript *script) {
275 0 : JS_ASSERT(mode == XDR_DECODE);
276 :
277 : /* The origin principals must be normalized at this point. */
278 2496 : JS_ASSERT_IF(principals, originPrincipals);
279 2496 : JS_ASSERT(!script->principals);
280 2496 : JS_ASSERT(!script->originPrincipals);
281 2496 : if (principals) {
282 17 : script->principals = principals;
283 17 : JS_HoldPrincipals(principals);
284 : }
285 2496 : if (originPrincipals) {
286 22 : script->originPrincipals = originPrincipals;
287 22 : JS_HoldPrincipals(originPrincipals);
288 : }
289 2496 : }
290 : };
291 :
292 : class XDREncoder : public XDRState<XDR_ENCODE> {
293 : public:
294 2390 : XDREncoder(JSContext *cx)
295 2390 : : XDRState<XDR_ENCODE>(cx) {
296 2390 : }
297 :
298 2390 : ~XDREncoder() {
299 2390 : buf.freeBuffer();
300 2390 : }
301 :
302 2369 : const void *getData(uint32_t *lengthp) const {
303 2369 : return buf.getData(lengthp);
304 : }
305 :
306 21 : void *forgetData(uint32_t *lengthp) {
307 21 : void *data = buf.getData(lengthp);
308 21 : buf.setData(NULL, 0);
309 21 : return data;
310 : }
311 : };
312 :
313 : class XDRDecoder : public XDRState<XDR_DECODE> {
314 : public:
315 : XDRDecoder(JSContext *cx, const void *data, uint32_t length,
316 : JSPrincipals *principals, JSPrincipals *originPrincipals);
317 :
318 : };
319 :
320 : } /* namespace js */
321 :
322 : #endif /* Xdr_h___ */
|