
/*

eldapend.c - Append ELD to a file

2024 by E. C. Masloch

Public Domain

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <inttypes.h>

#define BUFFERSIZE 8192
uint8_t buffer[BUFFERSIZE];
uint8_t trailer[16];

int main(int argc, char ** argv) {
  FILE * dst = NULL;
  FILE * src = NULL;
  uint32_t cc, ii, total = 0, offset, checksum, dstsize;
  if (argc != 3) {
    printf("usage: eldapend file.bin file.eld\n");
    return 1;
  }
  dst = fopen(argv[1], "r+b");
  if (!dst) {
    printf("Error: Failed to open destination file!\n");
    return 2;
  }
  src = fopen(argv[2], "rb");
  if (!src) {
    printf("Error: Failed to open source file!\n");
    fclose(dst);
    return 3;
  }
  fseek(dst, 0, SEEK_END);
  dstsize = ftell(dst);
  if (dstsize >= 16 + 32) {
    fseek(dst, -16, SEEK_CUR);
    cc = fread(buffer, 1, 16, dst);
    if (cc != 16) {
      printf("Error: Failed to read destination file!"
        " c=%"PRIu32"\n", cc);
      fclose(src);
      fclose(dst);
      return 7;
    }
    if (! memcmp(buffer, "ELD1TAIL", 8) ) {
      printf("Error: Destination file already has an ELD trailer!\n");
      fclose(src);
      fclose(dst);
      return 8;
    }
    fseek(dst, 0, SEEK_END);
  }
  for (;;) {
    cc = BUFFERSIZE;
    ii = fread(buffer, 1, cc, src);
    if (!ii) {
      break;
    }
    cc = fwrite(buffer, 1, ii, dst);
    if (ii != cc) {
      printf("Error: Failed to write ELD fragment to file!"
        " i=%"PRIu32" c=%"PRIu32" total=%"PRIu32"\n", ii, cc, total);
      fclose(src);
      fclose(dst);
      return 4;
    }
    total += cc;
    if (total < cc) {
      printf("Error: Internal error, total overflowed!"
        " i=%"PRIu32" c=%"PRIu32" total=%"PRIu32"\n", ii, cc, total);
      fclose(src);
      fclose(dst);
      return 6;
    }
  }
  memcpy(trailer, "ELD1TAIL", 8);
  offset = - total;
  trailer[ 8] = (offset >>  0) & 255;
  trailer[ 9] = (offset >>  8) & 255;
  trailer[10] = (offset >> 16) & 255;
  trailer[11] = (offset >> 24) & 255;
  for (ii = 0, cc = 0; cc < 14; cc += 2) {
    ii += trailer[cc] + trailer[cc + 1] * 256;
  }
  checksum = - ii;
  trailer[14] = (checksum >> 0) & 255;
  trailer[15] = (checksum >> 8) & 255;
  printf("At %"PRIu32" bytes:"
    " Write %"PRIu32" bytes ELD + 16 bytes ELD trailer"
    ", checksum=%04"PRIX32".\n", dstsize, total, checksum & 0xFFff);
  cc = fwrite(trailer, 1, 16, dst);
  if (cc != 16) {
    printf("Error: Failed to write ELD trailer to file!"
      " c=%"PRIu32" total=%"PRIu32"\n", cc, total);
    fclose(src);
    fclose(dst);
    return 5;
  }
  fclose(src);
  fclose(dst);
  return 0;
}
