From 7fb36fa3969661ca74ceec1a9d65b0e4ed92c208 Mon Sep 17 00:00:00 2001 From: Qvazar Date: Tue, 25 Aug 2015 11:56:02 +0200 Subject: [PATCH] code before tests.. hm --- test/1.txt | 1 + test/2.txt | 1 + test/3.txt | 1 + test/directory/1.txt | 1 + test/directory/2.txt | 1 + test/directory/3.txt | 1 + test/test.tar | Bin 0 -> 7680 bytes untar-worker.js | 168 +++++++++++++++++++++++++++++++++++++++++++ untar.js | 90 +++++++++++++++++++++++ 9 files changed, 264 insertions(+) create mode 100644 test/1.txt create mode 100644 test/2.txt create mode 100644 test/3.txt create mode 100644 test/directory/1.txt create mode 100644 test/directory/2.txt create mode 100644 test/directory/3.txt create mode 100644 test/test.tar create mode 100644 untar-worker.js create mode 100644 untar.js diff --git a/test/1.txt b/test/1.txt new file mode 100644 index 0000000..43dd47e --- /dev/null +++ b/test/1.txt @@ -0,0 +1 @@ +one \ No newline at end of file diff --git a/test/2.txt b/test/2.txt new file mode 100644 index 0000000..64c5e58 --- /dev/null +++ b/test/2.txt @@ -0,0 +1 @@ +two \ No newline at end of file diff --git a/test/3.txt b/test/3.txt new file mode 100644 index 0000000..1d19714 --- /dev/null +++ b/test/3.txt @@ -0,0 +1 @@ +three \ No newline at end of file diff --git a/test/directory/1.txt b/test/directory/1.txt new file mode 100644 index 0000000..43dd47e --- /dev/null +++ b/test/directory/1.txt @@ -0,0 +1 @@ +one \ No newline at end of file diff --git a/test/directory/2.txt b/test/directory/2.txt new file mode 100644 index 0000000..64c5e58 --- /dev/null +++ b/test/directory/2.txt @@ -0,0 +1 @@ +two \ No newline at end of file diff --git a/test/directory/3.txt b/test/directory/3.txt new file mode 100644 index 0000000..1d19714 --- /dev/null +++ b/test/directory/3.txt @@ -0,0 +1 @@ +three \ No newline at end of file diff --git a/test/test.tar b/test/test.tar new file mode 100644 index 0000000000000000000000000000000000000000..4af2de22f4286ad4b9cb50159ffd28ec1a7f5566 GIT binary patch literal 7680 zcmeHLQ3}E^4DC@ofhO&`oJVw^KMra|y}cPj3i}!RNQjvJw5*U9-tyYK;=aCWkR5;k zL=<2i%bCBXfHC(35g{es=VcB%kWFij{UTOgJruIP5*LEa9#fk|2OI1-+xt##{HiP%?{!WI0MdrIR-v_R(f6l literal 0 HcmV?d00001 diff --git a/untar-worker.js b/untar-worker.js new file mode 100644 index 0000000..b386677 --- /dev/null +++ b/untar-worker.js @@ -0,0 +1,168 @@ +"use strict"; + +onmessage = function(source) { + if (typeof source === "string") { + loadArrayBuffer(source).then( + untarBuffer, + function(err) { postMessage({ type: "error", data: err }); } + ); + } else { + untarBuffer(source); + } +}; + +function loadArrayBuffer(uri) { + return new Promise(function(resolve, reject) { + try { + var request = new XMLHttpRequest(); + + request.addEventListener("progress", function(e) { + postMessage({ type: "loading", data: e }); + }); + + request.addEventListener("load", function(e) { + resolve(request.response); + }); + + request.addEventListener("error", reject); + request.addEventListener("abort", reject); + + request.open("GET", uri); + request.responseType = "arraybuffer"; + request.send(); + } catch (err) { + reject(err); + } + }); +} + +function untarBuffer(arrayBuffer) { + try { + var tarFileStream = new TarFileStream(arrayBuffer); + while (tarFileStream.hasNext()) { + var file = tarFileStream.next(); + + postMessage({ type: "extract", data: file }, [file.buffer]); + } + + postMessage({ type: "complete" }); + ); + } catch (err) { + postMessage({ type: "error", data: err }); + } +} + +function TarFile() { + +} + +TarFile.prototype = { + +}; + +function Stream(arrayBuffer) { + this._bufferView = new DataView(arrayBuffer); + this._position = 0; +} + +Stream.prototype = { + readString: function(charCount) { + var charSize = 1; + var byteCount = charCount * charSize; + + var charCodes = []; + + for (var i = 0; i < charCount; ++i) { + var charCode = this._bufferView.getUint8(this.position() + (i * charSize)); + if (charCode !== 0) { + charCodes.push(charCode); + } else { + break; + } + } + + this.seek(byteCount); + + return String.fromCharCode.apply(null, charCodes); + }, + + readBuffer: function(byteCount) { + return this._bufferView.buffer.slice(this._position, byteCount); + } + + seek: function(byteCount) { + this._position += byteCount; + }, + + peekUint32: function() { + return this._bufferView.getUint32(this.position()); + } + + position: function(newpos) { + if (newpos === undefined) { + return this._position; + } else { + this._position = newpos; + } + } +}; + +function TarFileStream(arrayBuffer) { + this._stream = new Stream(arrayBuffer); +} + +TarFileStream.prototype = { + hasNext: function() { + return this._stream.peekUint32() != 0; + }, + + next: function() { + var stream = this._stream; + var file = new TarFile(); + + var headerBeginPos = stream.position; + var dataBeginPos = headerBeginPos + 512; + + // Read header + file.name = stream.readString(100); + file.mode = stream.readString(8); + file.uid = stream.readString(8); + file.gid = stream.readString(8); + file.size = parseInt(stream.readString(12), 8); + file.modificationTime = parseInt(stream.readString(12), 8); + file.checksum = stream.readString(8); + file.type = stream.readString(1); + file.linkname = stream.readString(1); + file.ustarFormat = stream.readString(6); + + if (file.ustarFormat === "ustar") { + file.version = stream.readString(2); + file.uname = stream.readString(32); + file.gname = stream.readString(32); + file.devmajor = stream.readString(8); + file.devminor = stream.readString(8); + file.namePrefix = stream.readString(155); + + if (file.namePrefix.length > 0) { + file.name = file.namePrefix + file.name; + } + } + + stream.position(dataBeginPos); + + // Normal file is either "\0" or 0. + if (file.type == 0 || file.type === "\0") { + file.buffer = stream.readBuffer(file.size); + } else if (file.type == 5) { + // Directory - should we do anything with this? Nope! + } else { + // We only care about real files, not symlinks. + } + + // File data is padded to reach a 512 byte boundary; skip the padded bytes. + var bytesToSkipCount = 512 - file.size % 512; + stream.seek(bytesToSkipCount); + + return file; + } +}; \ No newline at end of file diff --git a/untar.js b/untar.js new file mode 100644 index 0000000..ee0b70a --- /dev/null +++ b/untar.js @@ -0,0 +1,90 @@ +// var workerScriptUri is compiled in + +/** +source = ArrayBuffer or a url string. If an ArrayBuffer, it will be transfered to the web worker and will thus not be available in the window after. +options = { + onComplete, + onLoading, // When downloading the tar from a url. + onExtract, + onError +} +*/ +function untar(source, options) { + if (typeof Promise !== "function") { + throw new Error("Promise implementation not available in this environment."); + } + + if (typeof Worker !== "function") { + throw new Error("Worker implementation not available in this environment."); + } + + options = options || {}; + + function makeTarFile + + return new Promise(function(resolve, reject) { + var noop = function() { }; + var onComplete = options.onComplete || noop; + var onLoading = options.onProgress || noop; + var onExtract = options.onExtract || noop; + var onError = options.onError || noop; + + var worker = new Worker(workerScriptUri); + var files = []; + + worker.onmessage = function(message) { + switch (message.type) { + case "loading": + onLoading(message.data); + break; + case "extract": + var file = new TarFile(message.data); + files.push(file); + onExtract(file); + break; + case "complete": + onComplete(files); + resolve(files); + break; + case "error": + var error = message.data; + onError(error); + reject(error); + break; + default: + var error = new Error("Unknown message from worker."); + onError(error); + reject(error); + break; + } + }; + + // Don't transfer if source is a string. Only ArrayBuffer can be transfered. + worker.postMessage(source, (typeof source === "string" ? undefined : [source])); + }); +} + +function TarFile(orig) { + this._blobUrl = null; + + for (p in orig) { + switch (p) { + case "buffer": + this.blob = new Blob([orig.buffer]); + break; + default: + this[p] = orig[p]; + break; + } + } +} + +TarFile.prototype = { + getObjectUrl: function() { + if (!this._blobUrl) { + this._blobUrl = URL.createObjectURL(this.blob); + } + + return this._blobUrl; + } +}; \ No newline at end of file