@runejs/filestore
Version:
Tools for managing the RuneJS filestore.
155 lines (154 loc) • 7.07 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.writeDataChunk = exports.readDataChunk = exports.writeIndexChunk = exports.readIndexChunk = exports.readIndexedDataChunk = exports.sectorLength = exports.dataChunkLength = exports.indexFileLength = void 0;
const common_1 = require("@runejs/common");
exports.indexFileLength = 6;
exports.dataChunkLength = 512;
exports.sectorLength = 520;
const readIndexedDataChunk = (fileId, indexId, channels) => {
const indexFile = (0, exports.readIndexChunk)(fileId, indexId, indexId === 255
? channels.metaChannel
: channels.indexChannels[indexId]);
if (!indexFile) {
throw new Error(`Error parsing index file for file ID ${fileId} in index ${indexId}.`);
}
const dataFile = (0, exports.readDataChunk)(fileId, indexFile, channels.dataChannel);
if (!dataFile) {
throw new Error(`Error parsing data file for file ID ${fileId} in index ${indexId}.`);
}
return { indexFile, dataFile };
};
exports.readIndexedDataChunk = readIndexedDataChunk;
const readIndexChunk = (fileId, indexId, indexChannel) => {
const ptr = fileId * exports.indexFileLength;
if (ptr < 0 || ptr >= indexChannel.length) {
throw new Error('File Not Found');
}
const buf = new common_1.ByteBuffer(exports.indexFileLength);
indexChannel.copy(buf, 0, ptr, ptr + exports.indexFileLength);
if (buf.readable !== exports.indexFileLength) {
throw new Error(`Not Enough Readable Index Data: Buffer contains ${buf.readable} but needed ${exports.indexFileLength}`);
}
const size = buf.get('INT24');
const sector = buf.get('INT24');
return { indexId, fileId, size, sector };
};
exports.readIndexChunk = readIndexChunk;
const writeIndexChunk = (indexChunk, indexChannel) => {
const indexBuffer = new common_1.ByteBuffer(exports.indexFileLength);
indexBuffer.put(indexChunk.size, 'INT24');
indexBuffer.put(indexChunk.sector, 'INT24');
indexChannel.writerIndex = indexChunk.indexId * exports.indexFileLength;
indexChannel.putBytes(indexBuffer);
};
exports.writeIndexChunk = writeIndexChunk;
const readDataChunk = (fileId, indexFile, dataChannel) => {
const data = new common_1.ByteBuffer(indexFile.size);
let chunk = 0;
let remaining = indexFile.size;
let ptr = indexFile.sector * exports.sectorLength;
do {
const buf = new common_1.ByteBuffer(exports.sectorLength);
dataChannel.copy(buf, 0, ptr, ptr + exports.sectorLength);
if (buf.readable !== exports.sectorLength) {
throw new Error(`Not Enough Readable Sector Data: Buffer contains ${buf.readable} but needed ${exports.sectorLength}`);
}
const sectorId = buf.get('SHORT', 'UNSIGNED');
const sectorChunk = buf.get('SHORT', 'UNSIGNED');
const nextSector = buf.get('INT24');
const sectorIndex = buf.get('BYTE', 'UNSIGNED');
const sectorData = new common_1.ByteBuffer(exports.dataChunkLength);
buf.copy(sectorData, 0, buf.readerIndex, buf.readerIndex + exports.dataChunkLength);
if (remaining > exports.dataChunkLength) {
sectorData.copy(data, data.writerIndex, 0, exports.dataChunkLength);
data.writerIndex = data.writerIndex + exports.dataChunkLength;
remaining -= exports.dataChunkLength;
if (sectorIndex !== indexFile.indexId) {
throw new Error('File type mismatch.');
}
if (sectorId !== fileId) {
throw new Error('File id mismatch.');
}
if (sectorChunk !== chunk++) {
throw new Error('Chunk mismatch.');
}
ptr = nextSector * exports.sectorLength;
}
else {
sectorData.copy(data, data.writerIndex, 0, remaining);
data.writerIndex = data.writerIndex + remaining;
remaining = 0;
}
} while (remaining > 0);
return data;
};
exports.readDataChunk = readDataChunk;
const writeDataChunk = (indexId, fileId, fileBuffer, filestoreChannels) => {
let sector;
const writeBuffer = new common_1.ByteBuffer(exports.sectorLength);
sector =
(filestoreChannels.dataChannel.length + (exports.sectorLength - 1)) /
exports.sectorLength;
if (sector === 0) {
sector = 1;
}
for (let i = 0; fileBuffer.readable > 0; i++) {
let nextSector = 0;
let writableDataLength = 0;
if (nextSector === 0) {
nextSector =
(filestoreChannels.dataChannel.length + (exports.sectorLength - 1)) /
exports.sectorLength;
if (nextSector === 0) {
nextSector++;
}
if (nextSector === sector) {
nextSector++;
}
}
let writableMax;
if (0xffff < fileId) {
writableMax = 510;
writeBuffer.put(fileId, 'INT');
}
else {
writableMax = 512;
writeBuffer.put(fileId, 'SHORT');
}
if (fileBuffer.readable <= writableMax) {
nextSector = 0;
}
writeBuffer.put(i, 'SHORT');
writeBuffer.put(nextSector, 'INT24');
writeBuffer.put(indexId);
filestoreChannels.dataChannel.writerIndex = exports.sectorLength * sector;
// Ensure space
if (filestoreChannels.dataChannel.length <
filestoreChannels.dataChannel.writerIndex + writeBuffer.length) {
const newBuffer = new common_1.ByteBuffer(filestoreChannels.dataChannel.writerIndex + writeBuffer.length);
filestoreChannels.dataChannel.copy(newBuffer, 0, 0, filestoreChannels.dataChannel.length);
newBuffer.writerIndex = filestoreChannels.dataChannel.writerIndex;
filestoreChannels.dataChannel = newBuffer;
}
// Write the header
filestoreChannels.dataChannel.putBytes(writeBuffer.getSlice(0, 8));
writableDataLength = fileBuffer.readable;
if (writableDataLength > writableMax) {
writableDataLength = writableMax;
}
writeBuffer.putBytes(fileBuffer.getSlice(fileBuffer.readerIndex, writableDataLength));
fileBuffer.readerIndex += writableDataLength;
// Ensure space
if (filestoreChannels.dataChannel.length <
filestoreChannels.dataChannel.writerIndex + writeBuffer.length) {
const newBuffer = new common_1.ByteBuffer(filestoreChannels.dataChannel.writerIndex + writeBuffer.length);
filestoreChannels.dataChannel.copy(newBuffer, 0, 0, filestoreChannels.dataChannel.length);
newBuffer.writerIndex = filestoreChannels.dataChannel.writerIndex;
filestoreChannels.dataChannel = newBuffer;
}
// Write the sector
filestoreChannels.dataChannel.putBytes(writeBuffer.getSlice(writeBuffer.readerIndex, writeBuffer.length - writeBuffer.readerIndex));
sector = nextSector;
}
};
exports.writeDataChunk = writeDataChunk;