/*
 * pdb2gb  -  Convert a palm database into a gameboy game image
 *            for use with Phoinix
 *
 *  2001-05-05 Bodo Wenzel (bodowenzel@web.de)    V1.0  quick-n-dirty
 *  2001-07-02 Julian Hsiao (madoka@novastar.com) V1.01 MacOS Classic mods
 *  Now CVS-History:
 *  $Log $
 */

/* NOTES:
 * This program should be extended...
 * Look into the source of gb2pdb for further information.
 */

#define DB_CREATOR  "Phnx"
#define DB_TYPE     "ROMU"

#define BUF_SIZE 32768U

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

typedef unsigned char ubyte;
typedef signed char sbyte;
typedef unsigned short uword;
typedef short word;
typedef unsigned long udword;
typedef long dword;

#ifdef __mac_os
#pragma options align=packed
#include <console.h>
#endif

typedef struct {
  ubyte name[32];
  uword fileAttributes;
  uword version;
  udword creationDate;
  udword modificationDate;
  udword lastBackupDate;
  udword modificationNumber;
  udword appInfoArea;
  udword sortInfoArea;
  ubyte databaseType[4];        
  ubyte creatorID[4];
  udword uniqueIDSeed;
  udword nextRecordListID;
  uword numberOfRecords;
}
#ifdef __GNUC__
  __attribute__ ((packed))
#endif
  PdbHeader;

typedef struct {
  udword recordDataOffset;
  ubyte recordAttributes;
  ubyte uniqueID[3];
}
#ifdef __GNUC__
  __attribute__ ((packed))
#endif
  RecHeader;

uword
ReadWord(void *addr) {
  ubyte *to = (ubyte*)addr;

  return (to[0]<<8) | to[1];
}

udword
ReadDWord(void *addr) {
  ubyte *to = (ubyte*)addr;

  return (to[0]<<24) | (to[1]<<16) | (to[2]<<8) | to[3];
}

char gb_buffer[BUF_SIZE];

int main(int argc, char **argv) {
  FILE *outfile, *infile;
  char *p,*outname;
  PdbHeader pdb_header;
  RecHeader rec_header;
  unsigned long offset;
  int n;

#ifdef __mac_os
  argc = ccommand(&argv);
#endif

  printf("pdb2gb for Phoinix V1.0 (c) 2001 by Bodo Wenzel\n");
  printf("Minor modifications for MacOS Classic compatibility by Julian Hsiao\n");
  
  if ((argc != 2) && (argc != 3)) {
    puts("usage: pdb2gb infile [outfile]");
    return 1;
  }

  infile = fopen(argv[1], "rb");
  if(infile == NULL) {
    printf("error: can't open input file '%s'\n", argv[1]);
    return 1;
  }

  /* read pdb header */
  fread(&pdb_header,sizeof(PdbHeader),1,infile);
  if (memcmp(pdb_header.databaseType, DB_TYPE, 4) != 0 ||
      memcmp(pdb_header.creatorID, DB_CREATOR, 4) != 0) {
    printf("error: input file '%s' doesn't look like a converted GB\n", argv[1]);
    return 1;
  }

  /* offset to data inside db */
  fread(&rec_header,sizeof(RecHeader),1,infile);
  offset = ReadDWord(&(rec_header.recordDataOffset));
  fseek(infile, 0l, SEEK_END);
  if (ftell(infile) < offset + BUF_SIZE) {
    printf("error: input file '%s' is too short\n", argv[1]);
    return 1;
  }
  n = (ftell(infile) - offset) / BUF_SIZE;
  fseek(infile, offset, SEEK_SET);

  /* create destination file name */
  if (argc == 2) {
    outname = (char*)malloc(strlen(argv[1]) + 4 + 1);
    if (outname == NULL) {
      puts("error: failed allocating memory");
      fclose(infile);
      return 1;
    }
    strcpy(outname, argv[1]);
    if ((p = strrchr(outname, '.')) != NULL)
      strcpy(p, ".gb");
    else
      strcat(outname, ".gb");
  } else
    outname = argv[2];

  /* open destination file */
  outfile = fopen(outname, "wb");
  if (outfile == NULL) {
    printf("error: can't open output file '%s'\n", outname);
    fclose(infile);
    return 1;
  }
  printf("writing '%s'\n", outname);

  /* now copy rom content */
  while (n--) {
    if (fread(gb_buffer, 1, BUF_SIZE, infile)!=BUF_SIZE) {
      printf("error: can't read input file '%s'\n", argv[1]);
      fclose(outfile);
      fclose(infile);
      return 1;
    }

    fwrite(gb_buffer, BUF_SIZE, 1, outfile);
  }

  if (ferror(outfile)) {
    printf("error: can't write output file '%s'\n", outname);
    fclose(outfile);
    fclose(infile);
    return 1;
  }

  fclose(outfile);
  fclose(infile);

  return 0;
}
