var dl_fs, dl_fw;
var dl_queue = [];
var dl_queue_num = 0;
var dl_retryinterval = 1000;
var dl_method;
// 0: Filesystem API (Chrome / Firefox Extension polyfill
// 1: Adobe Flash SWF Filewriter (fallback for old browsers)
// 2: BlobBuilder (IE10/IE11)
// 3: Deprecated MEGA Firefox Extension
// 4: Arraybuffer/Blob Memory Based
// 5: MediaSource (experimental streaming solution)
// 6: IndexedDB blob based (Firefox 20+)
var blob_urls = [];
var dl_legacy_ie = (typeof XDomainRequest != 'undefined') && (typeof ArrayBuffer == 'undefined');
var dl_flash_connections = 0;
var dl_flash_progress;
var dl_instance = 0;
var dl_blob;
var dl_blob_array = [];
var dl_key;
var dl_keyNonce;
var dl_macs;
var dl_aes;
var dl_filename;
var dl_filesize;
var dl_geturl;
var dl_bytesreceived = 0;
var dl_chunks = [];
var dl_chunksizes;
var dl_storagetype = 0;
var dl_req_storage = false;
var downloading = false;
var dl_maxSlots = 4;
if (localStorage.dl_maxSlots) dl_maxSlots = localStorage.dl_maxSlots;
var dl_xhrs;
var dl_pos;
var dl_progress;
var dl_lastactive;
var dl_cipherq;
var dl_cipherqlen;
var dl_plainq;
var dl_plainqlen;
var dl_lastquotawarning;
var dl_maxWorkers = 4;
var dl_workers;
var dl_workerbusy;
var dl_quotabytes = 0;
var dl_write_position;
var dl_timeout;
var dl_id;
var dl_chunklen;
var skipcheck = 0;
var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB;
var use_idb = false;
var dl_db;
function dl_dispatch_chain()
{
if (downloading)
{
dl_dispatch_read();
dl_dispatch_decryption();
dl_dispatch_write();
}
}
function dl_dispatch_decryption()
{
var p;
if (use_workers)
{
for (var id = dl_maxWorkers; id--; )
{
if (!dl_workerbusy[id]) break;
}
if (id >= 0)
{
for (p in dl_cipherq)
{
dl_workerbusy[id] = 1;
if (typeof(dl_workers[id]) == "object")
{
dl_workers[id].terminate();
dl_workers[id] = null;
delete dl_workers[id];
}
dl_workers[id] = new Worker('decrypter.js');
dl_workers[id].postMessage = dl_workers[id].webkitPostMessage || dl_workers[id].postMessage;
dl_workers[id].id = id;
dl_workers[id].instance = dl_instance;
dl_workers[id].onmessage = function(e)
{
if (this.instance == dl_instance)
{
if (typeof(e.data) == "string")
{
if (e.data[0] == '[') dl_macs[this.dl_pos] = JSON.parse(e.data);
else if (d) console.log("WORKER" + this.id + ": '" + e.data + "'");
}
else
{
var databuf = new Uint8Array(e.data);
if (d) console.log("WORKER" + this.id + ": Received " + databuf.length + " decrypted bytes at " + this.dl_pos);
if (dl_zip && !this.dl_pos)
{
var prefix = ZIPheader(dl_queue[dl_queue_num].p+dl_queue[dl_queue_num].n,dl_queue[dl_queue_num].size,dl_queue[dl_queue_num].t).fileHeader;
var prefixlen = prefix.length;
if (dl_zip.suffix)
{
dl_zip.pos += dl_zip.suffix.length;
t = new Uint8Array(dl_zip.suffix.length+prefix.length);
t.set(dl_zip.suffix);
t.set(prefix,dl_zip.suffix.length);
prefix = t;
}
dl_zip.headerpos = dl_zip.pos;
dl_zip.pos += prefixlen+dl_queue[dl_queue_num].size;
var i, t = new Uint8Array(databuf.length+prefix.length);
t.set(prefix);
t.set(databuf,prefix.length);
dl_chunklen[this.dl_pos] = databuf.length;
databuf = t;
}
dl_plainq[this.dl_pos] = databuf;
dl_plainqlen++;
dl_workerbusy[this.id] = 0;
dl_dispatch_chain();
}
}
};
dl_workers[id].postMessage(dl_keyNonce);
if (d) console.log("WORKER" + id + ": Queueing " + dl_cipherq[p].length + " bytes at " + p);
dl_workers[id].dl_pos = parseInt(p);
dl_workers[id].postMessage(dl_workers[id].dl_pos/16);
dl_workers[id].postMessage(dl_cipherq[p]);
delete dl_cipherq[p];
dl_cipherqlen--;
break;
}
}
else if (d) console.log("All worker threads are busy now.");
}
else
{
for (p in dl_cipherq)
{
if (d) console.log("Decrypting pending block at " + p + " without workers...");
dl_macs[p] = decrypt_ab_ctr(dl_aes,dl_cipherq[p],[dl_key[4],dl_key[5]],p);
dl_plainq[p] = dl_cipherq[p];
delete dl_cipherq[p];
dl_cipherqlen--;
dl_plainqlen++;
break;
}
}
}
function dl_resume(id)
{
if (downloading) dl_dispatch_chain();
else
{
if (id) for (var i = dl_queue.length; i--; ) if (id == dl_queue[i].id)
{
dl_queue_num = i;
break;
}
startdownload();
}
}
var tt;
var dl_zip;
var dl_writing;
function dl_dispatch_write()
{
if (dl_filesize == -1) return;
if ((!document.getElementById('dlswf_' + dl_id)) && (dl_method == 1))
{
if (d) console.log("Flash element not yet initialized");
return;
}
if (dl_writing)
{
if (d) console.log("Writer busy");
return;
}
var p = -1;
// enforce linearity if zipping or not using FileWriter
if (dl_plainq[dl_write_position])
{
p = dl_write_position;
}
else if (d) console.log("Plaintext at " + dl_write_position + " still missing");
if (p < 0)
{
dl_checklostchunk();
return;
}
dl_write_block();
}
function dl_write_block()
{
if (d) console.log("Writing " + dl_plainq[dl_write_position].length + " bytes of file data at dl_pos " + dl_write_position);
if (dl_zip)
{
if (dl_zip.crc32pos != dl_write_position)
{
dl_zip.crc32 = crc32(dl_plainq[dl_write_position],dl_zip.crc32,dl_chunklen[dl_write_position] || dl_plainq[dl_write_position].length);
dl_zip.crc32pos = dl_write_position;
}
}
switch (dl_method)
{
case 0: // Filesystem API (Chrome / Firefox Extension polyfill
dl_writing = true;
dl_fw.instance = dl_instance;
dl_fw.targetpos = dl_fw.position+dl_plainq[dl_write_position].length;
dl_fw.write(new Blob([dl_plainq[dl_write_position]]));
break;
case 1: // Adobe Flash SWF Filewriter (fallback for old browsers)
var j, k;
var len;
if (have_ab) len = dl_plainq[dl_write_position].length;
else len = dl_plainq[dl_write_position].buffer.length;
if (have_ab) subdata = ab_to_base64(dl_plainq[dl_write_position]);
else subdata = base64urlencode(dl_plainq[dl_write_position].buffer);
document.getElementById('dlswf_' + dl_id).flashdata(dl_id,subdata);
dl_ack_write();
break;
case 2: // BlobBuilder IE10
if (have_ab) dl_blob.append(dl_plainq[dl_write_position]);
else dl_blob.append(dl_plainq[dl_write_position].buffer);
dl_ack_write();
break;
case 3: // Deprecated Firefox Extension
console.log(dl_write_position);
ffe_writechunk(ab_to_str(dl_plainq[dl_write_position]),dl_write_position);
dl_ack_write();
break;
case 4: // Blob Memory Based Downloading
dl_blob_array.push(new Blob([dl_plainq[dl_write_position]]));
dl_ack_write();
break;
case 5: // MediaSource (experimental)
try
{
sourceBuffer.append(dl_plainq[dl_write_position]);
}
catch(e)
{
console.log(e);
}
dl_ack_write();
break;
case 6: // IndexedDB blob based (Firefox 20+)
dl_writing = true;
DBWriter.write(dl_write_position);
}
}
function dl_killzip(id)
{
for (var i = dl_queue.length; i--; ) if (id == dl_queue[i].zipid)
dl_queue[i] = false;
}
function dl_ack_write()
{
if (dl_write_position < 0)
{
// zip suffix
dl_complete();
dl_killzip(dl_zip.id);
return startdownload();
}
if (dl_queue[dl_queue_num].data) new Uint8Array(dl_queue[dl_queue_num].data,dl_write_position,dl_plainq[dl_write_position].length).set(dl_plainq[dl_write_position]);
var t = dl_chunklen[dl_write_position] || (have_ab ? dl_plainq[dl_write_position].length : dl_plainq[dl_write_position].buffer.length);
delete dl_plainq[dl_write_position];
dl_plainqlen--;
dl_write_position += t;
dl_dispatch_chain();
}
function dl_write_failed(e)
{
console.log("WRITE FAILED: " + e);
if (dl_write_position < 0)
{
// zip trailer - retry
dl_setTimeout(dl_write_block,1000);
}
else dl_dispatch_chain();
}
function dl_settimer(timeout,target)
{
if (d) console.log(timeout < 0 ? "Stopping timer" : "Starting timer " + timeout);
if (dl_timeout) clearTimeout(dl_timeout);
if (timeout >= 0) dl_timeout = setTimeout(target,timeout);
else dl_timeout = undefined;
}
function dl_next()
{
var zipid = dl_zip && dl_zip.id;
var mi = -1;
var t = new Date().getTime();
var filesleft;
var i;
for (i = 0; i < dl_queue.length; i++) if (dl_queue[i] && !dl_queue[i].complete && (!zipid || zipid == dl_queue[i].zipid))
{
if (!dl_queue[i].mru)
{
mi = i;
break;
}
if (dl_queue[i].retryafter && t < dl_queue[i].retryafter) continue;
if (mi < 0 || dl_queue[i].mru < dl_queue[mi].mru) mi = i;
else filesleft = 1;
}
if (mi >= 0)
{
if (!zipid && dl_queue[mi].zipid) dl_zip = { id : dl_queue[mi].zipid, dirData : [], pos : 0, headerpos : 0, suffix : '', name : dl_queue[mi].zipname, crc32pos : -1 };
dl_queue[mi].mru = t;
return mi;
}
if (filesleft) dl_settimer(5000,startdownload);
else
{
if (zipid)
{
var t = [];
var p = dl_zip.pos+dl_zip.suffix.length;
t.push(dl_zip.suffix);
// t.push(ZIPfolders(dl_zip.id,p));
dl_zip.pos += t[0].length; //+t[1].length;
for (i = 0; i < dl_zip.dirData.length; i++) t.push(dl_zip.dirData[i]);
t.push(ZIPsuffix(p));
var l = 0;
for (i = t.length; i--; ) l += t[i].length;
var b = new Uint8Array(l);
l = 0;
for (i = 0; i < t.length; i++)
{
b.set(t[i],l);
l += t[i].length;
}
dl_plainq = { '-1' : b };
dl_write_position = -1;
dl_write_block(-1);
}
else dl_queue = [];
return -1;
}
}
// try to start download at dl_queue_num
// if that download is not available, loop through the whole dl_queue and try to start
// another one
function startdownload()
{
if (downloading)
{
if (d) console.log("startdownload() called with active download");
return;
}
if (dl_req_storage) return;
dl_queue_num = dl_next();
if (dl_queue_num < 0) return;
dl_settimer(-1);
downloading = true;
dl_key = dl_queue[dl_queue_num].key;
if (d) console.log("dl_key " + dl_key);
if (dl_queue[dl_queue_num].ph) dl_id = dl_queue[dl_queue_num].ph;
else dl_id = dl_queue[dl_queue_num].id;
dl_geturl = '';
dl_bytesreceived = 0;
dl_chunksizes = [];
dl_keyNonce = JSON.stringify([dl_key[0]^dl_key[4],dl_key[1]^dl_key[5],dl_key[2]^dl_key[6],dl_key[3]^dl_key[7],dl_key[4],dl_key[5]]);
dl_macs = {};
dl_filesize = -1;
dl_cipherq = [];
dl_cipherqlen = 0;
dl_plainq = [];
dl_plainqlen = 0;
dl_lastquotawarning = 0;
dl_chunklen = {};
dl_pos = Array(dl_maxSlots);
dl_progress = Array(dl_maxSlots);
dl_lastactive = Array(dl_maxSlots);
if (!dl_legacy_ie)
{
dl_xhrs = Array(dl_maxSlots);
for (var slot = dl_maxSlots; slot--; )
{
dl_xhrs[slot] = new XMLHttpRequest;
if (dl_xhrs[slot].overrideMimeType) dl_xhrs[slot].overrideMimeType('text/plain; charset=x-user-defined');
dl_xhrs[slot].slot = slot;
dl_pos[slot] = -1;
dl_progress[slot] = 0;
}
}
else
{
dl_flash_connections = 0;
dl_flash_progress = {};
}
if (use_workers)
{
dl_workers = new Array(dl_maxWorkers);
dl_workerbusy = new Array(dl_maxWorkers);
for (var id = dl_maxWorkers; id--; ) dl_workerbusy[id] = 0;
}
else dl_aes = new sjcl.cipher.aes([dl_key[0]^dl_key[4],dl_key[1]^dl_key[5],dl_key[2]^dl_key[6],dl_key[3]^dl_key[7]]);
dl_write_position = 0;
dl_getsourceurl(startdownload2);
}
function dl_renewsourceurl()
{
dl_getsourceurl(dl_renewsourceurl2);
}
function dl_getsourceurl(callback)
{
req = { a : 'g', g : 1, ssl : use_ssl };
if (dl_queue[dl_queue_num].ph) req.p = dl_queue[dl_queue_num].ph;
else if (dl_queue[dl_queue_num].id) req.n = dl_queue[dl_queue_num].id;
api_req([req],{ callback : callback });
}
function dl_renewsourceurl2(res,ctx)
{
if (typeof res == 'object')
{
if (typeof res[0] == 'number')
{
dl_reportstatus(dl_queue_num,res[0]);
}
else
{
if (res[0].g)
{
dl_geturl = res[0].g;
dl_dispatch_chain()
return;
}
else if (res[0].e) dl_reportstatus(dl_queue_num,res[0].e);
}
dl_queue[dl_queue_num].retryafter = new Date().getTime()+30000;
startdownload();
}
}
function dl_reportstatus(num,code)
{
if (dl_queue[num])
{
dl_queue[num].lasterror = code;
dl_queue[num].onDownloadError(dl_queue[num].id || dl_queue[num].ph,code);
}
}
function startdownload2(res,ctx)
{
if (typeof res == 'object')
{
if (typeof res[0] == 'number')
{
dl_reportstatus(dl_queue_num,res[0]);
}
else
{
if (res[0].d)
{
dl_reportstatus(dl_queue_num,res[0].d ? 2 : 1);
dl_queue[dl_queue_num] = false;
}
else if (res[0].g)
{
var ab = base64_to_ab(res[0].at);
var o = dec_attr(ab,[dl_key[0]^dl_key[4],dl_key[1]^dl_key[5],dl_key[2]^dl_key[6],dl_key[3]^dl_key[7]]);
if (typeof o == 'object' && typeof o.n == 'string')
{
if (have_ab && res[0].pfa && res[0].s <= 48*1048576 && is_image(o.n) && (!res[0].fa || res[0].fa.indexOf(':0*') < 0)) dl_queue[dl_queue_num].data = new ArrayBuffer(res[0].s);
return dl_setcredentials(res[0].g,res[0].s,o.n);
}
else dl_reportstatus(dl_queue_num,EKEY);
}
else dl_reportstatus(dl_queue_num,res[0].e);
}
}
else dl_reportstatus(dl_queue_num,EAGAIN);
downloading = false;
dl_queue_num++;
dl_retryinterval *= 1.2;
dl_settimer(dl_retryinterval,startdownload);
}
function dl_setcredentials(g,s,n)
{
var i;
var p;
var pp;
dl_geturl = g;
dl_filesize = s;
dl_filename = n;
dl_chunks = [];
p = pp = 0;
for (i = 1; i <= 8 && p < dl_filesize-i*131072; i++)
{
dl_chunksizes[p] = i*131072;
dl_chunks.push(p);
pp = p;
p += dl_chunksizes[p];
}
while (p < dl_filesize)
{
dl_chunksizes[p] = 1048576;
dl_chunks.push(p);
pp = p;
p += dl_chunksizes[p];
}
if (!(dl_chunksizes[pp] = dl_filesize-pp))
{
delete dl_chunksizes[pp];
delete dl_chunks[dl_chunks.length-1];
}
if (dl_zip)
{
delete dl_zip.crc32;
dl_zip.crc32pos = -1;
}
if (!dl_zip || !dl_zip.open)
{
if (dl_zip) dl_zip.open = true;
switch (dl_method)
{
case 0: // Chrome (aync)
dl_createtmp();
return;
case 2:
dl_blob = new MSBlobBuilder();
break;
case 3:
ffe_createtmp();
break;
case 4:
dl_blob_array = [];
break;
case 6:
DBWriter.init();
}
}
dl_run();
}
function dl_run()
{
if (dl_filesize)
{
for (var i = dl_maxSlots; i--; ) dl_dispatch_read();
dl_queue[dl_queue_num].onDownloadStart(dl_id,dl_filename,dl_filesize);
}
else dl_checklostchunk();
}
function dl_checklostchunk()
{
var i, p;
if (dl_write_position == dl_filesize)
{
if (dl_filesize)
{
var t = [];
for (p in dl_macs) t.push(p);
t.sort(function(a,b) { return parseInt(a)-parseInt(b) });
for (i = 0; i < t.length; i++) t[i] = dl_macs[t[i]];
var mac = condenseMacs(t,[dl_key[0]^dl_key[4],dl_key[1]^dl_key[5],dl_key[2]^dl_key[6],dl_key[3]^dl_key[7]]);
}
if (skipcheck) console.log('Expected: [' + dl_key[6] + ',' + dl_key[7] + '], got: [' + (mac[0]^mac[1]) + ',' + (mac[2]^mac[3]) + ']');
downloading = false;
if (have_ab && !skipcheck && dl_filesize && (dl_key[6] != (mac[0]^mac[1]) || dl_key[7] != (mac[2]^mac[3])))
{
dl_reportstatus(dl_queue_num,EKEY);
if (dl_zip) dl_killzip(dl_zip.id);
else dl_queue[dl_queue_num] = false;
}
else
{
if (dl_queue[dl_queue_num].data && !skipcheck) createnodethumbnail(dl_queue[dl_queue_num].id,new sjcl.cipher.aes([dl_key[0]^dl_key[4],dl_key[1]^dl_key[5],dl_key[2]^dl_key[6],dl_key[3]^dl_key[7]]),++ul_faid,dl_queue[dl_queue_num].data);
if (!dl_zip) dl_complete();
else
{
t = ZIPheader(dl_queue[dl_queue_num].p+dl_queue[dl_queue_num].n,dl_queue[dl_queue_num].size,dl_queue[dl_queue_num].t,dl_zip.crc32,false,dl_zip.headerpos);
dl_zip.suffix = t.dataDescriptor;
dl_zip.dirData.push(t.dirRecord);
dl_queue[dl_queue_num].complete = true;
dl_queue[dl_queue_num].crc32 = dl_zip.crc32;
}
// release all downloads waiting for quota
for (i = dl_queue.length; i--; ) if (dl_queue[i] && dl_queue[i].lasterror == EOVERQUOTA)
{
dl_reportstatus(i,0);
delete dl_queue[i].retryafter;
}
dl_retryinterval = 1000;
}
startdownload();
}
}
function dl_complete()
{
var name;
var path;
if (dl_zip)
{
name = dl_zip.name;
path = false;
}
else
{
name = dl_queue[dl_queue_num].n;
path = dl_queue[dl_queue_num].p;
}
switch (dl_method)
{
case 0:
if (dl_queue_num >= 0) dl_queue[dl_queue_num].onBeforeDownloadComplete();
document.getElementById('dllink').download = name;
document.getElementById('dllink').href = document.fileEntry.toURL();
if (!is_chrome_firefox) document.getElementById('dllink').click();
break;
case 1:
document.getElementById('dlswf_' + dl_id).flashdata(dl_id,'',name);
break;
case 2:
navigator.msSaveOrOpenBlob(dl_blob.getBlob(),name);
break;
case 3:
ffe_complete(name,path);
break;
case 4:
document.getElementById('dllink').download = name;
blob_urls.push(myURL.createObjectURL(new Blob(dl_blob_array)));
document.getElementById('dllink').href = blob_urls[blob_urls.length-1];
document.getElementById('dllink').click();
setTimeout(function()
{
myURL.revokeObjectURL(document.getElementById('dllink').href);
},100);
break;
case 6:
DBWriter.servedl(name);
}
if (dl_zip)
{
fm_zipcomplete(dl_zip.id);
dl_killzip(dl_zip.id);
dl_zip = false;
}
else
{
dl_queue[dl_queue_num].onDownloadComplete(dl_id);
dl_queue[dl_queue_num] = false;
}
}
function dl_httperror(code)
{
if (code == 509)
{
var t = new Date().getTime();
if (!dl_lastquotawarning || t-dl_lastquotawarning > 55000)
{
dl_lastquotawarning = t;
dl_reportstatus(dl_queue_num,code == 509 ? EOVERQUOTA : ETOOMANYCONNECTIONS);
dl_settimer(60000,dl_dispatch_chain);
}
return;
}
dl_reportstatus(dl_queue_num,EAGAIN);
dl_retryinterval *= 1.2;
if (!dl_write_position)
{
dl_cancel();
dl_queue_num++;
dl_settimer(dl_retryinterval,startdownload);
}
else
{
if (d) console.log("Network error, retrying in " + Math.floor(dl_retryinterval)/1000 + " seconds...");
dl_settimer(dl_retryinterval,code == 509 ? dl_dispatch_chain : dl_renewsourceurl);
}
}
function flash_dlprogress(p,numbytes)
{
dl_flash_progress[p] = numbytes;
dl_updateprogress();
}
function dl_flashdldata(p,data,httpcode)
{
dl_flash_connections--;
if (data == 'ERROR' || httpcode != 200)
{
dl_chunks.unshift(p);
var t = new Date().getTime();
dl_httperror(httpcode);
return;
}
data = base64urldecode(data);
delete dl_flash_progress[p];
dl_bytesreceived += data.length;
dl_cipherq[p] = { buffer : data };
dl_cipherqlen++;
dl_updateprogress();
dl_dispatch_chain();
}
function dl_dispatch_read()
{
if (uldl_hold || dl_cipherqlen+dl_plainqlen > dl_maxSlots+40) return;
if (!dl_chunks.length) return;
if (dl_legacy_ie)
{
if (dl_flash_connections > 6) return;
dl_flash_connections++;
var p = dl_chunks[0];
dl_chunks.splice(0,1);
flashdlchunk(p,dl_geturl + '/' + p + '-' + (p+dl_chunksizes[p]-1));
return;
}
for (var slot = dl_maxSlots; slot--; )
if (dl_pos[slot] == -1) break;
if (slot < 0) return;
dl_pos[slot] = dl_chunks[0];
dl_chunks.splice(0,1);
dl_xhrs[slot].instance = dl_instance;
if (d) console.log("Requesting chunk " + dl_pos[slot] + "/" + dl_chunksizes[dl_pos[slot]] + " on slot " + slot + ", " + dl_chunks.length + " remaining");
dl_xhrs[slot].onprogress = function(e)
{
if (this.instance == dl_instance)
{
dl_lastactive[this.slot] = new Date().getTime();
if (!dl_lastquotawarning || new Date().getTime()-dl_lastquotawarning > 55000)
{
if (dl_pos[this.slot] >= 0)
{
dl_progress[this.slot] = e.loaded;
dl_updateprogress();
}
}
}
}
dl_xhrs[slot].onreadystatechange = function()
{
if (this.instance == dl_instance)
{
dl_lastactive[this.slot] = new Date().getTime();
if (this.readyState == this.DONE)
{
if (dl_pos[this.slot] >= 0)
{
if (this.response != null)
{
var p = dl_pos[this.slot];
if (have_ab)
{
if (p >= 0)
{
if (navigator.appName != 'Opera') dl_bytesreceived += this.response.byteLength;
dl_cipherq[p] = new Uint8Array(this.response);
}
}
else
{
// non-IE
if (p >= 0)
{
dl_bytesreceived += this.response.length;
dl_cipherq[p] = { buffer : this.response };
}
}
dl_cipherqlen++;
if (navigator.appName != 'Opera') dl_progress[this.slot] = 0;
dl_updateprogress();
dl_pos[this.slot] = -1;
dl_dispatch_chain();
}
else
{
if (dl_pos[this.slot] != -1)
{
dl_chunks.unshift(dl_pos[this.slot]);
dl_pos[this.slot] = -1;
dl_httperror(this.status);
}
}
}
}
}
}
var range = '/' + dl_pos[slot] + '-' + (dl_pos[slot]+dl_chunksizes[dl_pos[slot]]-1);
if (dl_method) dl_xhrs[slot].open('POST', dl_geturl + range, true);
else
{
// plug extreme Chrome memory leak
var t = dl_geturl.lastIndexOf('/dl/');
dl_xhrs[slot].open('POST', dl_geturl.substr(0,t+1));
dl_xhrs[slot].setRequestHeader("MEGA-Chrome-Antileak",dl_geturl.substr(t) + range);
}
dl_xhrs[slot].responseType = have_ab ? 'arraybuffer' : 'text';
dl_xhrs[slot].send();
}
var dl_prevprogress = 0;
var dl_lastprogress = 0;
function dl_updateprogress()
{
var p = dl_bytesreceived;
if (dl_queue[dl_queue_num])
{
if (dl_legacy_ie) for (var pp in dl_flash_progress) p += dl_flash_progress[pp];
else for (var slot = dl_maxSlots; slot--; ) p += dl_progress[slot];
if (dl_lastprogress+250 > new Date().getTime()) return false;
else dl_lastprogress=new Date().getTime();
dl_queue[dl_queue_num].onDownloadProgress(dl_id, p, dl_filesize, dl_xr.update(p-dl_prevprogress));
dl_prevprogress = p;
}
}
function appendBuffer( buffer1, buffer2 )
{
var tmp = new Uint8Array( buffer1.byteLength + buffer2.byteLength );
tmp.set( new Uint8Array( buffer1 ), 0 );
tmp.set( new Uint8Array( buffer2 ), buffer1.byteLength );
return tmp.buffer;
}
function dl_cancel()
{
dl_settimer(-1);
dl_instance++;
dl_xhrs = dl_pos = dl_workers = dl_progress = dl_cipherq = dl_plainq = dl_progress = dl_chunks = dl_chunksizes = undefined;
downloading = false;
dl_writing = false;
dl_zip = false;
}
var fs_instance;
function dl_retryfsop()
{
if (fs_instance == dl_instance) dl_createtmp();
}
function dl_createtmpfile(fs)
{
dl_fs = fs;
dl_fs.root.getDirectory(dirid, {create: true}, function(dirEntry)
{
if (d) console.log('Directory "' + dirid + '" created')
document.dirEntry = dirEntry;
}, getDirectory_errorHandler);
if (d) console.log("Opening file for writing: " + dl_id);
fs.root.getFile(dirid + '/' + dl_id, {create: true}, function(fileEntry)
{
fileEntry.createWriter(function(fileWriter)
{
if (d) console.log('File "' + dirid + '/' + dl_id + '" created');
dl_fw = fileWriter;
dl_fw.truncate(0);
dl_fw.onerror = function(e)
{
if (d) console.log('Write failed: ' + e.toString());
if (this.instance == dl_instance)
{
dl_writing = false;
dl_write_failed(e);
}
}
dl_fw.onwriteend = function()
{
if (this.instance == dl_instance)
{
if (d) console.log("fileWriter: onwriteend, position: " + this.position + ", expected: " + this.targetpos);
dl_writing = false;
if (this.position == this.targetpos) dl_ack_write();
else dl_write_failed('Short write (' + this.position + ' / ' + this.targetpos + ')');
}
}
document.fileEntry = fileEntry;
dl_run();
}, createWriter_errorHandler);
}, getFile_errorHandler);
}
function RequestFileSystem_errorHandler(e)
{
errorHandler(e,'RequestFileSystem');
}
function getDirectory_errorHandler(e)
{
errorHandler(e,'getDirectory');
}
function createWriter_errorHandler(e)
{
errorHandler(e,'createWriter');
}
function getFile_errorHandler(e)
{
errorHandler(e,'getFile');
}
function errorHandler(e,type)
{
switch (e.code) {
case FileError.QUOTA_EXCEEDED_ERR:
alert('Error writing file, is your harddrive almost full? (' + type + ')');
break;
case FileError.NOT_FOUND_ERR:
alert('NOT_FOUND_ERR in ' + type);
break;
case FileError.SECURITY_ERR:
alert('File transfers do not work with Chrome Incognito.<br>' + '(Security Error in ' + type + ')');
break;
case FileError.INVALID_MODIFICATION_ERR:
alert('INVALID_MODIFICATION_ERR in ' + type);
break;
case FileError.INVALID_STATE_ERR:
fs_instance = dl_instance;
console.log('INVALID_STATE_ERROR in ' + type + ', retrying...');
setTimeout(dl_retryfsop,500);
break;
default:
alert('webkitRequestFileSystem failed in ' + type);
}
}
var dirid = "mega";
function dl_createtmp()
{
window.requestFileSystem(dl_storagetype,1024*1024*1024*25,dl_createtmpfile,RequestFileSystem_errorHandler);
}
if (window.webkitRequestFileSystem)
{
window.requestFileSystem = window.webkitRequestFileSystem;
function dl_getspace(storagetype,minsize)
{
if (!storagetype) storagetype = 0;
if (!minsize) minsize = 0;
window.webkitStorageInfo.queryUsageAndQuota(1, function(used, remaining)
{
if (remaining > 0)
{
dl_quotabytes = remaining;
dl_storagetype=1;
if (dl_quotabytes < 1073741824) clearit(1,3600);
else clearit(1);
startdownload();
}
else
{
var requestbytes = 1024*1024*1024*100;
if (storagetype == 0) requestbytes = 1024*1024*1024*25;
if (storagetype == 1) dl_req_storage = true;
window.webkitStorageInfo.requestQuota(storagetype,requestbytes,function(grantedBytes)
{
window.webkitStorageInfo.queryUsageAndQuota(storagetype, function(used, remaining)
{
if (storagetype == 1) dl_req_storage = false;
dl_quotabytes = remaining;
if (dl_quotabytes < 1073741824) clearit(storagetype,3600);
if ((remaining == 0) && (storagetype == 1))
{
if (!dl_req_storage) dl_getspace(1,minsize);
return false;
}
else if ((minsize > dl_quotabytes) && (storagetype == 0))
{
if (!dl_req_storage) dl_getspace(1,minsize)
return false;
}
else if ((minsize > dl_quotabytes) && (storagetype == 1)) clearit(storagetype,3600);
if (remaining > 0) dl_storagetype = storagetype;
startdownload();
},
function(e)
{
console.log('ERROR: Could not query usage and storage quota. (' + dl_storagetype + ') ' + e);
alert('Could not query usage and storage quota. (' + dl_storagetype + ') ' + e);
});
},
function(e)
{
console.log('ERROR: Could not grant storage space (' + dl_storagetype + ') ' + e);
alert('Could not grant storage space (' + dl_storagetype + ') ' + e);
});
}
},
function(e)
{
console.log('ERROR: Could not query usage and storage quota. (' + dl_storagetype + ') ' + e);
alert('Could not query usage and storage quota. (' + dl_storagetype + ') ' + e);
});
}
dl_getspace(0);
dl_method = 0;
}
else if (navigator.msSaveOrOpenBlob)
{
dl_method = 2;
}
else if ("download" in document.createElementNS("http://www.w3.org/1999/xhtml", "a") && use_idb)
{
function pingDBname()
{
var dbnames = localStorage.dbnames;
if (dbnames) dbnames = JSON.parse(dbnames);
else dbnames = {};
dbnames[DBWriter.iddb_name] =
{
t: new Date().getTime()
};
localStorage.dbnames = JSON.stringify(dbnames);
}
function purgeDBcache()
{
var dbnames = localStorage.dbnames;
if (dbnames)
{
dbnames = JSON.parse(dbnames);
for (var name in dbnames)
{
if (((dbnames[name].c) && (dbnames[name].t < (new Date().getTime()-86000000)))
|| (dbnames[name].t < (new Date().getTime()-200000000)))
{
try
{
window.indexedDB.deleteDatabase(name);
delete dbnames[name];
}
catch (e)
{
console.log('Failed to purge cache DB ' + name);
}
}
}
localStorage.dbnames = JSON.stringify(dbnames);
}
}
purgeDBcache();
var firefox20 = true;
dl_method = 6;
var DBWriter =
{
names: {},
writing: false,
write: function(p)
{
if (localStorage.dbquota) DBWriter.dowrite();
else
{
//ffDialog.start();
DBWriter.tmpdb = new Date().getTime();
var request = window.indexedDB.open(DBWriter.tmpdb,1);
request.onerror = function (error)
{
//ffDialog.start();
if (d) console.log('Error obtaining quota, retrying...');
DBWriter.write();
};
request.onsuccess = function (event)
{
DBWriter.tmpiddb = request.result;
request.getquota();
},
request.onupgradeneeded = function (event)
{
event.target.result.createObjectStore(DBWriter.tmpdb);
};
request.getquota = function ()
{
var transaction = DBWriter.tmpiddb.transaction(DBWriter.tmpdb,'readwrite');
transaction.oncomplete = function()
{
//ffDialog.close();
DBWriter.tmpiddb.close();
window.indexedDB.deleteDatabase(DBWriter.tmpdb);
localStorage.dbquota = 1;
DBWriter.dowrite();
}
transaction.onerror = function(event)
{
//ffDialog.start();
DBWriter.write();
}
transaction.objectStore(DBWriter.tmpdb).put(new Blob([new ArrayBuffer(62914560)]),'quota');
}
}
},
dowrite: function()
{
var request = window.indexedDB.open(DBWriter.iddb_name, 1);
request.onerror = function (error)
{
dl_write_failed(error);
};
request.onsuccess = function (event)
{
// hide quota warning dialog
retry = 0;
DBWriter.iddb = request.result;
request.dowrite();
}
request.onupgradeneeded = function (event)
{
event.target.result.createObjectStore(DBWriter.iddb_name);
}
request.dowrite = function()
{
var transaction = DBWriter.iddb.transaction(DBWriter.iddb_name,'readwrite');
transaction.oncomplete = function()
{
if (transaction.dl_instance == dl_instance)
{
dl_writing = false;
//ffDialog.close();
DBWriter.iddb_i++;
retry = 0;
DBWriter.iddb.close();
pingDBname();
if (d) console.log('DBWriter: Chunk complete');
dl_ack_write();
}
}
transaction.onerror = function(event)
{
dl_writing = false;
// show quota warning dialog
DBWriter.write();
}
transaction.dl_instance = dl_instance;
transaction.objectStore(DBWriter.iddb_name).put(new Blob([dl_plainq[dl_write_position]]),'chunk'+DBWriter.iddb_i);
}
},
servedl: function(name)
{
if (!name) name = 'file.bin';
var request = window.indexedDB.open(DBWriter.iddb_name, 1);
request.onsuccess = function(event)
{
var iddb = request.result;
var transaction = iddb.transaction([DBWriter.iddb_name],'readonly');
transaction.objectStore(DBWriter.iddb_name).mozGetAll().onsuccess = function(event)
{
var dlURL = URL.createObjectURL(new Blob(event.target.result));
var a = document.getElementById('dllink');
a.download = name;
a.href = dlURL;
a.click();
};
}
},
init: function()
{
DBWriter.iddb_i = 1000000;
DBWriter.iddb_name = new Date().getTime();
DBWriter.names[DBWriter.iddb_name] = 1;
pingDBname()
}
};
$(window).unload(function()
{
var dbnames = localStorage.dbnames;
if (dbnames) dbnames = JSON.parse(dbnames);
else dbnames = {};
for (var name in DBWriter.names)
{
dbnames[DBWriter.iddb_name] =
{
t: new Date().getTime(),
c: 1
};
}
localStorage.dbnames = JSON.stringify(dbnames);
});
}
else if ("download" in document.createElementNS("http://www.w3.org/1999/xhtml", "a"))
{
dl_method = 4;
}
else
{
// Flash fallback
dl_method = 1;
}
if (localStorage.dlmethod) dl_method = parseInt(localStorage.dlmethod);
function getxr()
{
return {
update : function(b)
{
var ts = new Date().getTime();
if (b < 0)
{
this.tb = {};
this.st = 0;
return 0;
}
if (b) this.tb[ts] = this.tb[ts] ? this.tb[ts]+b : b;
b = 0;
for (t in this.tb)
{
t = parseInt(t);
if (t < ts-this.window) delete this.tb[t];
else b += this.tb[t];
}
if (!b)
{
this.st = 0;
return 0;
}
else if (!this.st) this.st = ts;
if (!(ts -= this.st)) return 0;
if (ts > this.window) ts = this.window;
return b/ts;
},
tb : {},
st : 0,
window : 60000
}
}
var dl_xr = getxr();
var uldl_hold = false;
function uldl_pause()
{
uldl_hold = true;
}
function uldl_resume()
{
var i;
uldl_hold = false;
if (downloading) for (i = dl_maxSlots; i--; ) dl_dispatch_chain();
if (ul_uploading) for (i = ul_maxSlots; i--; ) ul_dispatch_chain();