Skip to content

Instantly share code, notes, and snippets.

@yne
Last active December 3, 2024 15:56
Show Gist options
  • Save yne/21648c9e48d9e9ef84f3d303d1185c96 to your computer and use it in GitHub Desktop.
Save yne/21648c9e48d9e9ef84f3d303d1185c96 to your computer and use it in GitHub Desktop.
615A 8002/8004 LUH JSON dumper
// BUILD:
// cc luh.c -o luh
// USAGE:
// luh < EXAMPLE.LUH > EXAMPLE.json
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
uint16_t crc16_tab[256];
void crc16_init() {
uint16_t i,j,c;// to please c89 gods
for (i = 0; i < sizeof(crc16_tab) / sizeof(*crc16_tab); i++)
for (j = 0, c = i << 8; j < 8; j++, c = c << 1)
crc16_tab[i] = ( crc16_tab[i] << 1 ) ^ ( (crc16_tab[i] ^ c) & 0x8000 ? 0x1021 : 0);
}
uint16_t crc16 = 0xFFFF;
void crc16_digest(uint8_t data) {
crc16 = (crc16 << 8) ^ crc16_tab[((crc16 >> 8) ^ data) & 0xFF];
}
uint32_t crc32_tab[256];
void crc32_init() {
uint32_t i,j;// to please c89 gods
for (i = 0; i < sizeof(crc32_tab) / sizeof(*crc32_tab); i++)
for (j = 0, crc32_tab[i] = i << 24; j < 8; j++)
crc32_tab[i] = crc32_tab[i] & 0x80000000 ? crc32_tab[i] << 1 ^ 0x04C11DB7 : crc32_tab[i] << 1;
}
uint32_t crc32 = 0xFFFFFFFF;
void crc32_digest(uint8_t data) {
crc32 = (crc32 << 8) ^ crc32_tab[(( crc32 >> 24) ^ data) & 0xFF];
}
char* hash(char* path, void (*digest)(uint8_t)) {
uint8_t c;
int fd = open(path,0);
if(fd < 0)return path;
while(read(fd,&c,sizeof(c)) > 0)digest(c);
close(fd);
return NULL;
}
size_t get_total = 0;//total read
uint8_t get() {
uint8_t c;
if(read(0, &c, sizeof(c)) == EOF) exit(c);
get_total += sizeof(c);
crc16_digest(c);
crc32_digest(c);
return c;
}
int indent=0, iter[10]={0};
void attr(char*name){printf("%s\n%*s%s%s%s", iter[indent]++?",":"",4*indent,"", *name?"\"":"",name, *name?"\": ":"");}
void obj_init(char*name){attr(name);printf("{");indent++;}
void arr_init(char*name){attr(name);printf("[");indent++;}
void obj_fini(){iter[indent]=0;printf("\n%*s}",4*--indent,"");}
void arr_fini(){iter[indent]=0;printf("\n%*s]",4*--indent,"");}
size_t hex(size_t bit, char*name) {
size_t acc=0;
attr(name);
for(; bit >= 8; bit -= 8) {
uint8_t c = get();
// printf("%02X", c);
acc = c | (acc << 8);
}
printf("%i",acc);
return acc;
}
typedef struct {char str[4096];size_t len;} String;
String last_str;
void str(size_t byte, char*name) {
attr(name); printf("\"");
size_t pad = byte & 0x01;
for(last_str.len=0;byte--;last_str.len++) {
char c = get();
printf("%c", c);
last_str.str[last_str.len]=c;
}
last_str.str[last_str.len] = '\0';
printf("\"");
while(pad--) {
get();//fprintf(stderr," # 0x%02X", get());
}
}
size_t jump(size_t to) {
if (to) {
//printf("\n-- jump %i Bytes to 0x%X (%08X)\n", to - get_total, to, to/sizeof(uint16_t));
while(get_total<to)get();//fprintf(stderr," # 0x%02X",get());
}
return to;
}
int next(size_t*pointers, size_t count) {
int i,min=~0,ret = 0;
for (i = 0; i < count; i++) {
if ((pointers[i]*2) >= get_total && pointers[i] < min) {
min = pointers[i];
ret = i;
}
}
// printf("\n-- next section from %04X is [%i] %04X\n",get_total, ret, pointers[ret]*2);
return ret;
}
String paths[256];
size_t paths_total;
void parse8004(){
size_t s,t,u, type;
hex(16, "partFlags");
obj_init("pointers");
size_t pointers[] = {
0, // use section[0] as special case to break the while
hex(32, "loadPnLength"),
hex(32, "numberOfTargetHWID"),
hex(32, "numberOfDataFiles"),
hex(32, "numberOfSupportFiles"),
hex(32, "userDefinedData"),
hex(32, "loadTypeDescriptionLength"),
hex(32, "numberOfTargetHWIDWithPositions"),
hex(32, "loadCheckValueLength"),
};
obj_fini();
while((type=next(pointers, sizeof(pointers)/sizeof(*pointers)))){
jump(pointers[type]*2);
switch (type){
case 1:
s=hex(16,"loadPnLength");
str(s?:1,"loadPn");/* s?:1 because "One or more 16-bit words" (Note1) */
break;
case 6://pointer order are different than field definition order in the spec
s=hex(16,"loadTypeDescriptionLength");
str(s, "loadTypeDescription");
hex(16, "loadTypeID");
break;
case 2:
s=hex(16,"targetHWIDTotal");
arr_init("targetHWID");
while(s--) {
obj_init("");
t=hex(16, "length");
str(t?:1, "value");
obj_fini();
}
arr_fini();
break;
case 7://strange definition order
s=hex(16, "targetHWIDWithPositionsTotal");
arr_init("targetHWIDWithPositions");
while(s--) {
obj_init("");
t=hex(16, "targetHWIDLength");
str(t?:1, "targetHWID");
t=hex(16, "positionsTotal");
arr_init( "positions");
while(t--) {
obj_init("");
u=hex(16, "length");
str(u?:1, "value");
obj_fini();
}
arr_fini();
obj_fini();
}
arr_fini();
break;
case 3:
s=hex(16, "dataFileTotal");
arr_init("dataFile");
while(s--) {
obj_init("");
hex(16, "pointer");
t=hex(16,"nameLength");
str(t?:1,"name");
paths[paths_total++] = last_str; // printf("[%.*s]\n", last_str.len, last_str.str);
t=hex(16,"pnLength");
str(t?:1,"pn");
hex(32, "length");
hex(16, "crc");
{
uint16_t crc16_bkp = crc16;
crc16 = 0xFFFF; // need a fresh start on this file
attr("crc__expected");
char* missing = hash(paths[paths_total-1].str, crc16_digest);
if (missing) {
printf("\"%s:%s\"", missing, strerror(errno));
} else {
printf("\"0x%04X\"", crc16);
}
crc16 = crc16_bkp;
}
hex(64, "lengthBytes");
t=hex(16,"checkValueLength");
if (t) { // "Omit if Data File Check Value Length is set to 0x0000"
hex(16, "checkValueType");
str(t?:1,"checkValue");
}
obj_fini();
}
arr_fini();
break;
case 4:
s=hex(16, "supportFilesTotal");
arr_init("supportFiles");
while(s--) {
obj_init("");
hex(16, "pointer");
t=hex(16,"nameLength");
str(t, "name"); // 0
t=hex(16,"pnLength");
str(t, "pn"); // 0
hex(32, "length");
hex(16, "crc");
t=hex(16,"checkValueLength");
if (t) { // "Omit if Support File Check Value Length is set to 0x0000"
hex(16, "checkValueType");
str(t?:1,"checkValue");
}
obj_fini();
}
arr_fini();
break;
case 5:
hex(16, "userDefinedData");
break;
case 8:
t=hex(16, "loadCheckValueLength");
if (t) { // "Omit if Load Check Value Length is set to 0x0000"
hex(16, "loadCheckValueType");
hex(16, "loadCheckValue");
}
uint16_t expected16 = crc16;
hex(16, "headerFileCrc");
attr("headerFileCrc__expected");
printf("%i", expected16);
char* missing = NULL;
for (s = 0; s < paths_total && missing==NULL; s++) {
missing = hash(paths[s].str, crc32_digest);
}
uint32_t expected32 = crc32; // save it before reading anymore data !
hex(32, "loadCrc");
attr("loadCrc__expected");
if (missing) {
printf("\"%s:%s\"", missing, strerror(errno));
} else {
printf("%i", ~expected32);
}
break;
}
}
attr("__read_bytes");printf("%zu", get_total);
attr("__read_hword");printf("%zu", get_total/2);
// fprintf(stderr,"\n# total read: %zuBytes (0x%lXh)\n", get_total, get_total/2);
}
// I can't find the ARINC spec for this version, let's blind guess every field
void parse8002(){
size_t s,t,type;
obj_init("pointers");
size_t pointers[] = {
0, // use section[0] as special case to break the while
hex(32, "loadPnLength"),
hex(32, "numberOfTargetHWID"),
hex(32, "numberOfDataFiles"),
hex(32, "numberOfSupportFiles"),
hex(32, "userDefinedData"),
};
obj_fini();
while((type=next(pointers, sizeof(pointers)/sizeof(*pointers)))){
jump(pointers[type]*2);
switch (type){
case 1:
s=hex(16,"loadPnLength");
str(s?:1,"loadPn");/* s?:1 because "One or more 16-bit words" (Note1) */
break;
case 2:
s=hex(16,"targetHWIDTotal");
arr_init("targetHWID");
while(s--) {
t=hex(16, "length");
str(t?:1, "value");
}
arr_fini();
break;
case 3:
s=hex(16, "fataFilesTotal");
//attr("DataFiles")
arr_init("fataFiles");
while(s--) {
obj_init("");
hex(16, "pointer");
t=hex(16,"nameLength");
str(t?:1,"name");
t=hex(16,"pnLength");
str(t?:1,"pn");
hex(32, "length");
hex(16, "crc");
obj_fini();
}
arr_fini();
break;
default:
fprintf(stderr,"\n# unhandled pointer[%zu]@0x%lX\n",type,get_total);
return;
}
}
hex(16, "userDataPointer:");
hex(16, "crc1:");
hex(16, "crc2:");
hex(16, "crc3:");
fprintf(stderr,"\n# total read: %zuBytes (0x%lXh)\n", get_total, get_total/2);
}
int main(int argc, char**argv) {
if (isatty(0)) {
return fprintf(stderr, "USAGE:\n\t%s < sample.LUH\n", argv[0]);
}
crc16_init();
crc32_init();
obj_init("");
hex(32, "headerFileLength");
uint32_t version = hex(16, "loadFileFormatVersion");
if (version==0x8004) parse8004();
else if (version==0x8002) parse8002();
else printf("\"error\":\"unsupported LUH version %04X\"", version);
obj_fini();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment