Page 1 of 1

FDS Infolizer

Posted: Tue Apr 10, 2007 8:44 pm
by beneficii
こんな物を見付けないので、今日はこれを書きました。ソースコードです:

【Cで書いて、MinGWでコンパイルをしました。ファイルの名は「fdsinfo.c」です。】

Code: Select all

/*

FDS Infolizer
Written by Beneficii on April 10, 2007--finished at 10:38 PM CDT (GMT -05)
beneficii@gmail.com

Prints information about an FDS file stored in fwNES format; also can output
files from the FDS disks to your file system
You might want to use redirection ">filename" to redirect the standard output of
this program
Parameters:
    fdsinfo     program filename
    fds-file    filename of FDS file to read
    -o          adding this tells the program to output the files from the FDS
                (optional)
    base dir    provides a base directory to store the output files
                (optional; defaults to current console window directory)
    
When this saves the files, it creates a directory for each of the disks and puts
the files in their respective disks' directories

^_^ Special thanks to Nori's and Brad Taylor's Docs ^_^
^_^ And the wonderful people at nesdev.com and acmlm.no-ip.org ^_^

*/

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

#define START_ADDRESS     0x10
#define DISK_SIZE         (size_t) 65500
#define DISK_HEADER       41
#define FILE_AMOUNT       1
#define FILE_HEADER       15
#define F(e,b)            sprintf(e, "Bad format at %s!\n", b);
#define S(e)              sprintf(e, "Bad file size!\n");
#define ERROR(c,s,e,f,n)  \
if(c) { \
    fclose(f); \
    s \
    perror(e); \
    return (n); \
}
#define FP(c,e,b,f)       ERROR(c, F(e,b), e, f, 4)
#define SP(c,e,f)         ERROR(c, S(e), e, f, 5)
#define COMP_CONDITION1   ((ftell(in)-START_ADDRESS) / DISK_SIZE != nodisks)
#define COMP_CONDITION2   ((ftell(in)-START_ADDRESS) % DISK_SIZE)

typedef unsigned char data;

const char title[]     = "fdsinfo <fds-file> [-o [base directory]]\n\
\t-o\toutput fds files\n\n";
const char fds_check[] = "FDS\x1a";
const char hvc_check[] = "*NINTENDO-HVC*";
const char *strings[] = {
    "10-Byte Check",
    "Manufacture Code",
    "Game Name",
    "Game Version Number",
    "Side Number",
    "Disk Number", 
    "Err. 9",
    "Err. 10",
    "Boot Read File Code",
    "Manufacture Permit Date (?)",
    "Create Date",
};
const char *fstrings[] = {
    "File Number",
    "File ID Code",
    "Filename",
    "File (Memory) Address",
    "File Size",
    "File Kind",
};
const char *fkinds[] = {
    "Program (PRAM)",
    "Character (CRAM)",
    "Name Table (VRAM)",
};
/* starting byte of each piece of info from disk header starting with first
   byte after *NINTENDO-HVC* */
const int  dstart[] = {0, 0, 1, 5, 6, 7, 8, 9, 10, 16, 29};
const int  fstart[] = {0, 1, 2, 10, 12, 14};
const char sides[]  = {'A', 'B'};

void buildspacebuffer(char *buff, int num) {
int i;
     for(i = 0; i < num; i++) {
           buff[i] = ' ';
     }
     if(num < 0) num = 0;
     buff[num] = '\0';
}

int main(int argc, char **argv) {
    int outfiles = 0, nodisks = 0, i = 0, j = 0, k = 0, cflag = 0, 
      dirflag = 0, dircheck = 0;
    size_t memstart = 0, outsize = 0;
    data input[DISK_SIZE];
    data *ptr = NULL;
    FILE *in = NULL, *out = NULL;
    char error[300], space[50], filename[9], fileout[350];
    if(argc < 2) {
        printf(title);
        return 0;
    }
    if(argc > 4) {
        printf(title);
        perror("Too many parameters!\n");
        return 1;
    }
    in = fopen(argv[1], "rb");
    if(in == NULL) {
        perror("Bad filename!\n");
        return 2;
    }
    if(argc >= 3) {
        if(strcmp("-o", argv[2])) {
            fclose(in);
            printf(title);
            perror("Bad parameter after file!\n");
            return 3;
        }
        outfiles = 1;
    }
    if(argc==4) {
        dircheck = chdir(argv[3]);
        if(dircheck < 0) {
            dircheck = mkdir(argv[3]);
            if(dircheck < 0) {
                perror("Could not create base directory.  Cannot write files.\n");
                outfiles = 0;
            } else {
                dircheck = chdir(argv[3]);
                if(dircheck < 0) {
                    perror("Could not switch to base directory. Cannot write files.\n");
                    outfiles = 0;
                }
            }
        }    
    }
    /* deal with fwNES header and total size check */
    SP(fread(input, sizeof(data), strlen(fds_check), in)!=strlen(fds_check), error, in)
    FP(strncmp(fds_check, input, strlen(fds_check)), error, "fwNES check", in)
    nodisks = fgetc(in);
    SP(nodisks < 0, error, in)
    rewind(in);
    fseek(in, 0, SEEK_END);
    SP(COMP_CONDITION1 || COMP_CONDITION2, error, in)
    /* do each disk */
    for(i = 0; i < nodisks; i++) {
        printf("Disk %i:\n", i);
        rewind(in);
        fseek(in, START_ADDRESS + i * DISK_SIZE, SEEK_SET);
        SP(fread(input, sizeof(data), DISK_SIZE, in)!=DISK_SIZE, error, in)
        if(outfiles) {
            /* check if already in sub-directory */
            if(dirflag) {
                j = chdir("..");
                if(j < 0) {
                    perror("Error coming out of directory.  Cannot write files.\n");
                    outfiles = 0;
                }
            }
            sprintf(fileout, "DISK_%02X", i);
            j = chdir(fileout);
            if(j < 0) {
                j = mkdir(fileout);
                if(j < 0) {
                    sprintf(error, 
                      "Cannot create directory %s!  Cannot write files.\n",
                      fileout);
                    perror(error);
                    outfiles = 0;
                } else {
                    j = chdir(fileout);
                    if(j < 0) {
                        sprintf(error, 
                          "Cannot create directory %s!  Cannot write files.\n",
                          fileout);
                        perror(error);
                        outfiles = 0;    
                    }
                }
            }
            dirflag = 1;
        }
        memstart = outsize = 0;
        ptr = input;
        cflag = 1;
        do {
            if(ptr - input >= DISK_SIZE) /* if not enough room on disk */ {
                perror("Disk overflow?\nNot enough room on disk for exit byte!\n");
                break;
            }
            switch(*ptr) {
                case 1: /*disk header*/
                    /* if not enough room for disk header */
                    if(ptr - input + 1 + strlen(hvc_check) + DISK_HEADER 
                      > DISK_SIZE) {
                        perror("Not enough room for disk header!\n");
                        cflag = 0;
                        break;
                    }
                    ptr++;
                    printf("Header:\n");
                    if(strncmp(hvc_check, ptr, strlen(hvc_check))) {
                        perror("Bad header format for disk!\n");
                        cflag = 0;
                        break;
                    }
                    ptr += strlen(hvc_check);
                    /* print disk header info */
                    for(j = 0; j < 11; j++) {
                        buildspacebuffer(space, 30 - strlen(strings[j]));
                        printf("%s:%s", strings[j], space);
                        switch(j) {
                            case 0:
                                for(k = 0; k < 10; k++) 
                                    printf("$%02X ", ptr[k+dstart[j]]);
                                break;
                            case 2:
                                for(k = 0; k < 4; k++) 
                                    printf("%c", ptr[k+dstart[j]]);
                                break;
                            case 4: 
                                printf("Side %c", sides[ptr[dstart[j]] & 1]);
                                break;
                            case 9:
                            case 10:
                                printf("%x-%x in the year of Showa %x",
                                  ptr[1+dstart[j]], ptr[2+dstart[j]], ptr[0+dstart[j]]);
                                break;
                            default:
                                printf("$%02X", ptr[dstart[j]]);
                                break;
                        }
                        printf("\n");
                    }
                    printf("End of block\n\n");
                    ptr += DISK_HEADER;
                    break;
                case 2:   /*file amount block*/
                    if(ptr - input + 2 > DISK_SIZE) {
                        perror("Not enough space for file amount block!\n");
                        cflag = 0;
                        break;
                    }
                    ptr++;
                    buildspacebuffer(space, 30 - strlen("Number of files"));
                    printf("File amount block:\nNumber of files:%s%i\n",
                      space, *ptr);
                    printf("End of block\n\n");
                    ptr++;
                    break;
                case 3:   /*file header info*/
                    if(ptr - input + 1 + FILE_HEADER > DISK_SIZE) {
                        perror("Not enough space for file header block!\n");
                        cflag = 0;
                        break;
                    }
                    ptr++;
                    for(j = 0; j < 6; j++) {
                        buildspacebuffer(space, 30 - strlen(fstrings[j]));
                        printf("%s:%s", fstrings[j], space); 
                        switch(j) {
                            case 2:
                                for(k = 0; k < 8; k++) {
                                    filename[k] = ptr[fstart[j]+k];
                                    printf("%c", filename[k]);
                                }
                                filename[k] = '\0';
                                break;
                            case 3:
                                memstart = ptr[fstart[j]] | (ptr[fstart[j]+1]<<8);
                                printf("$%04X", memstart);
                                break;
                            case 4:
                                outsize  = ptr[fstart[j]] | (ptr[fstart[j]+1]<<8);
                                printf("$%04X", outsize);
                                break;
                            case 5:
                                if(ptr[fstart[j]] > 2) 
                                    printf("Unknown (UNKT)");
                                else
                                    printf("%s", fkinds[ptr[fstart[j]]]);
                                break;
                            default:
                                printf("$%02X", ptr[fstart[j]]);
                                break;
                        }
                        printf("\n");
                    }
                    printf("End of block\n\n");
                    ptr += FILE_HEADER;
                    break;
                case 4:
                    if(ptr - input + 1 + outsize > DISK_SIZE) {
                        perror("Not enough room for file on disk!\n");
                        cflag = 0;
                        break;
                    }
                    ptr++;
                    printf("File %s\n", filename); 
                    if(outfiles) {
                        printf("Printing file from disk %i...\n", i);
                        for(j = 0; j < 8; j++) 
                            if(isspace(filename[j]))
                                filename[j] = '_';
                        sprintf(fileout, "%s.BIN", filename);
                        out = fopen(fileout, "wb");
                        if(out==NULL) {
                            outfiles = 0;
                            sprintf(error, "Could not open %s for writing!\n", 
                                fileout);
                            perror(error);
                            printf("Cancelling all file write-outs!\n");
                        } else {
                            fwrite(ptr, sizeof(data), outsize, out);
                            j = fclose(out);
                            if(j) {
                                perror("Ouch, error while closing out file\n");
                                perror("Aborting program\n");
                                j = fclose(in);
                                if(j) {
                                    perror("Ouch, error while closing in file too\n");
                                    perror("Something's wrong\n");
                                }
                                return j;
                            }    
                            printf("File write to %s successful!\n", fileout);
                        }
                    }
                    printf("End of file\n\n");
                    ptr += outsize;
                    memstart = outsize = 0; /*resetting file info*/
                    filename[0] = '\0';
                    break;
                case 0:
                case 255: /* disk end block */
                    cflag = 0;
                    break;
                default:
                    sprintf(error, 
                      "Unknown/Invalid block type at disk %i byte %04X!\n", 
                      i, ptr - input);
                    perror(error);
                    cflag = 0;
                    break;
            }
        } while(cflag);
        printf("End of disk\n\n\n\n");
    }
    i = fclose(in);
    if(i) {
        perror("Error closing in file\nAborting program\n");
        return i;
    }
    printf("End of FDS Disk Set\n");
    printf("Success!\n");
    return 0;
}
/* updated at 5:18 PM CDT (GMT -5) on Wednesday, May 2, 2007 */