Skip to content

Instantly share code, notes, and snippets.

@yne
Last active May 8, 2023 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • 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 validator and YAML dumper
// BUILD:
// cc luh.c -o luh
// USAGE:
// luh < EXAMPLE.LUH > EXAMPLE.yml
#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];
}
void hash(char* path, void (*digest)(uint8_t)) {
uint8_t c;
int fd = open(path,0);
if(fd < 0)printf("\n# unable to digest ./%s: %s", path, strerror(errno));
while(read(fd,&c,sizeof(c)) > 0)digest(c);
close(fd);
}
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;
}
size_t hex(size_t bit, char*name) {
size_t acc=0;
printf("\n%-50s: 0x", name);
for(; bit >= 8; bit -= 8) {
uint8_t c = get();
printf("%02X", c);
acc = c | (acc << 8);
}
return acc;
}
typedef struct {char str[4096];size_t len;} String;
String last_str;
void str(size_t byte, char*name) {
printf("\n%-50s: ", name);
size_t pad = byte & 0x01;
printf("\"");
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--) {
printf(" # 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)printf(" # 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;
int parse8004(){
size_t s,t,u, type;
hex(16, "Part Flags");
size_t pointers[] = {
0, // use section[0] as special case to break the while
hex(32, "Pointer to Load PN Length"),
hex(32, "Pointer to Number of Target HW IDs"),
hex(32, "Pointer to Number of Data Files"),
hex(32, "Pointer to Number of Support Files"),
hex(32, "Pointer to User Defined Data"),
hex(32, "Pointer to Load Type Description Length"),
hex(32, "Pointer to Number of Target HW ID with Positions"),
hex(32, "Pointer to Load Check Value Length"),
};
while((type=next(pointers, sizeof(pointers)/sizeof(*pointers)))){
jump(pointers[type]*2);
switch (type){
case 1:
s=hex(16,"Load PN Length");
str(s?:1,"Load PN");/* 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,"Load Type Description Length");
str(s,"Load Type Description");
hex(16, "Load Type ID");
break;
case 2:
s=hex(16,"Target HW IDs Total");
printf("\nTarget HW IDs:");
while(s--) {
printf("\n-");
t=hex(16, " Target HW ID Length");
str(t?:1, " Target HW ID");
}
break;
case 7://strange definition order
s=hex(16, "Number of Target HW ID with Positions");
while(s--) {
printf("\n-");
t=hex(16, " Target HW ID with Positions Length");
str(t?:1, " Target HW ID with Positions");
t=hex(16, " Target HW ID Positions Total");
printf("\n Target HW ID Positions:");
while(t--) {
printf("\n -");
u=hex(16, " Position Length");
str(u?:1, " Position");
}
}
break;
case 3:
s=hex(16, "Data Files Total");
printf("\nData Files:");
while(s--) {
printf("\n-");
hex(16, " Data File Pointer");
t=hex(16," Data File Name Length");
str(t?:1," Data File Name");
paths[paths_total++] = last_str; // printf("[%.*s]\n", last_str.len, last_str.str);
t=hex(16," Data File PN Length");
str(t?:1," Data File PN");
hex(32, " Data File Length");
hex(16, " Data File CRC");
{
uint16_t crc16_bkp = crc16;
crc16 = 0xFFFF; // need a fresh start on this file
hash(paths[paths_total-1].str, crc16_digest);
printf(" # expected=0x%04X", crc16);
crc16 = crc16_bkp;
}
hex(64, " Data File Length in Bytes");
t=hex(16," Data File Check Value Length");
if (t) { // "Omit if Data File Check Value Length is set to 0x0000"
hex(16, " Data File Check Value Type");
str(t?:1," Data File Check Value");
}
}
break;
case 4:
s=hex(16, "Support Files Total");
printf("\nSupport Files:");
while(s--) {
printf("\n-");
hex(16, " Support File Pointer");
t=hex(16," Support File Name Length");
str(t, " Support File Name"); // 0
t=hex(16," Support File PN Length");
str(t, " Support File PN"); // 0
hex(32, " Support File Length");
hex(16, " Support File CRC");
t=hex(16," Support File Check Value Length");
if (t) { // "Omit if Support File Check Value Length is set to 0x0000"
hex(16, " Support File Check Value Type");
str(t?:1," Support File Check Value");
}
}
break;
case 5:
hex(16, "User Defined Data");
break;
case 8:
t=hex(16, "Load Check Value Length");
if (t) { // "Omit if Load Check Value Length is set to 0x0000"
hex(16, "Load Check Value Type");
hex(16, "Load Check Value");
}
uint16_t expected16 = crc16;
hex(16, "Header File CRC");
printf(" # expected=0x%04X", expected16);
for(s = 0; s < paths_total; s++) {
hash(paths[s].str, crc32_digest);
}
uint32_t expected32 = crc32; // save it before reading anymore data !
hex(32, "Load CRC");
printf(" # expected=0x%08X", ~expected32);
break;
}
}
printf("\n# total read: %zuBytes (0x%lXh)\n", get_total, get_total/2);
return 0;
}
// I can't find the ARINC spec for this version, let's blind guess every field
int parse8002(){
size_t s,t,type;
size_t pointers[] = {
0, // use section[0] as special case to break the while
hex(32, "Pointer to Load PN Length"),
hex(32, "Pointer to Number of Target HW IDs"),
hex(32, "Pointer to Number of Data Files"),
hex(32, "Pointer to Number of Support Files"),
hex(32, "Pointer to User Defined Data"),
};
while((type=next(pointers, sizeof(pointers)/sizeof(*pointers)))){
jump(pointers[type]*2);
switch (type){
case 1:
s=hex(16,"Load PN Length");
str(s?:1,"Load PN");/* s?:1 because "One or more 16-bit words" (Note1) */
break;
case 2:
s=hex(16,"Target HW IDs Total");
printf("\nTarget HW IDs:");
while(s--) {
printf("\n-");
t=hex(16, " Target HW ID Length");
str(t?:1, " Target HW ID");
}
break;
case 3:
s=hex(16, "Data Files Total");
printf("\nData Files:");
while(s--) {
printf("\n-");
hex(16, " Data File Pointer");
t=hex(16," Data File Name Length");
str(t?:1," Data File Name");
t=hex(16," Data File PN Length");
str(t?:1," Data File PN");
hex(32, " Data File Length");
hex(16, " Data File CRC");
}
break;
default: return printf("\n# unhandled pointer[%zu]@0x%lX\n",type,get_total);
}
}
hex(16, "User Data Pointer:");
hex(16, "CRC1:");
hex(16, "CRC2:");
hex(16, "CRC3:");
printf("\n# total read: %zuBytes (0x%lXh)\n", get_total, get_total/2);
return 0;
}
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();
hex(32, "Header File Length");
uint32_t version = hex(16, "Load File Format Version");
if (version==0x8004) return parse8004();
if (version==0x8002) return parse8002();
return printf(" # version=%04X unsupported !!!\n", version);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment