Skip to content

Instantly share code, notes, and snippets.

@Kattoor
Created September 12, 2021 10:05
Show Gist options
  • Save Kattoor/bf9ff15c87478a6de6eabb811d04e681 to your computer and use it in GitHub Desktop.
Save Kattoor/bf9ff15c87478a6de6eabb811d04e681 to your computer and use it in GitHub Desktop.
const fs = require('fs');
const data = fs.readFileSync('out/javelindata_areadefinitions.datasheet');
const amountOfColumnsOffset = 0x44;
const amountOfRowsOffset = 0x48;
const headersOffset = 0x5c;
const amountOfBytesInHeader = 12;
const amountOfBytesInCell = 8;
const amountOfColumns = data.readInt32LE(amountOfColumnsOffset);
const amountOfRows = data.readInt32LE(amountOfRowsOffset);
const cellsOffset = headersOffset + amountOfColumns * amountOfBytesInHeader;
const amountOfBytesInRow = amountOfBytesInCell * amountOfColumns;
const stringsOffset = cellsOffset + amountOfRows * amountOfColumns * amountOfBytesInCell;
const headers = [];
for (let i = 0; i < amountOfColumns; i++) {
const headerOffset = headersOffset + i * amountOfBytesInHeader;
const stringValue = readStringValue(headerOffset);
const text = readCString(data, stringsOffset, stringValue.stringOffset);
const type = data.readInt32LE(headerOffset + 8);
headers.push({text, type});
}
const rows = [];
for (let i = 0; i < amountOfRows; i++) {
const cells = [];
for (let j = 0; j < amountOfColumns; j++) {
const cellOffset = cellsOffset + i * amountOfBytesInRow + j * amountOfBytesInCell;
const cellValue = readCell(cellOffset);
const columnType = headers[j].type;
cells.push(parseCellValueToType(cellValue, columnType));
}
rows.push(cells);
}
function handleInnerComma(text) {
if (typeof text !== 'string') {
return text;
}
if (text.includes(',')) {
return `"${text}"`;
} else {
return text;
}
}
function toCsv(headers, rows) {
return [
headers.map(header => handleInnerComma(header.text)).join(','),
...rows.map(cells => cells.map(handleInnerComma).join(','))
].join('\n');
}
fs.writeFileSync('./output.csv', toCsv(headers, rows));
function readCString(data, stringsOffset, value) {
const offset = stringsOffset + value.readInt32LE(0);
let lengthUntilNullTermination = 0;
let nextByte;
do {
nextByte = data.readInt8(offset + lengthUntilNullTermination++);
} while (nextByte !== 0)
if (lengthUntilNullTermination === 1) {
return null;
}
return data.slice(offset, offset + lengthUntilNullTermination - 1).toString();
}
function parseCellValueToType(cellValue, type) {
switch (type) {
case 1:
return readCString(data, stringsOffset, cellValue);
case 2:
return cellValue.readFloatLE(0);
case 3:
return !!cellValue.readInt32LE(0);
}
}
function readCell(offset) {
const stringOffset = data.readInt32LE(offset);
const cellValue = data.slice(offset + 4, offset + 8);
return cellValue;
}
function readStringValue(offset) {
const hash = data.slice(offset, offset + 4);
const stringOffset = data.slice(offset + 4, offset + 8);
return {hash, stringOffset};
}
@twitdude
Copy link

Any chance you can also change this so instead of it just focused on one file 'out/javelindata_areadefinitions.datasheet'

You make it so it checks all the files in that folder like '*.datasheet' and converts them all ?

I have been using this but I have to manually change the name for each datasheet file and Im not sure how to code it to work the other way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment