UNPKG

@runejs/filestore

Version:

Tools for managing the RuneJS filestore.

155 lines (154 loc) 7.07 kB
"use strict"; 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;