src/binary_text.js
var fs = require("fs");
function createSauce(columns, rows, datatype, filetype, filesize, doFlagsAndTInfoS, iceColours, letterSpacing) {
function addText(text, maxlength, index) {
var i;
for (i = 0; i < maxlength; i += 1) {
sauce[i + index] = (i < text.length) ? text.charCodeAt(i) : 0x20;
}
}
var sauce = new Uint8Array(129);
sauce[0] = 0x1A;
sauce.set(new Uint8Array([0x53, 0x41, 0x55, 0x43, 0x45, 0x30, 0x30]), 1);
addText("", 35, 8);
addText("", 20, 43);
addText("", 20, 63);
var date = new Date();
addText(date.getFullYear().toString(10), 4, 83);
var month = date.getMonth() + 1;
addText((month < 10) ? ("0" + month.toString(10)) : month.toString(10), 2, 87);
var day = date.getDate();
addText((day < 10) ? ("0" + day.toString(10)) : day.toString(10), 2, 89);
sauce[91] = filesize & 0xFF;
sauce[92] = (filesize >> 8) & 0xFF;
sauce[93] = (filesize >> 16) & 0xFF;
sauce[94] = filesize >> 24;
sauce[95] = datatype;
sauce[96] = filetype;
sauce[97] = columns & 0xFF;
sauce[98] = columns >> 8;
sauce[99] = rows & 0xFF;
sauce[100] = rows >> 8;
sauce[105] = 0;
if (doFlagsAndTInfoS === true) {
var flags = 0;
if (iceColours === true) {
flags += 1;
}
if (letterSpacing === false) {
flags += (1 << 1);
} else {
flags += (1 << 2);
}
sauce[106] = flags;
var fontName = "IBM VGA";
addText(fontName, fontName.length, 107);
}
return sauce;
}
function convert16BitArrayTo8BitArray(Uint16s) {
var Uint8s = new Uint8Array(Uint16s.length * 2);
for (var i = 0, j = 0; i < Uint16s.length; i++, j += 2) {
Uint8s[j] = Uint16s[i] >> 8;
Uint8s[j + 1] = Uint16s[i] & 255;
}
return Uint8s;
}
function bytesToString(bytes, offset, size) {
var text = "", i;
for (i = 0; i < size; i++) {
text += String.fromCharCode(bytes[offset + i]);
}
return text;
}
function getSauce(bytes, defaultColumnValue) {
var sauce, fileSize, dataType, columns, rows, flags;
function removeTrailingWhitespace(text) {
return text.replace(/\s+$/, "");
}
if (bytes.length >= 128) {
sauce = bytes.slice(-128);
if (bytesToString(sauce, 0, 5) === "SAUCE" && bytesToString(sauce, 5, 2) === "00") {
fileSize = (sauce[93] << 24) + (sauce[92] << 16) + (sauce[91] << 8) + sauce[90];
dataType = sauce[94];
if (dataType === 5) {
columns = sauce[95] * 2;
rows = fileSize / columns / 2;
} else {
columns = (sauce[97] << 8) + sauce[96];
rows = (sauce[99] << 8) + sauce[98];
}
flags = sauce[105];
return {
"title": removeTrailingWhitespace(bytesToString(sauce, 7, 35)),
"author": removeTrailingWhitespace(bytesToString(sauce, 42, 20)),
"group": removeTrailingWhitespace(bytesToString(sauce, 62, 20)),
"fileSize": (sauce[93] << 24) + (sauce[92] << 16) + (sauce[91] << 8) + sauce[90],
"columns": columns,
"rows": rows,
"iceColours": (flags & 0x01) === 1,
"letterSpacing": (flags >> 1 & 0x02) === 2
};
}
}
return {
"title": "",
"author": "",
"group": "",
"fileSize": bytes.length,
"columns": defaultColumnValue,
"rows": undefined,
"iceColours": false,
"letterSpacing": false
};
}
function convertUInt8ToUint16(uint8Array, start, size) {
var i, j;
var uint16Array = new Uint16Array(size / 2);
for (i = 0, j = 0; i < size; i += 2, j += 1) {
uint16Array[j] = (uint8Array[start + i] << 8) + uint8Array[start + i + 1];
}
return uint16Array;
}
function load(filename, callback) {
fs.readFile(filename, (err, bytes) => {
var sauce = getSauce(bytes, 160);
var data;
if (err) {
saveImageData();
} else {
data = convertUInt8ToUint16(bytes, 0, sauce.columns * sauce.rows * 2);
callback({
"columns": sauce.columns,
"rows": sauce.rows,
"data": data,
"iceColours": sauce.iceColours,
"letterSpacing": sauce.letterSpacing
});
}
});
}
function save(filename, imageData, callback) {
var data = convert16BitArrayTo8BitArray(imageData.data);
var sauce = createSauce(0, 0, 5, imageData.columns / 2, data.length, true, imageData.iceColours, imageData.letterSpacing);
output = new Uint8Array(data.length + sauce.length);
output.set(data, 0);
output.set(sauce, data.length);
fs.writeFile(filename, Buffer.from(output.buffer), () => {
if (callback !== undefined) {
callback();
}
});
}
module.exports = {
"load": load,
"save": save
};