@bitblit/asyncglk
Version:
A Typescript Glk library
71 lines (67 loc) • 2.17 kB
JavaScript
/*
Interchange File Format
=======================
Copyright (c) 2022 Dannii Willis
MIT licenced
https://github.com/curiousdannii/asyncglk
*/
import { FileView } from '../common/misc.js';
/** An Interchange File Format reader and writer */
export class IFF {
type = '';
chunks = [];
parse(data) {
const view = new FileView(data);
// Check this is actually an IFF file
if (view.getFourCC(0) !== 'FORM') {
throw new Error('Not an IFF file');
}
// Parse the file
this.type = view.getFourCC(8);
let i = 12;
// Adrift 5 Blorbs have an incorrect length, so just use the size of the buffer
//const length = view.getUint32(4) + 8
const length = data.length;
while (i < length) {
const chunk_length = view.getUint32(i + 4);
if (chunk_length < 0 || (chunk_length + i) > length) {
throw new Error('IFF chunk out of range');
}
this.chunks.push({
data: view.getUint8Subarray(i + 8, chunk_length),
offset: i,
type: view.getFourCC(i),
});
i += 8 + chunk_length;
if (i % 2) {
i++;
}
}
}
write() {
// First calculate the required buffer length
let buffer_length = 12;
for (const chunk of this.chunks) {
buffer_length += 8 + chunk.data.length;
if (buffer_length % 2) {
buffer_length++;
}
}
// Now make the IFF file and return it
const view = new FileView(new ArrayBuffer(buffer_length));
view.setFourCC(0, 'FORM');
view.setUint32(4, buffer_length - 8);
view.setFourCC(8, this.type);
let i = 12;
for (const chunk of this.chunks) {
view.setFourCC(i, chunk.type);
view.setUint32(i + 4, chunk.data.length);
view.setUint8Array(i + 8, chunk.data);
i += 8 + chunk.data.length;
if (i % 2) {
i++;
}
}
return view.getUint8Subarray();
}
}