/* This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/wtfpl/COPYING for more details. */ 

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


/* IP.BIN header format. */
#if defined( __GNUC__ )
#pragma pack(1)
#else
#pragma pack(push,1)
#endif

#define SC_BUP_DATA_VERSION 0x42
typedef struct _ip_bin
{
    /* Text-based informations. */
    char hwr_id[16]; // "SEGA SEGASATURN "
    char man_id[16]; // "SEGA TP KAISHA-A"
    char prd_nb[10]; // "T-053G    "
    char version[6]; // "V0.001"
    char date[8];    // "19940912"
    char dev_id[8];  // "CD-1/1  "
    char area[16];   // "JTUBKAEL        "
    char pers[16];   // "JAST            "
    char title[112]; // ...

    /* Value-based informations. */
    unsigned char unused01[4];
    unsigned char unused02[4];
    unsigned char unused03[4];
    unsigned char unused04[4];

    unsigned char ip_size[4];   // 0x00001800
    unsigned char unused06[4];
    unsigned char stack_m[4];   // 0x00000000 ?
    unsigned char stack_s[4];   // 0x00000000 ?

    unsigned char first_adr[4]; // 0x06004000
    unsigned char first_siz[4]; // 0x00000000 ?
    unsigned char unused11[4];
    unsigned char unused12[4];
} ip_bin_t;

#if defined( __GNUC__ )
#pragma pack()
#else
#pragma pack(pop)
#endif




int main (int argc, char *argv[])
{
    FILE* fp = NULL;
    /* Our IP header. */
    ip_bin_t header;
    memset((void*)(&header), ' ', sizeof(ip_bin_t));

    if(argc <= 1)
    {
        printf("Type %s -h for help.\n", argv[0]);
        return 0;
    }
    if(argc >= 2)
    {
        if((!strcmp(argv[1], "-h"))
        || (!strcmp(argv[1], "-help"))
        || (!strcmp(argv[1], "-?")))
        {
            printf("--- IP header customizer v0.2 by cafe-alpha.                ---\n");
            printf("--- This is a part of my entry in the S.A.T.U.R.N. contest. ---\n");
            printf("Usage : <in_file> [-xxx [<str>]] ...\n");
            printf(" <in_file> can be an ISO, or an ARP firmware file.\n");
            printf(" IP header customization arguments:\n");
            printf("  -man       <str>: set ip manufacturer    (ex:SEGA TP KAISHA-A)\n");
            printf("  -prod      <str>: set ip product number  (ex:T-053G)\n");
            printf("  -ver       <str>: set ip version         (ex:V0.001)\n");
            printf("  -date      <str>: set ip date            (ex:19940912)\n");
            printf("  -today          : set ip date to today\n");
            printf("  -dev       <str>: set ip device ID       (ex:CD-1/1)\n");
            printf("  -area      <str>: set ip area            (ex:JTUBKAEL)\n");
            printf("  -per       <str>: set ip peripherals     (ex:JAST)\n");
            printf("  -title     <str>: set ip title           (ex:MY TITLE)\n");
            printf("\n");
            printf("  -ip_size   <val>: set ip size            (ex:0x00001800)\n");
            printf("  -stack_m   <val>: set CPU1 stack address (ex:0x06001000)\n");
            printf("  -stack_s   <val>: set CPU2 stack address (ex:0x06000D00)\n");
            printf("  -first_adr <val>: set 1st read address   (ex:0x06004000)\n");
            printf("  -first_siz <val>: set 1st read size      (ex:0x00000000)\n");
            return 0;
        }
    }

    /* Open file, and read its header. */
    fp = fopen(argv[1], "rb");
    if(fp == NULL)
    {
        printf("IP header: couldn't open file for reading !\n");
        return 0;
    }
    fread((void*)&header, sizeof(ip_bin_t), 1, fp);
    fclose(fp); fp = NULL;


    int i;

    // Parse arguments
    for(i=2; i<argc; i++)
    {
        if(!strcmp(argv[i], "-man"))
        {i++;
            memset((void*)(&(header.man_id)), ' ', sizeof(header.man_id));
            strncpy(header.man_id, argv[i], sizeof(header.man_id));
        }
        else if(!strcmp(argv[i], "-prod"))
        {i++;
            memset((void*)(&(header.prd_nb)), ' ', sizeof(header.prd_nb));
            strncpy(header.prd_nb, argv[i], sizeof(header.prd_nb));
        }
        else if(!strcmp(argv[i], "-ver"))
        {i++;
            memset((void*)(&(header.version)), ' ', sizeof(header.version));
            strncpy(header.version, argv[i], sizeof(header.version));
        }
        else if(!strcmp(argv[i], "-date"))
        {i++;
            memset((void*)(&(header.date)), ' ', sizeof(header.date));
            strncpy(header.date, argv[i], sizeof(header.date));
        }
        else if(!strcmp(argv[i], "-today"))
        {
            time_t     now;
            struct tm  *ts;
            now = time(NULL);
            ts = localtime(&now);
            char       buf[80];
            strftime(buf, sizeof(buf), "%Y%m%d", ts);
            strncpy(header.date, buf, sizeof(header.date));
        }
        else if(!strcmp(argv[i], "-dev"))
        {i++;
            memset((void*)(&(header.dev_id)), ' ', sizeof(header.dev_id));
            strncpy(header.dev_id, argv[i], sizeof(header.dev_id));
        }
        else if(!strcmp(argv[i], "-area"))
        {i++;
            memset((void*)(&(header.area)), ' ', sizeof(header.area));
            strncpy(header.area, argv[i], sizeof(header.area));
        }
        else if(!strcmp(argv[i], "-per"))
        {i++;
            memset((void*)(&(header.pers)), ' ', sizeof(header.pers));
            strncpy(header.pers, argv[i], sizeof(header.pers));
        }
        else if(!strcmp(argv[i], "-title"))
        {i++;
            memset((void*)(&(header.title)), ' ', sizeof(header.title));
            strncpy(header.title, argv[i], sizeof(header.title));
        }
        else if(!strcmp(argv[i], "-ip_size"))
        {i++;
            unsigned long ip_size = strtoul(argv[i], NULL, 0);
            printf("ip_size = %X", ip_size >> 24);
            header.ip_size[0] = ( ip_size >> 24 ) & 0xFF;
            printf("ip_size test = %X", header.ip_size[0]);
            header.ip_size[1] = ( ip_size >> 16 ) & 0xFF;
            header.ip_size[2] = ( ip_size >>  8 ) & 0xFF;
            header.ip_size[3] = ( ip_size >>  0 ) & 0xFF;
        }
        else if(!strcmp(argv[i], "-stack_m"))
        {i++;
            unsigned long stack_m = strtoul(argv[i], NULL, 0);
            header.stack_m[0] = ( stack_m >> 24 ) & 0xFF;
            header.stack_m[1] = ( stack_m >> 16 ) & 0xFF;
            header.stack_m[2] = ( stack_m >>  8 ) & 0xFF;
            header.stack_m[3] = ( stack_m >>  0 ) & 0xFF;
        }
        else if(!strcmp(argv[i], "-stack_s"))
        {i++;
            unsigned long stack_s = strtoul(argv[i], NULL, 0);
            header.stack_s[0] = ( stack_s >> 24 ) & 0xFF;
            header.stack_s[1] = ( stack_s >> 16 ) & 0xFF;
            header.stack_s[2] = ( stack_s >>  8 ) & 0xFF;
            header.stack_s[3] = ( stack_s >>  0 ) & 0xFF;
        }
        else if(!strcmp(argv[i], "-first_adr"))
        {i++;
            unsigned long first_adr = strtoul(argv[i], NULL, 0);
            header.first_adr[0] = ( first_adr >> 24 ) & 0xFF;
            header.first_adr[1] = ( first_adr >> 16 ) & 0xFF;
            header.first_adr[2] = ( first_adr >>  8 ) & 0xFF;
            header.first_adr[3] = ( first_adr >>  0 ) & 0xFF;
        }
        else if(!strcmp(argv[i], "-first_siz"))
        {i++;
            unsigned long first_siz = strtoul(argv[i], NULL, 0);
            header.first_siz[0] = ( first_siz >> 24 ) & 0xFF;
            header.first_siz[1] = ( first_siz >> 16 ) & 0xFF;
            header.first_siz[2] = ( first_siz >>  8 ) & 0xFF;
            header.first_siz[3] = ( first_siz >>  0 ) & 0xFF;
        }
        else
        {
            printf("IP header: unknown parameter ! (%s)\n", argv[i]);
        }
    }

    /* Remove non-ASCII characters in text-based informations. */
    unsigned char* str = (unsigned char*)&header;
    for(i-0; i<208; i++)
    {
        if(str[i] < ' ')
        {
            str[i] = ' ';
        }
    }


    /* Write modified header to file. */
    fp = fopen(argv[1], "r+");
    if(fp == NULL)
    {
        printf("IP header: couldn't open file for writing !\n");
        return 0;
    }
    fwrite((void*)&header, sizeof(ip_bin_t), 1, fp);
    fclose(fp); fp = NULL;

    return 0;
}



