|
|
|
// import { base64decode, base64encode, base64ToBytes } from './base64.js';
|
|
|
|
|
|
|
|
// https://github.com/nesbox/TIC-80/wiki/TIC-File-Format
|
|
|
|
export const CHUNK_TILES = 1,
|
|
|
|
CHUNK_SPRITES = 2,
|
|
|
|
CHUNK_COVER = 3,
|
|
|
|
CHUNK_MAP = 4,
|
|
|
|
CHUNK_CODE = 5,
|
|
|
|
CHUNK_FLAGS = 6,
|
|
|
|
CHUNK_SAMPLES = 9,
|
|
|
|
CHUNK_WAVEFORM = 10,
|
|
|
|
CHUNK_PALETTE = 12,
|
|
|
|
CHUNK_MUSIC_TRACKS = 14,
|
|
|
|
CHUNK_MUSIC_PATTERNS = 15,
|
|
|
|
CHUNK_CODE_ZIP = 16,
|
|
|
|
LITTLE_ENDIAN = 1;
|
|
|
|
|
|
|
|
function pad0(n, p) {
|
|
|
|
n = ''+n;
|
|
|
|
while (n.length < p) { n = '0'+n; }
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
function tohex (a) {
|
|
|
|
let ret = '', hh;
|
|
|
|
console.log("tohex", a);
|
|
|
|
for (var b=0, len=a.byteLength; b<len; b+=1) {
|
|
|
|
ret += pad0(a.getUint8(b).toString(16), 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// export function ensure_Uint8Array (buf) {
|
|
|
|
// if (buf instanceof Int8Array) {
|
|
|
|
// console.log("Signed data");
|
|
|
|
// var ret = new Uint8Array(buf.byteLength),
|
|
|
|
// data = new DataView(ret.buffer);
|
|
|
|
// data.setUint8
|
|
|
|
// }
|
|
|
|
// return buf;
|
|
|
|
// }
|
|
|
|
|
|
|
|
export function parsetic (buf) {
|
|
|
|
if (!(buf instanceof Uint8Array)) {
|
|
|
|
console.log("ERROR buf is not UInt8Array");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var ret = {},
|
|
|
|
data = new DataView(buf.buffer),
|
|
|
|
i=0,
|
|
|
|
bank,
|
|
|
|
ctype,
|
|
|
|
clen,
|
|
|
|
future_use;
|
|
|
|
|
|
|
|
ret.chunks = [];
|
|
|
|
ret.chunks_by_type = {};
|
|
|
|
while (i<buf.length) {
|
|
|
|
bank = buf[i] >> 5;
|
|
|
|
ctype = buf[i] & 0b11111;
|
|
|
|
i+=1;
|
|
|
|
clen = data.getUint16(i, LITTLE_ENDIAN);
|
|
|
|
i+=2;
|
|
|
|
future_use = buf[i];
|
|
|
|
i+=1; // byte reserved for future_use
|
|
|
|
var chunk = {bank: bank, ctype: ctype, future_use: future_use};
|
|
|
|
chunk.original_length = clen; // can be out of sync with data, only for control purposes
|
|
|
|
ret.chunks.push(chunk);
|
|
|
|
ret.chunks_by_type[ctype] = chunk;
|
|
|
|
var chunk_data = buf.slice(i, i+clen);
|
|
|
|
if (ctype == CHUNK_CODE) {
|
|
|
|
ret.code = chunk;
|
|
|
|
chunk.text = new TextDecoder().decode(chunk_data);
|
|
|
|
} else {
|
|
|
|
//chunk.data = new DataView(buf.buffer, i, clen);
|
|
|
|
chunk.data = chunk_data;
|
|
|
|
}
|
|
|
|
i += clen;
|
|
|
|
// chunk.data = base64encode(chunk.data);
|
|
|
|
}
|
|
|
|
ret.tobuffer = function () {
|
|
|
|
// dry run for length
|
|
|
|
var outputLength = 0;
|
|
|
|
ret.chunks.forEach(chunk => {
|
|
|
|
outputLength += 4;
|
|
|
|
outputLength += (chunk.text) ? new TextEncoder().encode(chunk.text).byteLength : chunk.data.byteLength;
|
|
|
|
});
|
|
|
|
var outputBuffer = new Uint8Array(outputLength),
|
|
|
|
o = 0,
|
|
|
|
data = new DataView(outputBuffer.buffer);
|
|
|
|
|
|
|
|
ret.chunks.forEach(chunk => {
|
|
|
|
data.setUint8(o++, (chunk.bank << 5) | chunk.ctype);
|
|
|
|
var chunk_data = chunk.text ? new TextEncoder().encode(chunk.text) : chunk.data;
|
|
|
|
data.setUint16(o, chunk_data.byteLength, 1);
|
|
|
|
o += 2;
|
|
|
|
data.setUint8(o++, chunk.future_use);
|
|
|
|
for (var i=0; i<chunk_data.byteLength; i++) {
|
|
|
|
data.setUint8(o++, chunk_data[i]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return outputBuffer;
|
|
|
|
};
|
|
|
|
return ret;
|
|
|
|
}
|