/*  Copyright 2009, Unpublished Work of Technologic Systems
 *  All Rights Reserved.
 *
 *  THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL,
 *  PROPRIETARY AND TRADE SECRET INFORMATION OF TECHNOLOGIC SYSTEMS.
 *  ACCESS TO THIS WORK IS RESTRICTED TO (I) TECHNOLOGIC SYSTEMS EMPLOYEES
 *  WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF THEIR
 *  ASSIGNMENTS  AND (II) ENTITIES OTHER THAN TECHNOLOGIC SYSTEMS WHO
 *  HAVE ENTERED INTO  APPROPRIATE LICENSE AGREEMENTS.  NO PART OF THIS
 *  WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED, REVISED,
 *  MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, EXPANDED, COLLECTED,
 *  COMPILED,LINKED,RECAST, TRANSFORMED, ADAPTED IN ANY FORM OR BY ANY
 *  MEANS,MANUAL, MECHANICAL, CHEMICAL, ELECTRICAL, ELECTRONIC, OPTICAL,
 *  BIOLOGICAL, OR OTHERWISE WITHOUT THE PRIOR WRITTEN PERMISSION AND
 *  CONSENT OF TECHNOLOGIC SYSTEMS . ANY USE OR EXPLOITATION OF THIS WORK
 *  WITHOUT THE PRIOR WRITTEN CONSENT OF TECHNOLOGIC SYSTEMS  COULD
 *  SUBJECT THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

static unsigned char preamble[] = {
  0x65, 0xb1, 0xac, 0x5f, 0x5f, 0x5f, 0x5f, 0x31, 0x32, 0x2e, 0x31, 0xf2,
  0x19, 0xfe, 0x04, 0x56, 0x01, 0x10, 0x00, 0x08, 0x00, 0x06, 0x00, 0x09,
  0x00, 0x07, 0x00, 0x02, 0x03, 0x03, 0x02, 0x0b, 0xc0, 0x84, 0x3d, 0x10,
  0x01, 0x11, 0x08, 0x13, 0x68, 0x70, 0x12, 0x20, 0x13, 0xff, 0xff, 0xff,
  0xff, 0x14, 0xc2, 0x09, 0x94, 0x80, 0x15, 0xff, 0xff, 0xff, 0xff, 0x70,
  0x11, 0x08, 0x13, 0x38, 0x70, 0x12, 0x8a, 0x03, 0x13, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x70,
  0x11, 0x08, 0x13, 0xaa, 0x70, 0x10, 0x01, 0x1b, 0x03, 0x1a, 0x03, 0x1a,
  0x94, 0x80, 0x02, 0x11, 0x08, 0x13, 0xc0, 0x70, 0x10, 0x01, 0x1b, 0x03,
  0x1a, 0x03, 0x1a, 0x81, 0x80, 0x02, 0x11, 0x08, 0x13, 0x84, 0x70, 0x10,
  0x01, 0x1b, 0x03, 0x1a, 0x03, 0x1a, 0x81, 0x80, 0x02, 0x11, 0x08, 0x13,
  0xe6, 0x70
};

static unsigned char postamble[] = {
  0x11, 0x08, 0x13, 0x58, 0x70, 0x12, 0x20, 0x13, 0xff, 0xff, 0xca, 0x2a, 
  0x70, 0x10, 0x01, 0x1b, 0x03, 0x1a, 0x03, 0x1a, 0x81, 0x80, 0x02, 0x11,
  0x08, 0x13, 0xa2, 0x70, 0x12, 0x20, 0x13, 0xff, 0xff, 0xff, 0xff, 0x70,
  0x10, 0x01, 0x1b, 0x03, 0x1a, 0x03, 0x1a, 0x94, 0x80, 0x02, 0x11, 0x08,
  0x13, 0x22, 0x70, 0x10, 0x01, 0x1b, 0x03, 0x1a, 0x03, 0x1a, 0x81, 0x80,
  0x02, 0x12, 0x20, 0x13, 0x00, 0x00, 0x00, 0x00, 0x14, 0xff, 0xff, 0xff,
  0xff, 0x70, 0x11, 0x08, 0x13, 0x4d, 0x70, 0x10, 0x01, 0x1b, 0x03, 0x1a,
  0x03, 0x1a, 0x81, 0x80, 0x02, 0x12, 0x08, 0x13, 0x00, 0x14, 0x00, 0x15,
  0x80, 0x70, 0x11, 0x08, 0x13, 0xf4, 0x70, 0x10, 0x01, 0x1b, 0x03, 0x1a,
  0x03, 0x1a, 0xb2, 0x80, 0x02, 0x11, 0x08, 0x13, 0x4d, 0x70, 0x10, 0x01,
  0x1b, 0x03, 0x1a, 0x03, 0x1a, 0x81, 0x80, 0x02, 0x12, 0x08, 0x13, 0x00,
  0x14, 0x40, 0x15, 0xc0, 0x70, 0x11, 0x08, 0x13, 0x78, 0x70, 0x10, 0x01,
  0x1b, 0x03, 0x1a, 0x03, 0x1a, 0xc8, 0x81, 0x02, 0x11, 0x08, 0x13, 0xff,
  0x70, 0x10, 0x01, 0x1b, 0x03, 0x1a, 0x03, 0x1a, 0x81, 0x80, 0x02, 0x10,
  0x00, 0x7f
};

static inline void printbuf(unsigned char *b) {
	int i;
	static unsigned char post[] = 
	  { 0x70, 0x10, 0x01, 0x1b, 0x03, 0x1a, 0x03, 0x1a, 0x81, 0x80, 0x02 };
	static unsigned char pre[] = { 0x12, 0xfe, 0x04, 0x13 };

	fwrite(pre, sizeof(pre), 1, stdout);
	fwrite(b, 80, 1, stdout);
	fwrite(post, sizeof(post), 1, stdout);
}

static void usage(void) {
	fprintf(stderr, "Usage: jed2vme [FILE]\n"
	  "Converts TS Lattice XP2 JEDEC .jed files to .vme files on stdout\n"
	  "Example: jed2vme ts7500.jed > ts7500.vme\n"
	  "\n"
	  "Options:\n"
	  "  -h, --help              This help\n"
	  "\n"
	  "If FILE is not given, converts JEDEC file on stdin.  If FILE ends\n"
	  "with .bz2 or .gz, jed2vme will automatically attempt to decompress.\n"
	  );
}

int main(int argc, char **argv) {
	int c;
	int state = 0;
	int bit = 0;
	unsigned char buf[80];
	unsigned int sr;
	FILE *in;

	if (argc > 1) {
		char b[512];
		int l = strlen(argv[1]);
		
		if (argv[1][0] == '-') {
			  usage();
			  return 0;
		} else if (strcmp(".bz2", &argv[1][l - 4]) == 0) {
			snprintf(b, 512, "exec bunzip2 -c '%s'", argv[1]);
			in = popen(b, "r");
		} else if (strcmp(".gz", &argv[1][l - 3]) == 0) {
			snprintf(b, 512, "exec gunzip -c '%s'", argv[1]);
			in = popen(b, "r");
		} else in = fopen(argv[1], "r");

		if (in == NULL) {
			perror(argv[1]);
			return 2;
		}
	} else in = stdin;
	
	while ((c = fgetc(in)) != EOF) {
		switch (state) {
		case 0:
			if (c == 2) state = 3;
			break;
		case 1: /* tag type  */
			if (c == 'L') {
				int offs;
				fscanf(in, "%x", &offs);
				fwrite(preamble, sizeof(preamble), 1, stdout);
				if (offs == 0) state = 4;
				else state = 2;
			} else state = 2;
			break;
		case 2: /* skip until asterisk */
			if (c == '*') state = 3;
			break;
		case 3: /* skip until EOL */
			if (c == '\n') state = 1;
			break;
		case 4: /* next line has our data */
			if (c == '\n') state = 5;
			break;
		case 5: /* 1's and 0's */
			if (c == '0' || c == '1') {
				bit++;
				sr = (sr << 1) | (c - '0');
				if ((bit & 0x7) == 0) {
					buf[(bit>>3) - 1] = sr;
				}
				if (bit == 638) {
					bit = 0;
					buf[79] = sr<<2;
					printbuf(buf);
				}
			} else if (c == '*') {
				assert(bit == 0);
				state = 3;
				if (pclose(in) == -1) fclose(in);
				fwrite(postamble, sizeof(postamble), 1, stdout);
				return 0;
			}
			break;
		}
	}
	if (pclose(in) == -1) fclose(in);
	return 1;
}
