Возврат строки байтов в ExternalInterface.call вызывает ошибку

Я работаю над своим проектом с открытым исходным кодом Downloadify, и до сих пор он просто обрабатывал возвращаемые строки в ответ на ExternalInterface.call команды.

Я пытаюсь собрать тестовый пример, используя JSZip и Downloadify вместе, конечным результатом является то, что Zip-файл создается динамически в браузере, а затем сохраняется на диск с помощью FileReference.save. Однако это моя проблема:

Библиотека JSZip может возвращать либо закодированную base64 строку Zip, либо строку необработанных байтов. Проблема в том, что если я возвращаю эту байтовую строку в ответ на команду ExternalInterface.call, я получаю эту ошибку:

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);

Где queue_name — это просто строка, используемая для идентификации правильного экземпляра в JS.

JavaScript:

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

Если вместо строки байтов я верну обычную строку, вызов будет работать правильно. Я хотел бы избежать использования base64, поскольку мне пришлось бы включать декодер base64 в мой swf, что увеличит его размер.

Наконец: я не ищу генератор AS3 Zip. Для моего проекта обязательно, чтобы эта часть выполнялась на JavaScript

По общему признанию, я не программист AS3 по профессии, поэтому, если вам нужна дополнительная информация, дайте мне знать.


person Doug Neiner    schedule 21.01.2010    source источник
comment
Выглядит хорошо! Я понятия не имею, как ответить на ваш вопрос, но решил указать на опечатку на downloadify.info - пришло время широко использовать эту функцию, должно быть, пришло время широко использовать эту функцию.   -  person Dominic Rodger    schedule 21.01.2010
comment
@ Доминик Роджер Спасибо, чувак ... все исправлено! Компьютерные языки, я не против. Человеческие языки, ну, это разные :)   -  person Doug Neiner    schedule 21.01.2010
comment
нп - всегда рад быть педантом!   -  person Dominic Rodger    schedule 21.01.2010


Ответы (2)


Когда данные возвращаются из вызовов javascript, они сериализуются в строку XML. Поэтому, если «необработанная строка», возвращаемая JSZip, будет включать символы, которые делают XML недействительным, что, как я думаю, здесь происходит, вы получите подобные ошибки.

То, что вы получаете в качестве возврата, на самом деле:

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

Представьте, что ваша возвращаемая строка включает символ "‹" - это сделает xml недействительным, и трудно сказать, какие коды символов будет также переводить необработанный поток байтов.

Дополнительные сведения о формате XML внешнего API см. на странице LiveDocs

person Robert Bak    schedule 21.01.2010
comment
+1 А как бы он это починил? Итерация потока байтов для замены 0x3C (‹) на 0x26 0x6C 0x74 0x3B () и т. д. в javascript и обратно во flash? Будет ли это работать/практично ли это? - person Amarghosh; 21.01.2010
comment
Я бы просто использовал строку в кодировке base64, поскольку библиотека поддерживает, и это хороший и безопасный способ кодирования данных в виде строк. Существует библиотека AS3, которая поддерживает декодирование и кодирование данных base64, по адресу github.com/spjwebster/as3base64. - person Robert Bak; 21.01.2010
comment
Теперь это начинает иметь смысл, почему он выдавал то, что казалось ошибкой XML. Теперь он работает с base64, я просто надеялся избежать этого шага. Я думаю, это тоже хорошо, потому что именно так я буду получать данные из элемента Canvas HTML5. Большое спасибо за вашу помощь и отличный ответ +1. - person Doug Neiner; 21.01.2010

я думаю, что проблема вызвана тем фактом, что флэш-память ожидает строку utf8, и вы бросаете в нее какие-то двоичные файлы. думаю например 0x00FF не окажется валидным utf8...

можно попробовать поиграться с flash.system::System.setCodePage, но я бы не был слишком оптимистичен...

я предполагаю, что декодер base64, вероятно, действительно самый простой ... я бы предпочел беспокоиться о скорости, чем о размере файла ... этот рудиментарный метод декодера использует менее половины 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;
}

вы можете просто сократить имена функций и взять изображение меньшего размера... или использовать ColorTransform или ConvolutionFilter на одном изображении вместо четырех... или скомпилировать изображение в SWF для уменьшения общего размера... или уменьшить длину имени функции...

так что, если вы не планируете работать с мегабайтами данных, это путь ...

person back2dos    schedule 21.01.2010
comment
ой ... забыл на самом деле опубликовать ответ ... ну в любом случае, это может помочь ... ;) - person back2dos; 21.01.2010
comment
Вы правы, даже добавление упомянутой выше библиотеки Encoded/Decoder @Robert добавило всего 1 КБ к моему готовому SWF. Я думаю, я могу жить с этим. Спасибо за ваше время! - person Doug Neiner; 21.01.2010