1 : /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Web Workers.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2011
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * William Chen <wchen@mozilla.com> (Original Author)
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * 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 : #include "File.h"
41 :
42 : #include "nsIDOMFile.h"
43 :
44 : #include "jsapi.h"
45 : #include "jsatom.h"
46 : #include "jsfriendapi.h"
47 : #include "nsCOMPtr.h"
48 : #include "nsJSUtils.h"
49 : #include "nsStringGlue.h"
50 :
51 : #include "Exceptions.h"
52 : #include "WorkerInlines.h"
53 : #include "WorkerPrivate.h"
54 :
55 : #define PROPERTY_FLAGS \
56 : (JSPROP_ENUMERATE | JSPROP_SHARED)
57 :
58 : USING_WORKERS_NAMESPACE
59 :
60 : using mozilla::dom::workers::exceptions::ThrowFileExceptionForCode;
61 :
62 : namespace {
63 :
64 : class Blob
65 : {
66 : // Blob should never be instantiated.
67 : Blob();
68 : ~Blob();
69 :
70 : static JSClass sClass;
71 : static JSPropertySpec sProperties[];
72 : static JSFunctionSpec sFunctions[];
73 :
74 : public:
75 : static JSObject*
76 0 : InitClass(JSContext* aCx, JSObject* aObj)
77 : {
78 : return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0, sProperties,
79 0 : sFunctions, NULL, NULL);
80 : }
81 :
82 : static JSObject*
83 0 : Create(JSContext* aCx, nsIDOMBlob* aBlob)
84 : {
85 0 : JS_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aBlob), aBlob));
86 :
87 0 : JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
88 0 : if (obj) {
89 0 : JS_SetPrivate(obj, aBlob);
90 0 : NS_ADDREF(aBlob);
91 : }
92 0 : return obj;
93 : }
94 :
95 : static nsIDOMBlob*
96 : GetPrivate(JSObject* aObj);
97 :
98 : private:
99 : static nsIDOMBlob*
100 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
101 : {
102 0 : nsIDOMBlob* blob = GetPrivate(aObj);
103 0 : if (blob) {
104 0 : return blob;
105 : }
106 :
107 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
108 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
109 0 : JS_GetClass(aObj)->name);
110 0 : return NULL;
111 : }
112 :
113 : static JSBool
114 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
115 : {
116 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
117 0 : sClass.name);
118 0 : return false;
119 : }
120 :
121 : static void
122 0 : Finalize(JSContext* aCx, JSObject* aObj)
123 : {
124 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
125 :
126 0 : nsIDOMBlob* blob = GetPrivate(aObj);
127 0 : NS_IF_RELEASE(blob);
128 0 : }
129 :
130 : static JSBool
131 0 : GetSize(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
132 : {
133 0 : nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "size");
134 0 : if (!blob) {
135 0 : return false;
136 : }
137 :
138 : PRUint64 size;
139 0 : if (NS_FAILED(blob->GetSize(&size))) {
140 0 : ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
141 : }
142 :
143 0 : if (!JS_NewNumberValue(aCx, double(size), aVp)) {
144 0 : return false;
145 : }
146 :
147 0 : return true;
148 : }
149 :
150 : static JSBool
151 0 : GetType(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
152 : {
153 0 : nsIDOMBlob* blob = GetInstancePrivate(aCx, aObj, "type");
154 0 : if (!blob) {
155 0 : return false;
156 : }
157 :
158 0 : nsString type;
159 0 : if (NS_FAILED(blob->GetType(type))) {
160 0 : ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
161 : }
162 :
163 0 : JSString* jsType = JS_NewUCStringCopyN(aCx, type.get(), type.Length());
164 0 : if (!jsType) {
165 0 : return false;
166 : }
167 :
168 0 : *aVp = STRING_TO_JSVAL(jsType);
169 :
170 0 : return true;
171 : }
172 :
173 : static JSBool
174 0 : Slice(JSContext* aCx, unsigned aArgc, jsval* aVp)
175 : {
176 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
177 0 : if (!obj) {
178 0 : return false;
179 : }
180 :
181 0 : nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "slice");
182 0 : if (!blob) {
183 0 : return false;
184 : }
185 :
186 0 : double start = 0, end = 0;
187 0 : JSString* jsContentType = JS_GetEmptyString(JS_GetRuntime(aCx));
188 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "/IIS", &start,
189 0 : &end, &jsContentType)) {
190 0 : return false;
191 : }
192 :
193 0 : nsDependentJSString contentType;
194 0 : if (!contentType.init(aCx, jsContentType)) {
195 0 : return false;
196 : }
197 :
198 0 : PRUint8 optionalArgc = aArgc;
199 0 : nsCOMPtr<nsIDOMBlob> rtnBlob;
200 0 : if (NS_FAILED(blob->Slice(static_cast<PRUint64>(start),
201 : static_cast<PRUint64>(end),
202 : contentType, optionalArgc,
203 : getter_AddRefs(rtnBlob)))) {
204 0 : ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
205 0 : return false;
206 : }
207 :
208 0 : JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
209 0 : if (!rtnObj) {
210 0 : return false;
211 : }
212 :
213 0 : JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(rtnObj));
214 0 : return true;
215 : }
216 : };
217 :
218 : JSClass Blob::sClass = {
219 : "Blob",
220 : JSCLASS_HAS_PRIVATE,
221 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
222 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
223 : JSCLASS_NO_OPTIONAL_MEMBERS
224 : };
225 :
226 : JSPropertySpec Blob::sProperties[] = {
227 : { "size", 0, PROPERTY_FLAGS, GetSize, js_GetterOnlyPropertyStub },
228 : { "type", 0, PROPERTY_FLAGS, GetType, js_GetterOnlyPropertyStub },
229 : { 0, 0, 0, NULL, NULL }
230 : };
231 :
232 : JSFunctionSpec Blob::sFunctions[] = {
233 : JS_FN("slice", Slice, 1, JSPROP_ENUMERATE),
234 : JS_FS_END
235 : };
236 :
237 : class File : public Blob
238 : {
239 : // File should never be instantiated.
240 : File();
241 : ~File();
242 :
243 : static JSClass sClass;
244 : static JSPropertySpec sProperties[];
245 :
246 : public:
247 : static JSObject*
248 0 : InitClass(JSContext* aCx, JSObject* aObj, JSObject* aParentProto)
249 : {
250 : return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
251 0 : sProperties, NULL, NULL, NULL);
252 : }
253 :
254 : static JSObject*
255 0 : Create(JSContext* aCx, nsIDOMFile* aFile)
256 : {
257 0 : JS_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aFile), aFile));
258 :
259 0 : JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
260 0 : if (obj) {
261 0 : JS_SetPrivate(obj, aFile);
262 0 : NS_ADDREF(aFile);
263 : }
264 0 : return obj;
265 : }
266 :
267 : static nsIDOMFile*
268 0 : GetPrivate(JSObject* aObj)
269 : {
270 0 : if (aObj) {
271 0 : JSClass* classPtr = JS_GetClass(aObj);
272 0 : if (classPtr == &sClass) {
273 0 : nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
274 0 : nsCOMPtr<nsIDOMFile> file = do_QueryInterface(priv);
275 0 : JS_ASSERT_IF(priv, file);
276 0 : return file;
277 : }
278 : }
279 0 : return NULL;
280 : }
281 :
282 : static JSClass*
283 0 : Class()
284 : {
285 0 : return &sClass;
286 : }
287 :
288 : private:
289 : static nsIDOMFile*
290 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
291 : {
292 0 : nsIDOMFile* file = GetPrivate(aObj);
293 0 : if (file) {
294 0 : return file;
295 : }
296 :
297 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
298 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
299 0 : JS_GetClass(aObj)->name);
300 0 : return NULL;
301 : }
302 :
303 : static JSBool
304 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
305 : {
306 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_WRONG_CONSTRUCTOR,
307 0 : sClass.name);
308 0 : return false;
309 : }
310 :
311 : static void
312 0 : Finalize(JSContext* aCx, JSObject* aObj)
313 : {
314 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
315 :
316 0 : nsIDOMFile* file = GetPrivate(aObj);
317 0 : NS_IF_RELEASE(file);
318 0 : }
319 :
320 : static JSBool
321 0 : GetMozFullPath(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
322 : {
323 0 : nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "mozFullPath");
324 0 : if (!file) {
325 0 : return false;
326 : }
327 :
328 0 : nsString fullPath;
329 :
330 0 : if (GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal() &&
331 0 : NS_FAILED(file->GetMozFullPathInternal(fullPath))) {
332 0 : ThrowFileExceptionForCode(aCx, FILE_NOT_READABLE_ERR);
333 0 : return false;
334 : }
335 :
336 : JSString* jsFullPath = JS_NewUCStringCopyN(aCx, fullPath.get(),
337 0 : fullPath.Length());
338 0 : if (!jsFullPath) {
339 0 : return false;
340 : }
341 :
342 0 : *aVp = STRING_TO_JSVAL(jsFullPath);
343 0 : return true;
344 : }
345 :
346 : static JSBool
347 0 : GetName(JSContext* aCx, JSObject* aObj, jsid aIdval, jsval* aVp)
348 : {
349 0 : nsIDOMFile* file = GetInstancePrivate(aCx, aObj, "name");
350 0 : if (!file) {
351 0 : return false;
352 : }
353 :
354 0 : nsString name;
355 0 : if (NS_FAILED(file->GetName(name))) {
356 0 : name.Truncate();
357 : }
358 :
359 0 : JSString* jsName = JS_NewUCStringCopyN(aCx, name.get(), name.Length());
360 0 : if (!jsName) {
361 0 : return false;
362 : }
363 :
364 0 : *aVp = STRING_TO_JSVAL(jsName);
365 0 : return true;
366 : }
367 : };
368 :
369 : JSClass File::sClass = {
370 : "File",
371 : JSCLASS_HAS_PRIVATE,
372 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
373 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
374 : JSCLASS_NO_OPTIONAL_MEMBERS
375 : };
376 :
377 : JSPropertySpec File::sProperties[] = {
378 : { "name", 0, PROPERTY_FLAGS, GetName, js_GetterOnlyPropertyStub },
379 : { "mozFullPath", 0, PROPERTY_FLAGS, GetMozFullPath,
380 : js_GetterOnlyPropertyStub },
381 : { 0, 0, 0, NULL, NULL }
382 : };
383 :
384 : nsIDOMBlob*
385 0 : Blob::GetPrivate(JSObject* aObj)
386 : {
387 0 : if (aObj) {
388 0 : JSClass* classPtr = JS_GetClass(aObj);
389 0 : if (classPtr == &sClass || classPtr == File::Class()) {
390 0 : nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
391 0 : nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(priv);
392 0 : JS_ASSERT_IF(priv, blob);
393 0 : return blob;
394 : }
395 : }
396 0 : return NULL;
397 : }
398 :
399 : } // anonymous namespace
400 :
401 : BEGIN_WORKERS_NAMESPACE
402 :
403 : namespace file {
404 :
405 : JSObject*
406 0 : CreateBlob(JSContext* aCx, nsIDOMBlob* aBlob)
407 : {
408 0 : return Blob::Create(aCx, aBlob);
409 : }
410 :
411 : bool
412 0 : InitClasses(JSContext* aCx, JSObject* aGlobal)
413 : {
414 0 : JSObject* blobProto = Blob::InitClass(aCx, aGlobal);
415 0 : return blobProto && File::InitClass(aCx, aGlobal, blobProto);
416 : }
417 :
418 : nsIDOMBlob*
419 0 : GetDOMBlobFromJSObject(JSObject* aObj)
420 : {
421 0 : return Blob::GetPrivate(aObj);
422 : }
423 :
424 : JSObject*
425 0 : CreateFile(JSContext* aCx, nsIDOMFile* aFile)
426 : {
427 0 : return File::Create(aCx, aFile);
428 : }
429 :
430 : nsIDOMFile*
431 0 : GetDOMFileFromJSObject(JSObject* aObj)
432 : {
433 0 : return File::GetPrivate(aObj);
434 : }
435 :
436 : } // namespace file
437 :
438 : END_WORKERS_NAMESPACE
|