djnz0feh
djnz0feh

Reputation: 437

Writing binary data from javascript (Firefox plugin)

Hi: I'm writing a firefox extension (my first) that among other things, gets an image url read into a byte Array, and then writes out that binary information to a file. I have used this example, which looks as if it works, but the file is not right, as if some sort of character conversion has been performed on it.

My version is as follows:

testWriteBinaryFile : function (dir, filename, data) {
    var aFile = Components.classes["@mozilla.org/file/local;1"].
        createInstance(Components.interfaces.nsILocalFile);

    aFile.initWithPath( "/home/mike/mypicture.gif" );
    aFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
    Firebug.Console.log("Binary writing: file set up");

    var stream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].
                 createInstance(Components.interfaces.nsIFileOutputStream);
    stream.init(aFile, 0x04 | 0x08 | 0x20, 0600, 0); // readwrite, create, truncate
    Firebug.Console.log("Binary writing: stream set up");

    Firebug.Console.log("Data length: " + data.length);
    Firebug.Console.log("Data byte 0: " + data[0].toString(16));
    Firebug.Console.log("Data byte 1: " + data[1].toString(16));
    Firebug.Console.log("Data byte 2: " + data[2].toString(16));
    Firebug.Console.log("Data byte 3: " + data[3].toString(16));
    Firebug.Console.log("Data byte 4: " + data[4].toString(16));

    stream.write(data, data.length);
    Firebug.Console.log("Binary writing: stream written")
    if (stream instanceof Components.interfaces.nsISafeOutputStream) {
        stream.finish();
    } else {
        stream.close();
    }
    Firebug.Console.log("Binary writing: done.");
}

I know the data buffer itself is OK by printing out the first few bytes, but the file is completely different once on disk. Any ideas or indeed any other ways to write out a binary file?

I know this is a synchronous write, but the files are small, (20Kb)... but that's the only example. If I can fix this I have the extension finished! Any and all help appreciated.

Upvotes: 1

Views: 1124

Answers (1)

Wladimir Palant
Wladimir Palant

Reputation: 57651

The code as you have it here works fine - e.g. it if data is "foo\0\n\rbar" that string is correctly written to disk. Maybe the issue is that nsIOutputStream.write() expects a string as parameter, you are talking about a byte array however. If your data variable is indeed a byte array then maybe it is easiest to convert it into a string first:

data = String.fromCharCode.apply(String, data);

After that operation data is a string corresponding to the original byte array and can be used with nsIOutputStream.write(). The more efficient (but probably unnecessary in this case) approach would be using nsIBinaryOutputStream, something like this:

Components.utils.import("resource://gre/modules/FileUtils.jsm");

var stream = FileUtils.openSafeFileOutputStream(aFile, FileUtils.MODE_WRONLY |
                                                       FileUtils.MODE_CREATE);

var binaryStream = Components.classes["@mozilla.org/binaryoutputstream;1"]
                             .createInstance(Components.interfaces.nsIBinaryOutputStream);
binaryStream.setOutputStream(stream);
binaryStream.writeByteArray(data, data.length);

FileUtils.closeSafeFileOutputStream(stream);

I am using FileUtils module in this example, it makes things a lot simpler.

Upvotes: 2

Related Questions