Question

This question is an extension of this StackOverflow question about IE to the Opera 12 browser.

The root problem is an issue in geoxml3 handling kmz (zipped kml) files.

Example that fails in Opera 12

The binary data is being processed with TypedArrays in a modified version of ZipFile.complete.js

After the binary file is transferred the Uint8Array is not populated correctly in Opera 12, it is as if the data is being imported as 16-bit elements.

The request is configured like this:

this.req.responseType = 'arraybuffer';
this.req.overrideMimeType('text/plain; charset=x-user-defined');

The value returned is handled like this:

var fileContents = binStream.req.response;
binStream.length = fileContents.byteLength;
binStream.array = new Uint8Array(fileContents);

the first eight bytes are populated like this in Opera 12:

0x004B0050; giving a decimal value of 4915280

but should be:

0x4034B50; a decimal value of 67324752.

This works correctly in Firefox, Chrome and IE (with a workaround).

Does anyone know how I can convince Opera 12 to populate the Uint8Array correctly? Or a workaround so that it will work (some way to convert the array of 16-bit bytes into an array of 8-bit bytes, discarding the unneeded upper 8-bits as efficiently as possible)? Is this a known bug in the recent implementation of the TypedArray/XmlHttpRequest in Opera 12?

Was it helpful?

Solution

Opera 12.00 introduced support for responseType; unfortunately, there's a bug in it that means given a text/* MIME type you'll end up the file as 16-bit words. It's fixed in 12.01, but the simplest fix is to set the override type as application/octet-stream. (This is CORE-46938 for those of you desiring to stalk a closed bug-tracker.)

OTHER TIPS

This "patch" works:

var fileContents = binStream.req.response;
binStream.length = fileContents.byteLength;
binStream.array = new Uint8Array(fileContents);

/* patch for Opera */
if (/opera/i.test(navigator.userAgent) && 
    // make sure it is still broken,
    // the first 4 bytes will contain the zip file signature
    // for the geoxml3 use case (so bytes 1 & 3 will not be 0)
    (binStream.array[1] == 0) && (binStream.array[3] == 0))
{    
    fixedArray = new Uint8Array(binStream.length/2);
    for (var i=0; i<binStream.length; i+=2) {
        fixedArray[i/2]=binStream.array[i];
    }
    binStream.array = fixedArray;
    binStream.length = binStream.length/2;
}
/* end patch for Opera */

Is there a more efficient way to do this? Does anyone know a way to do it without doing the browser specific test?

EDIT: added check to make sure the behavior is still broken (in case it is a bug and is fixed). May not work in the general case, but for the geoxml3 use case the first 4 bytes will contain the zip file signature which will not have 0's in the high order bytes if it works correctly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top