UNPKG

compound-binary-file-js

Version:

This is an implementation of [Compound Binary File v.3](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/53989ce4-7b05-4f8d-829b-d08d6148375b) \ Allows reading existing files, creation of the/write operation

76 lines (65 loc) 2.84 kB
import {CFDataview} from "./СFDataview"; import {ReferencingSubview} from "./ReferencingSubview"; import {SimpleDataview} from "./SimpleDataview"; import {initializedWidth} from "../utils"; /** * @internal */ export class FixedSizeChunkedDataview implements CFDataview { private readonly chunkSize: number; private readonly chunks: CFDataview[] = []; constructor(chunkSize: number, dataChunks?: number[]|CFDataview[]) { this.chunkSize = chunkSize; if(dataChunks != null) { if(typeof dataChunks[0] === 'number') { if(dataChunks.length % chunkSize !== 0) throw new Error(`The passed bytes array should be divisible by chunk size. Actual array size : ${dataChunks.length}; chunk size: ${chunkSize}.`); const dataLength = dataChunks.length; const rawView = new SimpleDataview(dataChunks as number[]); for (let i = 0; i < dataLength; i += 512) { this.chunks.push(new ReferencingSubview(rawView, i, i + 512)); } } else { this.chunks.push(...(dataChunks as CFDataview[])); } } } writeAt(position: number, bytes: number[]): CFDataview { return this.chunks[Math.floor(position / 512)].writeAt(position%512, bytes); } getSize(): number { return this.chunks.length * this.chunkSize; } getData(): number[] { const result: number[] = []; for (const chunk of this.chunks) { result.push(...chunk.getData()); } return result; } subView(start: number, end?: number): CFDataview { if(end == null) throw new Error("'end' parameter is mandatory"); if(Math.floor(start/this.chunkSize) !== Math.floor((end - 1)/this.chunkSize)) throw new Error(`Can only get subview enclosed by one chunk. Actual values: ${start} - ${end}`); if(start === end) throw new Error("Cannot get subview of size 0"); const chunk = this.chunks[Math.floor(start / this.chunkSize)]; if(end % this.chunkSize === 0) { return chunk.subView(start % this.chunkSize); } else { return chunk.subView(start % this.chunkSize, end % this.chunkSize); } } allocate(length: number): CFDataview { if (length !== this.chunkSize) throw new Error(); const view = new SimpleDataview(initializedWidth(length, 0)); this.chunks.push(view); return view; } fill(filler: number[]): CFDataview { throw new Error("Unsupported operation"); } readAt(position: number, length: number): number[] { throw new Error("Unsupported operation"); } isEmpty(): boolean { return false; } }