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

const char header[] =
{ 0x2A, 0x2A, 0x54, 0x49, 0x38, 0x33, 0x46, 0x2A, 0x1A, 0x0A, 0x00 };

char comment[] = "BIN28XP Converter";

char* resizeBuf(char*, int, int);
char* getFileName(char*);
char* cut(char*, int);
char* convName(char*);

char* out;
int buf_i;
void addBuf(char*, int);
void addByte(char);

int main(int argc, char** argv)
{
    char* comt = (char*)comment, *n = 0, pr = 0x06, *inf = 0;
    bool quiet = false;

    for (int a = 0; a < argc; a++)
    {
        if (!strcmp("-c", argv[a])) {
            if ((++a) < argc) comt = cut(argv[a], 42);
            else { printf("comment expected."); return 1; }
        }
        else if (!strcmp("--protected", argv[a])) pr = 0x06;
        else if (!strcmp("--unprotected", argv[a])) pr = 0x05;
        else if (!strcmp("-n", argv[a])) {
            if ((++a) < argc) n = cut(argv[a], 8);
            else { printf("name expected."); return 1; }
        }
        else if (!strcmp("--nocomment", argv[a])) comt[0] = 0;
        else if (!strcmp("-q", argv[a])) quiet = true;
        else inf = argv[a];
    }

    if (inf == 0) {
        printf("file expected.");
        return 1;
    }

    FILE* fh = fopen(inf, "rb");
    char* f = getFileName(inf);
    FILE* fho = fopen(f, "wb");

    if (!quiet) {
        printf("bin28xp, Keith's Fixed Ver!!! \n");
        printf("Converting \"%s\" to \"%s\". \n ", inf, f);
    }

    if (fh == 0) {
        printf("error while opening \"%s\" for input.\n", argv[1]);
        return 1;
    }
    if (fho == 0) {
        printf("error while opening \"%s\" for output.\n", f);
        return 1;
    }

    int i = 0, l = 1024;
    char* buf = (char*)malloc(l);

    while (!feof(fh)) {             /* read file */
        buf[i++] = fgetc(fh);
        if (i >= l) buf=resizeBuf(buf, l, (l*=2));
    }

    fclose(fh);

    char* cmt = (char*)malloc(42);

    short int data_sec = --i, t;

    /* data is in buf, size is in i */

    fwrite(header, 11, 1, fho);              /* write "**TI83F*",0x1A,0x0A,0 */
    int cl = strlen(comt);
    fwrite(comt, cl, 1, fho);                 /* write comment (42bytes) */
    for (cl; cl < 42; cl++) fputc(0, fho);
    data_sec += 19;                        /* write data section length+19 */
    fwrite(&data_sec, 2, 1, fho);

    /* starting here, output will first be placed into "out" */
    /* (for counting checksum) */
    out = (char*)malloc(19+i); buf_i = 0;
    data_sec -= 17;
    addByte(13); addByte(0);           /* 13, 0 */
    addBuf((char*)&data_sec, 2);                 /* write data section len.+2 */
    addByte(pr);                           /* protection (5:no,6:yes) */
    if (n == 0) {
        f[strlen(f)-4] = 0;                 /* cut off output file extension */
        addBuf(convName(f), 8);             /* write file name */
    } else addBuf(convName(n), 8);

    addByte(0); addByte(0);
    addBuf((char*)&data_sec, 2);            /* write data sec. len.+2 */
    data_sec -= 2;
    addBuf((char*)&data_sec, 2);           /* write data sec. len. */
    addBuf(buf, data_sec);                   /* write data section */

    short int checksum = 0;
    for (int a = 0; a < 19+i; a++)
        checksum += (unsigned char)out[a];

    fwrite(out, 19+i, 1, fho);              /* write "out" */
    fwrite(&checksum, 2, 1, fho);           /* write checksum */

    int outs = ftell(fho);

    fclose(fho);

    free(f);

    if (!quiet) printf("%i bytes written.", outs);

    return 0;
}

char* convName(char* n) {
    char* rv = (char*)malloc(8);
    int i = 0, sl = strlen(n);
    char cc;
    if (sl > 8) sl = 8;
    for (int a = 0; a < sl; a++) {
        cc = n[a];
        if (cc >= 'a' && cc <= 'z') cc -= 32;
        if (cc >= 'A' && cc <= 'Z') rv[i++] = cc;
    }
    for (i; i < 8; i++) rv[i] = 0;
    return rv;
}

void addBuf(char* buf, int len)
{ memcpy(out+buf_i, buf, len); buf_i += len; }

void addByte(char byte)
{ out[buf_i++] = byte; }

char* resizeBuf(char* buf, int old_size, int new_size)
{
    char* newbuf = (char*)malloc(new_size);
    memcpy(newbuf, buf, old_size);
    free(buf);
    return newbuf;
}

char* getFileName(char* old)
{
    int len = strlen(old);
    char* rv = (char*)malloc(13);
    int l2;
    char* t = strrchr(old, '\\'); /* find filename */
    if (t == 0) t = old;
    char* e = strchr(t, '.');    /* remove extension */
    if (e != 0) e[0] = 0;
    l2 = strlen(t); if (l2 > 8) l2 = 8;
    memcpy(rv, old, l2);
    rv[l2++] = '.'; rv[l2++] = '8'; rv[l2++] = 'X'; rv[l2++] = 'P'; rv[l2] = 0;
    if (e != 0) e[0] = '.'; /* restore extension */
    return rv;
}

char* cut(char* s, int p)
{
    if (strlen(s) > p) s[p-1] = 0;
    return s;
}
