MozillaZine

How to access local file via chrome URL?

Talk about add-ons and extension development.
Bananeweizen
 
Posts: 2
Joined: November 3rd, 2004, 12:13 am

Post Posted November 3rd, 2004, 12:21 am

Hi all,

in my Wikipedia extension I want to read a locale specific XML file from "chrome://wikipedia/locale/templates.xml". I have code using the nsILocalFile interface which definitely works for windows filename like c:\test.txt using initWithPath() but does not work for such a chrome URL. What do I need to do to translate the chrome URL to a local file name or do I need to use another interface?

Ciao and Thanks, Michael.

Torisugari
 
Posts: 1634
Joined: November 4th, 2002, 8:34 pm
Location: Kyoto, Nippon (GMT +9)

Post Posted November 3rd, 2004, 1:23 am

Bananeweizen wrote:What do I need to do to translate the chrome URL to a local file name or do I need to use another interface?


A file in a package is not a normal local file, so there might not be no "path". How about such a script?
Code: Select all
function getContents(aURL){
  var ioService=Components.classes["@mozilla.org/network/io-service;1"]
    .getService(Components.interfaces.nsIIOService);
  var scriptableStream=Components
    .classes["@mozilla.org/scriptableinputstream;1"]
    .getService(Components.interfaces.nsIScriptableInputStream);

  var channel=ioService.newChannel(aURL,null,null);
  var input=channel.open();
  scriptableStream.init(input);
  var str=scriptableStream.read(input.available());
  scriptableStream.close();
  input.close();
  return str;
}

try{
  alert(getContents("chrome://browser/content/browser.css"));
  alert(getContents("http://www.mozillazine.org/"));
}catch(e){alert(e)}


Note: Such a synch reading freezes the UI during its operation. If the contents is too large to put up with waiting for the result, please use asyncOpen instead.
http://www.xulplanet.com/references/xpc ... _asyncOpen

mcm_ham

User avatar
 
Posts: 1747
Joined: June 16th, 2004, 6:09 am
Location: Christchurch, New Zealand

Post Posted August 11th, 2005, 7:23 pm

Very useful Torisugari,

I have one problem though, in my extension I'm allowing the user to set the URL path to load from. On Deer Park Alpha though if it is set to a directory like "file:///C:/" then "channel.open()" works (on Fx 1.0.6 it throws a not implemented exception) and crashes on the scriptable stream read because "input.available()" returns a very large number.

Secondly I've found when reading files from a website address (http://...), it often does not read more then a single packet (I'm guessing) cutting the file off. Some astute person helped by suggesting this code which fixed that problem.

Code: Select all
var length, str = "";

if (channel.contentLength > 0)
  length = channel.contentLength;
else
  length = input.available();
     
while (str.length < length)
  str += streamIO.read(length - str.length);

Instead of:

Code: Select all
var str=scriptableStream.read(input.available());


Edit
Have filed Bug 304414 for the first issue.

dan61psu
 
Posts: 9
Joined: January 24th, 2007, 3:59 pm

Post Posted March 22nd, 2007, 6:00 pm

How could I extend the example Torisugari posted so that I can stream in well formed XML from a chrome path and then manipulate it/read it via DOM methods???

Thanks!

Jfingland
 
Posts: 4
Joined: March 21st, 2008, 7:43 pm

Post Posted March 31st, 2008, 8:30 pm

First note that you can read an xml file with the chrome url, but for writing you need something like the following...

Code: Select all
function chromeToPath (aPath) {

   if (!aPath || !(/^chrome:/.test(aPath)))
      return; //not a chrome url
   var rv;
   
      var ios = Components.classes['@mozilla.org/network/io-service;1'].getService(Components.interfaces["nsIIOService"]);
        var uri = ios.newURI(aPath, "UTF-8", null);
        var cr = Components.classes['@mozilla.org/chrome/chrome-registry;1'].getService(Components.interfaces["nsIChromeRegistry"]);
        rv = cr.convertChromeURL(uri).spec;

        if (/^file:/.test(rv))
          rv = this.urlToPath(rv);
        else
          rv = this.urlToPath("file://"+rv);

      return rv;
}

function urlToPath (aPath) {

    if (!aPath || !/^file:/.test(aPath))
      return ;
    var rv;
   var ph = Components.classes["@mozilla.org/network/protocol;1?name=file"]
        .createInstance(Components.interfaces.nsIFileProtocolHandler);
    rv = ph.getFileFromURLSpec(aPath).path;
    return rv;
}


the above will translate chrome urls to local file adreesses... in another function you could...

Code: Select all
function doXmlStuff () {
   var somefile = chromeToPath("chrome://path/to/file");
   var xmlDoc;
   var file = Components.classes["@mozilla.org/file/local;1"]
         .createInstance(Components.interfaces.nsILocalFile);
   file.initWithPath(somefile);
   if (!(file.exists())) {
      var fcStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
         .createInstance(Components.interfaces.nsIFileOutputStream);
      fcStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate

      var data = '<xml><rootnode></rootnode>';
      fcStream.write(data,data.length);
      fcStream.close
   }

   xmlDoc = document.implementation.createDocument("","",null);
   xmlDoc.load("chrome://piratequesting/content/trainingLog.xml");
   xmlDoc.onload = function () {
      xmlDoc.documentElement.appendChild(....whatever you want to append....);
      var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
                         .createInstance(Components.interfaces.nsIFileOutputStream);
      //clear the file for writing the new doc
      foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate
      var ser = new XMLSerializer();
      //write the serialized XML to file
      ser.serializeToStream(xmlDoc, foStream, "");
      foStream.close();   
   }
}


Hope this helps. There may be a faster way to do things but this gets the job done.

Kybuk
 
Posts: 4
Joined: June 18th, 2006, 8:22 am

Post Posted January 8th, 2009, 10:27 am

So, is there a way to get a file content from within xpi package ?

I need do it in js xpcom.

When I try Torisugari approach (second post in this theme) I get
Code: Select all
[Exception... "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIChannel.open]"  nsresult: "0x80004005 (NS_ERROR_FAILURE)"  location: ...


When I try next code (content descriptor in chrome.manifest has "contentacessible=yes" flag)
Code: Select all
var domdoc = Components.classes["@mozilla.org/xul/xul-document;1"].createInstance (Components.interfaces.nsIDOMXULDocument);
var doc = domdoc.implementation.createDocument("","",null);
doc.async = false;
doc. load("chrome://myext/content/overlay.xul");

I get
Code: Select all
[Exception... "Access to restricted URI denied"  code: "1012" nsresult: "0x805303f4 (NS_ERROR_DOM_BAD_URI)"  location: ...
immemorial to be born

max1million
 
Posts: 2807
Joined: November 15th, 2004, 5:03 am

Post Posted January 8th, 2009, 11:23 pm

XMLHttpRequest can read xml from chrome:// (even jarred) or file:// like in this reply. If you keep file out of jar you can use like in this reply to get a file:// url, or the var file is an nsIFile, and see Getting_special_files

say if the user specified file location not set and file not in profile folder, read a default from chrome:// or extension's folder,

and for modified xml, if the user specified file location not set, save then read from profile

note: all for chrome code not web page, (requesting xul I had troubles with)

Kybuk
 
Posts: 4
Joined: June 18th, 2006, 8:22 am

Post Posted January 10th, 2009, 6:38 am

Now I have some more info.
channel. open () fails if document being opened is already used as overlay. (i.e. there is an 'overlay' line in chrome.manifest).
I can't use XMLHttpRequest object because it isn't defined in js xpcom runtime environment. I tried to use nsIXMLHttpRequest but it returns 'null' in '.responseXML' ('.async' property was set to 'false').
immemorial to be born

Return to Extension Development


Who is online

Users browsing this forum: No registered users and 2 guests