xo-vmdk-to-vhd
Version:
JS lib reading and writing .vmdk and .ova files
118 lines (117 loc) • 5.06 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.compressionNone = exports.compressionDeflate = exports.SECTOR_SIZE = exports.MARKER_GT = exports.MARKER_GD = exports.MARKER_FOOTER = exports.MARKER_EOS = void 0;
exports.createStreamOptimizedHeader = createStreamOptimizedHeader;
exports.parseFlags = parseFlags;
exports.parseU64b = parseU64b;
exports.unpackHeader = unpackHeader;
const SECTOR_SIZE = exports.SECTOR_SIZE = 512;
const compressionDeflate = exports.compressionDeflate = 'COMPRESSION_DEFLATE';
const compressionNone = exports.compressionNone = 'COMPRESSION_NONE';
const MARKER_EOS = exports.MARKER_EOS = 0;
const MARKER_GT = exports.MARKER_GT = 1;
const MARKER_GD = exports.MARKER_GD = 2;
const MARKER_FOOTER = exports.MARKER_FOOTER = 3;
const compressionMap = [compressionNone, compressionDeflate];
function parseFlags(flagBuffer) {
const number = flagBuffer.readUInt32LE(0);
return {
newLineTest: !!(number & 1 << 0),
useSecondaryGrain: !!(number & 1 << 1),
useZeroedGrainTable: !!(number & 1 << 2),
compressedGrains: !!(number & 1 << 16),
hasMarkers: !!(number & 1 << 17)
};
}
function parseS64b(buffer, offset, valueName) {
const extraBits = buffer.readIntLE(offset + 6, 2);
const value = buffer.readIntLE(offset, 6);
const hadValueInHighBytes = !(extraBits === 0 || extraBits === -1);
const readWrongSign = Math.sign(value) * Math.sign(extraBits) < 0;
if (hadValueInHighBytes || readWrongSign) {
throw new Error('Unsupported VMDK, ' + valueName + ' is too big');
}
return value;
}
function parseU64b(buffer, offset, valueName) {
const extraBits = buffer.readUIntLE(offset + 6, 2);
const value = buffer.readUIntLE(offset, 6);
if (extraBits > 0) {
throw new Error('Unsupported VMDK, ' + valueName + ' is too big');
}
return value;
}
function unpackHeader(buffer) {
const magicString = buffer.slice(0, 4).toString('ascii');
if (magicString !== 'KDMV') {
throw new Error('not a VMDK file');
}
const version = buffer.readUInt32LE(4);
if (version !== 1 && version !== 3) {
throw new Error('unsupported VMDK version ' + version + ', only version 1 and 3 are supported');
}
const flags = parseFlags(buffer.slice(8, 12));
const capacitySectors = parseU64b(buffer, 12, 'capacitySectors');
const grainSizeSectors = parseU64b(buffer, 20, 'grainSizeSectors');
const descriptorOffsetSectors = parseU64b(buffer, 28, 'descriptorOffsetSectors');
const descriptorSizeSectors = parseU64b(buffer, 36, 'descriptorSizeSectors');
const numGTEsPerGT = buffer.readUInt32LE(44);
const rGrainDirectoryOffsetSectors = parseS64b(buffer, 48, 'rGrainDirectoryOffsetSectors');
const grainDirectoryOffsetSectors = parseS64b(buffer, 56, 'grainDirectoryOffsetSectors');
const overheadSectors = parseS64b(buffer, 64, 'overheadSectors');
const compressionMethod = compressionMap[buffer.readUInt16LE(77)];
const l1EntrySectors = numGTEsPerGT * grainSizeSectors;
return {
magicString,
version,
flags,
compressionMethod,
grainSizeSectors,
overheadSectors,
capacitySectors,
descriptorOffsetSectors,
descriptorSizeSectors,
grainDirectoryOffsetSectors,
rGrainDirectoryOffsetSectors,
l1EntrySectors,
numGTEsPerGT
};
}
function createStreamOptimizedHeader(capacitySectors, descriptorSizeSectors, grainDirectoryOffsetSectors = -1, rGrainDirectoryOffsetSectors = 0) {
const headerBuffer = Buffer.alloc(SECTOR_SIZE);
Buffer.from('KDMV', 'ascii').copy(headerBuffer, 0);
headerBuffer.writeUInt32LE(3, 4);
const flags = 1 | 1 << 1 | 1 << 16 | 1 << 17;
headerBuffer.writeUInt32LE(flags, 8);
headerBuffer.writeBigUInt64LE(BigInt(capacitySectors), 12);
const grainSizeSectors = 128;
headerBuffer.writeBigUInt64LE(BigInt(grainSizeSectors), 20);
const descriptorOffsetSectors = 1;
headerBuffer.writeBigUInt64LE(BigInt(descriptorOffsetSectors), 28);
headerBuffer.writeBigUInt64LE(BigInt(descriptorSizeSectors), 36);
const numGTEsPerGT = 512;
headerBuffer.writeUInt32LE(numGTEsPerGT, 44);
headerBuffer.writeBigInt64LE(BigInt(rGrainDirectoryOffsetSectors), 48);
headerBuffer.writeBigInt64LE(BigInt(grainDirectoryOffsetSectors), 56);
const grainDirectoryEntries = Math.ceil(Math.ceil(capacitySectors / grainSizeSectors) / numGTEsPerGT);
const grainTableEntries = grainDirectoryEntries * numGTEsPerGT;
const grainDirectorySizeSectors = Math.ceil(grainDirectoryEntries * 4 / SECTOR_SIZE);
const grainTableSizeSectors = Math.ceil(grainTableEntries * 4 / SECTOR_SIZE);
let overheadSectors = 1 + descriptorSizeSectors;
if (grainDirectoryOffsetSectors > 0) {
overheadSectors += grainDirectorySizeSectors + grainTableSizeSectors;
}
headerBuffer.writeBigInt64LE(BigInt(overheadSectors), 64);
headerBuffer.write('\n \r\n', 73, 4, 'ascii');
headerBuffer.writeUInt16LE(1, 77);
return {
buffer: headerBuffer,
grainDirectorySizeSectors,
grainTableSizeSectors,
grainDirectoryEntries,
grainTableEntries
};
}
//# sourceMappingURL=definitions.js.map
;