Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning a byte string to ExternalInterface.call throws an error

I am working on my open source project Downloadify, and up until now it simply handles returning Strings in response to ExternalInterface.call commands.

I am trying to put together a test case using JSZip and Downloadify together, the end result being that a Zip file is created dynamically in the browser, then saved to the disk using FileReference.save. However, this is my problem:

The JSZip library can return either a base64 encoded string of the Zip, or the raw byte string. The problem is, if I return that byte string in response to the ExternalInterface.call command, I get this error:

Error #1085: The element type "string" must be terminated by the matching end-tag "</string>"

ActionScript 3:

var theData:* = ExternalInterface.call('Downloadify.getTextForSave',queue_name);

Where queue_name is just a string used to identify the correct instance in JS.

JavaScript:

var zip = new JSZip();
zip.add("test.txt", "Hello world!\n");
var content = zip.generate(true);
return content;

If I instead return a normal string instead of the byte string, the call works correctly.I would like to avoid using base64 as I would have to include a base64 decoder in my swf which will increase its size.

Finally: I am not looking for a AS3 Zip generator. It is imperative to my project to have that part run in JavaScript

I am admittedly not a AS3 programmer by trade, so if you need any more detail please let me know.

like image 916
Doug Neiner Avatar asked Jan 21 '10 05:01

Doug Neiner


2 Answers

When data is being returned from javascript calls it's being serialized into an XML string. So if the "raw string" returned by JSZip will include characters which make the XML non-valid, which is what I think is happening here, you'll get errors like that.

What you get as a return is actually:

<string>[your JSZip generated string]</string>

Imagine your return string includes a "<" char - this will make the xml invalid, and it's hard to tell what character codes will a raw byte stream translate too.

You can read more about the external API's XML format on LiveDocs

like image 195
Robert Bak Avatar answered Oct 05 '22 22:10

Robert Bak


i think the problem is caused by the fact, that flash expects a utf8 String and you throw some binary stuff at it. i think for example 0x00FF will not turn out to be valid utf8 ...

you can try fiddling around with flash.system::System.setCodePage, but i wouldn't be too optimistic ...

i guess a base64 decoder is probably really the easiest ... i'd rather worry about speed than about file size though ... this rudimentary decoder method uses less than half a K:

public function decodeBase64(source:String):ByteArray {
 var ret:ByteArray = new ByteArray();
 var map:Object = new Object();
 var i:int = 0;
 for each (var char:String in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split("")) map[char] = i++;
 map["="] = 0;
 source = source.split("\n").join("").split("\r").join("");//remove linebreaks
 for (i = 0; i < source.length/4; i++) {
  var buf:int = 0;
  for each (char in source.substr(i * 4, 4).split("")) buf = (buf << 6) + map[char];
  ret.writeByte(buf >>> 16);
  ret.writeShort(buf);
 }
 return ret;
}

you could simply shorten function names and take a smaller image ... or use ColorTransform or ConvolutionFilter on one image instead of four ... or compile the image into the SWF for smaller overall size ... or reduce function name length ...

so unless you're planning on working with MBs of data, this is the way to go ...

like image 20
back2dos Avatar answered Oct 06 '22 00:10

back2dos