GT2/GT2-iOS/node_modules/decompress-zip/lib/structures.js

229 lines
6.7 KiB
JavaScript

'use strict';
var binary = require('binary');
var convertDateTime = function (dosDate, dosTime) {
var year = ((dosDate >> 9) & 0x7F) + 1980;
var month = (dosDate >> 5) & 0x0F;
var day = dosDate & 0x1F;
var hour = (dosTime >> 11);
var minute = (dosTime >> 5) & 0x3F;
var second = (dosTime & 0x1F) * 2;
var result = new Date(year, month - 1, day, hour, minute, second, 0);
return result;
};
var convertGeneralPurposeFlags = function (value) {
var bits = [];
for (var i = 0; i < 16; i++) {
bits[i] = (value >> i) & 1;
}
return {
encrypted: !!bits[0],
compressionFlag1: !!bits[1],
compressionFlag2: !!bits[2],
useDataDescriptor: !!bits[3],
enhancedDeflating: !!bits[4],
compressedPatched: !!bits[5],
strongEncryption: !!bits[6],
utf8: !!bits[11],
encryptedCD: !!bits[13]
};
};
var parseExternalFileAttributes = function (externalAttributes, platform) {
var types = {
// In theory, any of these could be set. Realistically, though, it will
// be regular, directory or symlink
1: 'NamedPipe',
2: 'Character',
4: 'Directory',
6: 'Block',
8: 'File',
10: 'SymbolicLink',
12: 'Socket'
};
switch (platform) {
case 3: // Unix
return {
platform: 'Unix',
type: types[(externalAttributes >> 28) & 0x0F],
mode: (externalAttributes >> 16) & 0xFFF
};
// case 0: // MSDOS
default:
if (platform !== 0) {
console.warn('Possibly unsupported ZIP platform type, ' + platform);
}
var attribs = {
A: (externalAttributes >> 5) & 0x01,
D: (externalAttributes >> 4) & 0x01,
V: (externalAttributes >> 3) & 0x01,
S: (externalAttributes >> 2) & 0x01,
H: (externalAttributes >> 1) & 0x01,
R: externalAttributes & 0x01
};
// With no better guidance we'll make the default permissions ugo+r
var mode = parseInt('0444', 8);
if (attribs.D) {
mode |= parseInt('0111', 8); // Set the execute bit
}
if (!attribs.R) {
mode |= parseInt('0222', 8); // Set the write bit
}
mode &= ~process.umask();
return {
platform: 'DOS',
type: attribs.D ? 'Directory' : 'File',
mode: mode
};
}
};
var readEndRecord = function (buffer) {
var data = binary.parse(buffer)
.word32lu('signature')
.word16lu('diskNumber')
.word16lu('directoryStartDisk')
.word16lu('directoryEntryCountDisk')
.word16lu('directoryEntryCount')
.word32lu('directorySize')
.word32lu('directoryOffset')
.word16lu('commentLength')
.buffer('comment', 'commentLength')
.vars;
data.comment = data.comment.toString();
return data;
};
var directorySort = function (a, b) {
return a.relativeOffsetOfLocalHeader - b.relativeOffsetOfLocalHeader;
};
var readDirectory = function (buffer) {
var directory = [];
var current;
var index = 0;
while (index < buffer.length) {
current = binary.parse(buffer.slice(index, index + 46))
.word32lu('signature')
.word8lu('creatorSpecVersion')
.word8lu('creatorPlatform')
.word8lu('requiredSpecVersion')
.word8lu('requiredPlatform')
.word16lu('generalPurposeBitFlag')
.word16lu('compressionMethod')
.word16lu('lastModFileTime')
.word16lu('lastModFileDate')
.word32lu('crc32')
.word32lu('compressedSize')
.word32lu('uncompressedSize')
.word16lu('fileNameLength')
.word16lu('extraFieldLength')
.word16lu('fileCommentLength')
.word16lu('diskNumberStart')
.word16lu('internalFileAttributes')
.word32lu('externalFileAttributes')
.word32lu('relativeOffsetOfLocalHeader')
.vars;
index += 46;
current.generalPurposeFlags = convertGeneralPurposeFlags(current.generalPurposeBitFlag);
current.fileAttributes = parseExternalFileAttributes(current.externalFileAttributes, current.creatorPlatform);
current.modifiedTime = convertDateTime(current.lastModFileDate, current.lastModFileTime);
current.fileName = current.extraField = current.fileComment = '';
current.headerLength = 46 + current.fileNameLength + current.extraFieldLength + current.fileCommentLength;
if (current.fileNameLength > 0) {
current.fileName = buffer.slice(index, index + current.fileNameLength).toString();
index += current.fileNameLength;
}
if (current.extraFieldLength > 0) {
current.extraField = buffer.slice(index, index + current.extraFieldLength).toString();
index += current.extraFieldLength;
}
if (current.fileCommentLength > 0) {
current.fileComment = buffer.slice(index, index + current.fileCommentLength).toString();
index += current.fileCommentLength;
}
if (current.fileAttributes.type !== 'Directory' && current.fileName.substr(-1) === '/') {
// TODO: check that this is a reasonable check
current.fileAttributes.type = 'Directory';
}
directory.push(current);
}
directory.sort(directorySort);
return directory;
};
var readFileEntry = function (buffer) {
var index = 0;
var fileEntry = binary.parse(buffer.slice(index, 30))
.word32lu('signature')
.word16lu('versionNeededToExtract')
.word16lu('generalPurposeBitFlag')
.word16lu('compressionMethod')
.word16lu('lastModFileTime')
.word16lu('lastModFileDate')
.word32lu('crc32')
.word32lu('compressedSize')
.word32lu('uncompressedSize')
.word16lu('fileNameLength')
.word16lu('extraFieldLength')
.vars;
index += 30;
fileEntry.fileName = fileEntry.extraField = '';
fileEntry.entryLength = 30 + fileEntry.fileNameLength + fileEntry.extraFieldLength;
if (fileEntry.entryLength > structures.maxFileEntrySize) {
throw new Error('File entry unexpectedly large: ' + fileEntry.entryLength + ' (max: ' + structures.maxFileEntrySize + ')');
}
if (fileEntry.fileNameLength > 0) {
fileEntry.fileName = buffer.slice(index, index + fileEntry.fileNameLength).toString();
index += fileEntry.fileNameLength;
}
if (fileEntry.extraFieldLength > 0) {
fileEntry.extraField = buffer.slice(index, index + fileEntry.extraFieldLength).toString();
index += fileEntry.extraFieldLength;
}
return fileEntry;
};
var structures = module.exports = {
readEndRecord: readEndRecord,
readDirectory: readDirectory,
readFileEntry: readFileEntry,
maxFileEntrySize: 4096
};