Bug 1199384 - Add shell function for writing a typed array to a file, r=sfink.
authorBrian Hackett <bhackett1024@gmail.com>
Sun, 13 Sep 2015 15:19:33 -0600
changeset 262256 c64a1f703079e505a5202be3cf2926277a75e3c4
parent 262255 faaafe8c3d1e6be8611b7f56297914a92ca1478d
child 262257 124d73f46e52640746f0414f951f717bb1c97b93
push id29369
push usercbook@mozilla.com
push dateMon, 14 Sep 2015 11:58:54 +0000
treeherdermozilla-central@fba4b0cd3823 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1199384
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1199384 - Add shell function for writing a typed array to a file, r=sfink.
js/src/shell/OSObject.cpp
js/src/shell/js.cpp
js/src/shell/jsshell.h
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -120,17 +120,17 @@ ResolvePath(JSContext* cx, HandleString 
 static JSObject*
 FileAsTypedArray(JSContext* cx, const char* pathname)
 {
     FILE* file = fopen(pathname, "rb");
     if (!file) {
         JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
         return nullptr;
     }
-    AutoCloseInputFile autoClose(file);
+    AutoCloseFile autoClose(file);
 
     RootedObject obj(cx);
     if (fseek(file, 0, SEEK_END) != 0) {
         JS_ReportError(cx, "can't seek end of %s", pathname);
     } else {
         size_t len = ftell(file);
         if (fseek(file, 0, SEEK_SET) != 0) {
             JS_ReportError(cx, "can't seek start of %s", pathname);
@@ -206,16 +206,60 @@ osfile_readFile(JSContext* cx, unsigned 
 
 static bool
 osfile_readRelativeToScript(JSContext* cx, unsigned argc, Value* vp)
 {
     return ReadFile(cx, argc, vp, true);
 }
 
 static bool
+osfile_writeTypedArrayToFile(JSContext* cx, unsigned argc, Value* vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+
+    if (args.length() != 2 ||
+        !args[0].isString() ||
+        !args[1].isObject() ||
+        !args[1].toObject().is<TypedArrayObject>())
+    {
+        JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
+                             JSSMSG_INVALID_ARGS, "writeTypedArrayToFile");
+        return false;
+    }
+
+    RootedString givenPath(cx, args[0].toString());
+    RootedString str(cx, ResolvePath(cx, givenPath, RootRelative));
+    if (!str)
+        return false;
+
+    JSAutoByteString filename(cx, str);
+    if (!filename)
+        return false;
+
+    FILE* file = fopen(filename.ptr(), "wb");
+    if (!file) {
+        JS_ReportError(cx, "can't open %s: %s", filename.ptr(), strerror(errno));
+        return false;
+    }
+    AutoCloseFile autoClose(file);
+
+    TypedArrayObject* obj = &args[1].toObject().as<TypedArrayObject>();
+
+    if (fwrite(obj->viewData(), obj->bytesPerElement(), obj->length(), file) != obj->length() ||
+        !autoClose.release())
+    {
+        JS_ReportError(cx, "can't write %s", filename.ptr());
+        return false;
+    }
+
+    args.rval().setUndefined();
+    return true;
+}
+
+static bool
 Redirect(JSContext* cx, FILE* fp, HandleString relFilename)
 {
     RootedString filename(cx, ResolvePath(cx, relFilename, RootRelative));
     if (!filename)
         return false;
     JSAutoByteString filenameABS(cx, filename);
     if (!filenameABS)
         return false;
@@ -266,16 +310,20 @@ static const JSFunctionSpecWithHelp osfi
 "readRelativeToScript(filename, [\"binary\"])",
 "  Read filename into returned string. Filename is relative to the directory\n"
 "  containing the current script."),
 
     JS_FS_HELP_END
 };
 
 static const JSFunctionSpecWithHelp osfile_unsafe_functions[] = {
+    JS_FN_HELP("writeTypedArrayToFile", osfile_writeTypedArrayToFile, 2, 0,
+"writeTypedArrayToFile(filename, data)",
+"  Write the contents of a typed array to the named file."),
+
     JS_FN_HELP("redirect", osfile_redirect, 2, 0,
 "redirect(stdoutFilename[, stderrFilename])",
 "  Redirect stdout and/or stderr to the named file. Pass undefined to avoid\n"
 "   redirecting. Filenames are relative to the current working directory."),
 
     JS_FS_HELP_END
 };
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -568,17 +568,17 @@ Process(JSContext* cx, const char* filen
     } else {
         file = fopen(filename, "r");
         if (!file) {
             JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                                  JSSMSG_CANT_OPEN, filename, strerror(errno));
             return;
         }
     }
-    AutoCloseInputFile autoClose(file);
+    AutoCloseFile autoClose(file);
 
     if (!forceTTY && !isatty(fileno(file))) {
         // It's not interactive - just execute it.
         RunFile(cx, filename, file, compileOnly);
     } else {
         // It's an interactive filehandle; drop into read-eval-print loop.
         ReadEvalPrintLoop(cx, file, gOutFile, compileOnly);
     }
@@ -659,17 +659,17 @@ CreateMappedArrayBuffer(JSContext* cx, u
     }
 
     FILE* file = fopen(filename.ptr(), "r");
     if (!file) {
         JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr,
                              JSSMSG_CANT_OPEN, filename.ptr(), strerror(errno));
         return false;
     }
-    AutoCloseInputFile autoClose(file);
+    AutoCloseFile autoClose(file);
 
     if (!sizeGiven) {
         struct stat st;
         if (fstat(fileno(file), &st) < 0) {
             JS_ReportError(cx, "Unable to stat file");
             return false;
         }
         if (st.st_size < off_t(offset)) {
@@ -1289,17 +1289,17 @@ js::shell::FileAsString(JSContext* cx, c
     size_t len, cc;
     char* buf;
 
     file = fopen(pathname, "rb");
     if (!file) {
         JS_ReportError(cx, "can't open %s: %s", pathname, strerror(errno));
         return nullptr;
     }
-    AutoCloseInputFile autoClose(file);
+    AutoCloseFile autoClose(file);
 
     if (fseek(file, 0, SEEK_END) != 0) {
         JS_ReportError(cx, "can't seek end of %s", pathname);
     } else {
         len = ftell(file);
         if (fseek(file, 0, SEEK_SET) != 0) {
             JS_ReportError(cx, "can't seek start of %s", pathname);
         } else {
--- a/js/src/shell/jsshell.h
+++ b/js/src/shell/jsshell.h
@@ -1,8 +1,14 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 #ifndef jsshell_js_h
 #define jsshell_js_h
 
 #include "jsapi.h"
 
 namespace js {
 namespace shell {
 
@@ -18,24 +24,30 @@ const JSErrorFormatString*
 my_GetErrorMessage(void* userRef, const unsigned errorNumber);
 
 static void
 my_ErrorReporter(JSContext* cx, const char* message, JSErrorReport* report);
 
 JSString*
 FileAsString(JSContext* cx, const char* pathname);
 
-class AutoCloseInputFile
+class AutoCloseFile
 {
   private:
     FILE* f_;
   public:
-    explicit AutoCloseInputFile(FILE* f) : f_(f) {}
-    ~AutoCloseInputFile() {
-        if (f_ && f_ != stdin)
-            fclose(f_);
+    explicit AutoCloseFile(FILE* f) : f_(f) {}
+    ~AutoCloseFile() {
+        (void) release();
+    }
+    bool release() {
+        bool success = true;
+        if (f_ && f_ != stdin && f_ != stdout && f_ != stderr)
+            success = !fclose(f_);
+        f_ = nullptr;
+        return success;
     }
 };
 
 } /* namespace shell */
 } /* namespace js */
 
 #endif