こんな物を見付けないので、今日はこれを書きました。ソースコードです:
【Cで書いて、MinGWでコンパイルをしました。ファイルの名は「fdsinfo.c」です。】
【Cで書いて、MinGWでコンパイルをしました。ファイルの名は「fdsinfo.c」です。】
Code:
/*
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 */
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 */