My first pass was to use nsIIOService to create an nsIChannel. This worked and gave me time to focus on getting my parser methods correct.
function runRestoreFromChannel( urlSpec, progress )
{
var ioService = CC["@mozilla.org/network/io-service;1"].getService(CI.nsIIOService);
var reader = CC["@mozilla.org/saxparser/xmlreader;1"].createInstance(CI.nsISAXXMLReader);
var channel = ioService.newChannel( urlSpec,null,null );
channel.notificationCallbacks = progress;
reader.contentHandler = new RestoreParser( broker, progress );
reader.parseAsync( null );
channel.contentType = "text/xml";
//channel.loadFlags = CI.nsIRequest.LOAD_BACKGROUND;
channel.asyncOpen( reader, null );
}
This solution has one major flaw. The nsIFileInputStream that’s created reads in very large chunks from the filesystem for performance. The problem is during my parse I do some fairly intensive I/O operations as I read my data in. But since, almost all the data is read in by the nsIInputStream, it means my GUI is locked up while I’m processing the data. To get around this I thought about writing my own nsIStreamListener and controlling how the data is passed to my nsISAXXMLReader. The problem there is I’d either have to buffer all the data or still be stuck in a loop on the main thread blocking the UI. Ideally, I’d be able to run the parser in a background thread at full speed. As a simple workaround I can use nsIInputStreamPump. It works almost identically to using the nsIChannel, except I can specify how much data to read at a time (i.e. the chunk size). There was one minor little problem that can be worked around using a custom nsIStreamListener around the nsISAXXMLReader.
Here’s the code for setting up the parser:
var reader = CC["@mozilla.org/saxparser/xmlreader;1"].createInstance(CI.nsISAXXMLReader);
var filestream = CC["@mozilla.org/network/file-input-stream;1"].createInstance(CI.nsIFileInputStream);
var pump = CC["@mozilla.org/network/input-stream-pump;1"].createInstance(CI.nsIInputStreamPump);
var ioService = CC["@mozilla.org/network/io-service;1"].getService(CI.nsIIOService);
var channel = ioService.newChannel( urlSpec,null,null );
var uri = ioService.newURI( urlSpec, null, null );
filestream.init(file, 0x01, 0444, 0);
reader.contentHandler = new RestoreParser( broker, progress );
reader.parseAsync( null );
pump.init( filestream, -1, -1, StreamChunkSize, 1, false );
reader.baseURI = uri;
pump.asyncRead( new StreamListener( reader, progress, channel ), null );
Here’s the code for wrapping the nsIStreamListener:
function StreamListener( reader, progress, channel )
{
this.reader = reader;
this.progress = progress;
this.channel = channel;
}
StreamListener.prototype = {
reader:null,
onStartRequest: function( request,context ){
dump( "starting\n" );
// XXX: passing channel here to work around bug in nsParser.cpp
this.reader.onStartRequest( this.channel, context );
},
onDataAvailable: function( request, context, input, offset, count ){
dump( "offset: " + offset + ", count: " + count + "\n" );
// XXX: passing channel here to work around bug in nsParser.cpp
this.reader.onDataAvailable( this.channel, context, input, offset, count );
this.progress.onProgress( request, context, offset, offset + count );
},
onStopRequest: function( request, context, status ){
// XXX: passing channel here to work around bug in nsParser.cpp
this.reader.onStopRequest( this.channel, context, status );
}
};
Software Javascript, XML, XPCOM, XUL
Recent Comments