kopia lustrzana https://github.com/viljoviitanen/js-untar
compiles, now for testing
rodzic
7fb36fa396
commit
d49886d085
|
@ -1,27 +1,2 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
build
|
||||
node_modules
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
var gulp = require("gulp"),
|
||||
umd = require("gulp-umd"),
|
||||
sourcemaps = require("gulp-sourcemaps"),
|
||||
uglify = require("gulp-uglify"),
|
||||
insert = require("gulp-insert"),
|
||||
addSrc = require("gulp-add-src"),
|
||||
concat = require("gulp-concat"),
|
||||
jshint = require("gulp-jshint"),
|
||||
jasmine = require("gulp-jasmine");
|
||||
|
||||
gulp.task("default", function() {
|
||||
return gulp.src("untar-worker.js")
|
||||
.pipe(sourcemaps.init())
|
||||
.pipe(jshint())
|
||||
.pipe(jshint.reporter("default"))
|
||||
.pipe(jshint.reporter("fail"))
|
||||
.pipe(uglify())
|
||||
.pipe(insert.transform(function(contents, file) {
|
||||
var str = ["\nworkerScriptUri = URL.createObjectURL(new Blob([\""];
|
||||
str.push(contents.replace(/"/g, '\\"'));
|
||||
str.push("\"]));");
|
||||
|
||||
return str.join("");
|
||||
}))
|
||||
.pipe(addSrc("untar.js"))
|
||||
.pipe(jshint())
|
||||
.pipe(jshint.reporter("default"))
|
||||
.pipe(jshint.reporter("fail"))
|
||||
.pipe(concat("untar.js"))
|
||||
.pipe(umd({
|
||||
exports: function() { return "untar"; },
|
||||
namespace: function() { return "untar"; }
|
||||
}))
|
||||
.pipe(sourcemaps.write())
|
||||
.pipe(gulp.dest("build/dev"))
|
||||
.pipe(uglify())
|
||||
.pipe(gulp.dest("build/dist"));
|
||||
});
|
||||
|
||||
gulp.task("test", ["default"], function() {
|
||||
return gulp.src("spec/*.js")
|
||||
.pipe(jasmine({
|
||||
includeStackTrace: true,
|
||||
verbose: true
|
||||
}));
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"name": "untar",
|
||||
"version": "0.0.1",
|
||||
"description": "untar files in the browser",
|
||||
"main": "",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Qvazar/js-untar.git"
|
||||
},
|
||||
"keywords": [
|
||||
"js",
|
||||
"untar",
|
||||
"browser",
|
||||
"extract"
|
||||
],
|
||||
"author": "Sebastian Joergensen <sebjorg@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Qvazar/js-untar/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Qvazar/js-untar",
|
||||
"devDependencies": {
|
||||
"gulp": "^3.9.0",
|
||||
"gulp-add-src": "^0.2.0",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-insert": "^0.5.0",
|
||||
"gulp-jasmine": "^2.0.1",
|
||||
"gulp-jshint": "^1.11.2",
|
||||
"gulp-sourcemaps": "^1.5.2",
|
||||
"gulp-uglify": "^1.3.0",
|
||||
"gulp-umd": "^0.2.0"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
var untar = require("../build/dev/untar.js");
|
||||
|
||||
describe("untar", function() {
|
||||
it("should unpack 3 files and a directory with 3 files", function() {
|
||||
untar("data/test.tar").then(function(files) {
|
||||
expect(files.length).toBe(6);
|
||||
});
|
||||
});
|
||||
})
|
|
@ -1 +0,0 @@
|
|||
one
|
|
@ -1 +0,0 @@
|
|||
two
|
|
@ -1 +0,0 @@
|
|||
three
|
|
@ -1 +0,0 @@
|
|||
one
|
|
@ -1 +0,0 @@
|
|||
two
|
|
@ -1 +0,0 @@
|
|||
three
|
277
untar-worker.js
277
untar-worker.js
|
@ -1,168 +1,169 @@
|
|||
"use strict";
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
onmessage = function(source) {
|
||||
if (typeof source === "string") {
|
||||
loadArrayBuffer(source).then(
|
||||
untarBuffer,
|
||||
function(err) { postMessage({ type: "error", data: err }); }
|
||||
);
|
||||
} else {
|
||||
untarBuffer(source);
|
||||
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 loadArrayBuffer(uri) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function untarBuffer(arrayBuffer) {
|
||||
try {
|
||||
var request = new XMLHttpRequest();
|
||||
var tarFileStream = new TarFileStream(arrayBuffer);
|
||||
while (tarFileStream.hasNext()) {
|
||||
var file = tarFileStream.next();
|
||||
|
||||
request.addEventListener("progress", function(e) {
|
||||
postMessage({ type: "loading", data: e });
|
||||
});
|
||||
postMessage({ type: "extract", data: file }, [file.buffer]);
|
||||
}
|
||||
|
||||
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();
|
||||
postMessage({ type: "complete" });
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
postMessage({ type: "error", data: 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() {
|
||||
function TarFile() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
TarFile.prototype = {
|
||||
TarFile.prototype = {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
function Stream(arrayBuffer) {
|
||||
this._bufferView = new DataView(arrayBuffer);
|
||||
this._position = 0;
|
||||
}
|
||||
function Stream(arrayBuffer) {
|
||||
this._bufferView = new DataView(arrayBuffer);
|
||||
this._position = 0;
|
||||
}
|
||||
|
||||
Stream.prototype = {
|
||||
readString: function(charCount) {
|
||||
var charSize = 1;
|
||||
var byteCount = charCount * charSize;
|
||||
Stream.prototype = {
|
||||
readString: function(charCount) {
|
||||
var charSize = 1;
|
||||
var byteCount = charCount * charSize;
|
||||
|
||||
var charCodes = [];
|
||||
var charCodes = [];
|
||||
|
||||
for (var i = 0; i < charCount; ++i) {
|
||||
var charCode = this._bufferView.getUint8(this.position() + (i * charSize));
|
||||
if (charCode !== 0) {
|
||||
charCodes.push(charCode);
|
||||
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 {
|
||||
break;
|
||||
this._position = newpos;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.seek(byteCount);
|
||||
|
||||
return String.fromCharCode.apply(null, charCodes);
|
||||
},
|
||||
|
||||
readBuffer: function(byteCount) {
|
||||
return this._bufferView.buffer.slice(this._position, byteCount);
|
||||
function TarFileStream(arrayBuffer) {
|
||||
this._stream = new Stream(arrayBuffer);
|
||||
}
|
||||
|
||||
seek: function(byteCount) {
|
||||
this._position += byteCount;
|
||||
},
|
||||
TarFileStream.prototype = {
|
||||
hasNext: function() {
|
||||
return this._stream.peekUint32() !== 0;
|
||||
},
|
||||
|
||||
peekUint32: function() {
|
||||
return this._bufferView.getUint32(this.position());
|
||||
}
|
||||
next: function() {
|
||||
var stream = this._stream;
|
||||
var file = new TarFile();
|
||||
|
||||
position: function(newpos) {
|
||||
if (newpos === undefined) {
|
||||
return this._position;
|
||||
} else {
|
||||
this._position = newpos;
|
||||
}
|
||||
}
|
||||
};
|
||||
var headerBeginPos = stream.position;
|
||||
var dataBeginPos = headerBeginPos + 512;
|
||||
|
||||
function TarFileStream(arrayBuffer) {
|
||||
this._stream = new Stream(arrayBuffer);
|
||||
}
|
||||
// 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);
|
||||
|
||||
TarFileStream.prototype = {
|
||||
hasNext: function() {
|
||||
return this._stream.peekUint32() != 0;
|
||||
},
|
||||
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);
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
};
|
||||
}());
|
||||
|
|
30
untar.js
30
untar.js
|
@ -1,4 +1,4 @@
|
|||
// var workerScriptUri is compiled in
|
||||
var workerScriptUri; // Included at compile time
|
||||
|
||||
/**
|
||||
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.
|
||||
|
@ -10,6 +10,7 @@ options = {
|
|||
}
|
||||
*/
|
||||
function untar(source, options) {
|
||||
"use strict";
|
||||
if (typeof Promise !== "function") {
|
||||
throw new Error("Promise implementation not available in this environment.");
|
||||
}
|
||||
|
@ -20,8 +21,6 @@ function untar(source, options) {
|
|||
|
||||
options = options || {};
|
||||
|
||||
function makeTarFile
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
var noop = function() { };
|
||||
var onComplete = options.onComplete || noop;
|
||||
|
@ -31,6 +30,7 @@ function untar(source, options) {
|
|||
|
||||
var worker = new Worker(workerScriptUri);
|
||||
var files = [];
|
||||
var msgData;
|
||||
|
||||
worker.onmessage = function(message) {
|
||||
switch (message.type) {
|
||||
|
@ -38,23 +38,23 @@ function untar(source, options) {
|
|||
onLoading(message.data);
|
||||
break;
|
||||
case "extract":
|
||||
var file = new TarFile(message.data);
|
||||
files.push(file);
|
||||
onExtract(file);
|
||||
msgData = new TarFile(message.data);
|
||||
files.push(msgData);
|
||||
onExtract(msgData);
|
||||
break;
|
||||
case "complete":
|
||||
onComplete(files);
|
||||
resolve(files);
|
||||
break;
|
||||
case "error":
|
||||
var error = message.data;
|
||||
onError(error);
|
||||
reject(error);
|
||||
msgData = message.data;
|
||||
onError(msgData);
|
||||
reject(msgData);
|
||||
break;
|
||||
default:
|
||||
var error = new Error("Unknown message from worker.");
|
||||
onError(error);
|
||||
reject(error);
|
||||
msgData = new Error("Unknown message from worker.");
|
||||
onError(msgData);
|
||||
reject(msgData);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
@ -65,9 +65,10 @@ function untar(source, options) {
|
|||
}
|
||||
|
||||
function TarFile(orig) {
|
||||
"use strict";
|
||||
this._blobUrl = null;
|
||||
|
||||
for (p in orig) {
|
||||
for (var p in orig) {
|
||||
switch (p) {
|
||||
case "buffer":
|
||||
this.blob = new Blob([orig.buffer]);
|
||||
|
@ -81,10 +82,11 @@ function TarFile(orig) {
|
|||
|
||||
TarFile.prototype = {
|
||||
getObjectUrl: function() {
|
||||
"use strict";
|
||||
if (!this._blobUrl) {
|
||||
this._blobUrl = URL.createObjectURL(this.blob);
|
||||
}
|
||||
|
||||
return this._blobUrl;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
Ładowanie…
Reference in New Issue