ダウンロードして復号までの流れ
ファイルのダウンロード時にはlocation.
location.
ファイルをダウンロードする
XMLHttpRequestを使って暗号化済みのファイルをダウンロードします。responseTypeを指定することで、
XMLHttpRequestで従来よりよく使われるresponseTextは、
- あいうえお
とUTF-8で書かれたファイルを受信した場合、
req = new XMLHttpRequest;
req.open("GET", "test.txt", false);
req.send();
req.responseText.length; // 5 文字req = new XMLHttpRequest;
req.responseType = "arraybuffer";
req.open("GET", "test.txt", false);
req.send();
req.response.byteLength; // 15bytesそれに対して、req.はリスト4のように5文字を示します。文字数とバイト数が一致しないと、
今までXMLHttpRequestを使ってバイナリファイルを扱うには、charset = x-user-definedという文字コードを指定する方法がよく知られていました
特殊な文字コード指定を使うことで、
ファイルのダウンロードと復号
単純にXMLHttpRequestで巨大なファイルをダウンロードする場合、
この問題はサーバ側でファイルを分割してダウンロードすることで解決できます。問題は、
crypto-jsでは受信したデータを順次復号していくことが可能ですが、
ほかのブラウザでは動かないことになってしまうので、
function download(path, password, filename){
  req = new XMLHttpRequest;
  req.open("GET", "./files/" + path, true);
  req.responseType = "arraybuffer";
  req.onload = function(){
    var buffer = req.response;
    decode_arraybuffer(buffer, password, filename);
  };
  req.send("");
}
function objecturlready(url, filename){
  var el;
  if (/(gif|jpg|png)$/i.test(filename)) {
    el = TB("img", {title: filename, alt: filename, src: url});
  } else {
    el = TB("a", {href: url, download: filename}, "Click here to save file");
  }
  document.getElementById("result").appendChild(el);
}
function decode_arraybuffer(ab, password, filename) {
  var dec = new StreamDecryptor(password);
  dec.decorder = null;
  var wordarray = CryptoJS.lib.WordArray.create( ab );
  dec.process(wordarray);
  dec.process();
  var isImage = /(gif|jpg|png)$/i.test(filename);
  var suffix = filename.match(/([^.]*?)$/);
  suffix = suffix ? suffix[1].toLowerCase() : "";
  var mimetype = isImage ? { type: "image/"+suffix}
  : { type: "application/octet-stream"};
  if (window.requestFileSystem) {
    var file = new TempFile();
    file.onready = function(){
      file.write( new Blob(dec.result) );
      setTimeout(function(){
        objecturlready(file.toURL(), filename);
      }, 100);
    };
  } else {
    // Safari does not support create blob from typed array
    var isBuggyBrowser = (new Blob([new Uint8Array()]).size > 0 ) ? true : false;
    var blob = isBuggyBrowser
        ? new Blob(dec.result.map(function(v){ return v.buffer }), mimetype)
        : new Blob(dec.result, mimetype);
    var objectURL = (
        window.URL || window.webkitURL || dataURLsim
      ).createObjectURL(blob);
    setTimeout(function(){
      objecturlready(objectURL, filename);
    }, 0);
  }
}FileSystem APIを使って一時ファイルを作る
次に、
window.requestFileSystem = window.requestFileSystem ||
window.webkitRequestFileSystem;
// for chrome
if (window.requestFileSystem) {
// var file = new TempFile; file.write(); file.
downloadLink;
  var TempFile = function(){
    var self = {
      ready: false
    };
    var errorHandler = function(){ console.log(arguments)
};
    var onInitFs = function(fs) {
      var fileHandler = function(fileEntry) {
        self.fileEntry = fileEntry;
        // Create a FileWriter object for our FileEntry
        fileEntry.createWriter(function(fileWriter) {
        fileWriter.onwriteend = function(e) {
          console.log('Write completed.') };
        fileWriter.onerror = function(e) {
          console.log('Write failed: ' + e.toString())
};
        // Create a new Blob and write it to log.txt.
        self.ready = true;
        self.writer = fileWriter;
          self.seek = function(pos) { fileWriter.seek(pos) };
          self.write = function(blob) {
            fileWriter.write(blob) };
          self.append = function(blob) {
            self.seek(fileWriter.length);
            self.write(blob);
          };
          self.toURL = function(){
            return self.fileEntry.toURL() };
          if (self.onready) {
            self.onready();
          }
        }, errorHandler);
      }
      fs.root.getFile(
       'data', // ファイル名
       {create: true}, fileHandler , errorHandler);
    };
    window.requestFileSystem(
      window.TEMPORARY, // 一時領域
      1024*1024, onInitFs, errorHandler);
    return self;
  }
}サイズの小さいデータならば、
ファイルをURLに変換する
createObjectURLを使うことで、
名前を付けてファイルを保存
aタグのdownload attributeというものがWHATWGで提案されており、download="ファイル名"とすることで、
Data URIで代用する
比較的小さなファイルや、
var dataURLsim = {
  createObjectURL: function(blob){
    var fr = new FileReader;
    fr.readAsDataURL(blob);
    return {
      toString: function(){ return fr.result }
    };
  }
};
var objectURL = (
  window.URL || window.webkitURL || dataURLsim
).createObjectURL(blob);
setTimeout(function(){ img.src = objectURL }, 0);本来使うべきcreateObjectURLと違ってFileReaderを使うため、
ダウンロード復号の際、特に気を付けたいポイント 
次に、
Blobの組み立て
Blobを生成するためには、
// 文字列からBlob を作る
// 長さ1 の内部表現文字列がUTF-8 にエンコードされて
// 3bytes のBlob になった
new Blob([" あ"]).size // 3bytes
// 長さ1 の内部表現文字列をUTF-8 のバイト列に変換する
inta = new Uint8Array( encodeURI(" あ").split("%").
slice(1).map(function(v){ return parseInt(v,16)}) )
// 長さ3 のUint8Array がそのままBlob に変換された
new Blob([inta]).size // 3bytes
// " あ" を3 文字に分解する
bytes = encodeURI(" あ").split("%").slice(1).
map(function(v){ return String.fromCharCode(
parseInt(v,16) ) }).join("");
bytes.length // 3 文字
// 長さ3 の内部表現文字列をUTF-8 にエンコードした結果
// 2×3 で6bytes になった
new Blob([bytes]).size // 6bytes従来の
Typed ArrayからのBlob生成
Blobコンストラクタに直接渡してBlobオブジェクトを生成できます。しかし、
// "\x01\x02\x03\x04\x05" 相当のバイナリデータを作る
var array = new Uint8Array([1,2,3,4,5]);
new Blob([array]) // 現在推奨されている方法 [12]
new Blob([array.buffer]) // 古い方法 [13]SafariでBlobコンストラクタに空のTyped Arrayを渡した場合、
b = new Blob([new Int8Array()]);
f = new FileReader;f.readAsText(b);
f.result; // "[object Int8Array]"このように、
Typed ArrayからBlobの生成に対応しているかどうか見極めるためには、
var isOldBlobConstructor = (
  new Blob([new Int8Array()]).size > 0 ) ? true : false;