Cet outil décode les entêtes des fichiers Nanoréseau et permet d'en extraire les sections binaires.
Exemple d'utilisation :
$ nrfile -e NRDOS.MO5
NRFile, version 1.0
File: NRDOS.MO5 (7552 bytes)
Header:
Station identifier: " " (default)
File type: binary
File mode: binary
File status: read/write
Nanoreseau version: 3.1
Creation date: 27/05/85
Last modification date: 27/05/85
Created on a: TO7
Created with: unreferenced application
File attributes: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Binary contents:
Format: extended
Target computer: MO5
Target application: unreferenced application
Loading flags: broadcast, load application first
Application: "NRDOS"
Code section 1:
Size: 7373 bytes
Load address: 00-5000 (do not switch RAM page)
Section has been dumped to NRDOS.MO5-00-5000.bin.
Execution address: 00-5000 (do not switch RAM page)
Code source :
#include
#include
#include
// Undefine this for Unix-like systems
#define PATH_WINDOWS
int gExtract = 0;
FILE *gSource = NULL;
unsigned char *gBuffer = NULL;
char *gFilename = NULL;
long gSize = 0;
char gIdentifier[9] = {0};
unsigned char gFileType = 0;
void TargetApp(unsigned char xByte)
{
switch (xByte)
{
case 0:
printf("unreferenced application");
break;
case 1:
printf("BASIC 1.0");
break;
case 2:
printf("LOGO");
break;
case 3:
printf("LSE");
break;
default:
printf("unknown application");
}
}
void TargetComputer(unsigned char xByte)
{
switch (xByte)
{
case 0:
printf("TO7");
break;
case 1:
printf("MO5");
break;
case 2:
printf("TO7/70");
break;
default:
printf("unknown computer");
}
}
void PageSwitch(unsigned char xPage)
{
switch (xPage)
{
case 0:
printf("do not switch RAM page");
break;
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
printf("switch to RAM page %d",xPage-0x40);
break;
case 0x80:
case 0x81:
case 0x82:
case 0x83:
printf("switch to 64K RAM expansion page %d",xPage-0x80);
break;
case 0xff:
printf("switch to internal ROM [BASIC]");
break;
default:
printf("unknown RAM page");
}
printf(")\n");
}
void AnalyseBinExt(unsigned char *xpBuffer)
{
long lOffset = 38;
unsigned int lSection = 1, lSize = 0, lAddress = 0;
char lBuffer[33] = {0};
char *lFilename = NULL;
unsigned char lPage = 0;
FILE *lDump = NULL;
printf(" Target computer: ");
TargetComputer(xpBuffer[1]);
printf("\n");
printf(" Target application: ");
TargetApp(xpBuffer[2]);
printf("\n");
printf(" Loading flags: ");
if (xpBuffer[3]&0x80)
{
printf("broadcast");
}
if (xpBuffer[3]&0x40)
{
if (xpBuffer[3]&0x80)
{
printf(", ");
}
printf("load application first");
}
printf("\n");
strncpy(lBuffer,(char*)xpBuffer+6,32);
printf(" Application: \"%s\"\n\n",lBuffer);
while (xpBuffer[lOffset]!=3)
{
printf(" Code section %d:\n",lSection);
lSize = xpBuffer[lOffset+1]*256+xpBuffer[lOffset+2];
lPage = xpBuffer[lOffset+5];
printf(" Size: %d bytes\n",lSize);
lAddress = xpBuffer[lOffset+3]*256+xpBuffer[lOffset+4];
printf(" Load address: %02X-%04X (",lPage,lAddress);
PageSwitch(lPage);
printf("\n");
if (gExtract)
{
lFilename = (char*)malloc(strlen(gFilename+11));
sprintf(lFilename,"%s-%02x-%04x.bin",gFilename,lPage,lAddress);
lDump = fopen(lFilename,"wb");
fwrite(xpBuffer+lOffset+6,lSize,1,lDump);
fclose(lDump);
printf(" Section has been dumped to %s.\n\n",lFilename);
free(lFilename);
}
lOffset += 6+lSize;
lSection++;
}
lPage = xpBuffer[lOffset+5];
printf(" Execution address: %02X-%04X (",lPage,xpBuffer[lOffset+3]*256+xpBuffer[lOffset+4]);
PageSwitch(lPage);
}
void AnalyseBinSimple(unsigned char *xpBuffer)
{
long lOffset = 0;
unsigned int lSection = 1, lSize = 0, lAddress = 0;
char *lFilename = NULL;
FILE *lDump = NULL;
while (xpBuffer[lOffset]==0)
{
printf(" Code section %d:\n",lSection);
lSize = xpBuffer[lOffset+1]*256+xpBuffer[lOffset+2];
printf(" Size: %d bytes\n",lSize);
lAddress = xpBuffer[lOffset+3]*256+xpBuffer[lOffset+4];
printf(" Load address: %04X\n",lAddress);
printf("\n");
if (gExtract)
{
lFilename = (char*)malloc(strlen(gFilename+11));
sprintf(lFilename,"%s-%04x.bin",gFilename,lAddress);
lDump = fopen(lFilename,"wb");
fwrite(xpBuffer+lOffset+6,lSize,1,lDump);
fclose(lDump);
printf(" Section has been dumped to %s.\n\n",lFilename);
free(lFilename);
}
lOffset += 5+lSize;
lSection++;
}
printf(" Execution address: %04X\n",xpBuffer[lOffset+3]*256+xpBuffer[lOffset+4]);
}
void AnalyseBin(unsigned char *xpBuffer)
{
printf("Binary contents:\n Format: ");
if (xpBuffer[0] == 1)
{
printf("extended\n");
AnalyseBinExt(xpBuffer);
} else
{
printf("simple\n\n");
AnalyseBinSimple(xpBuffer);
}
}
void ExtractFilename(char *xSrcStr, char **xStrDst)
{
char *lPtr = strrchr(xSrcStr,
#ifdef PATH_WINDOWS
'\\'
#else
'/'
#endif // PATH_WINDOWS
);
if (lPtr==NULL)
{
*xStrDst = (char*) malloc(strlen(xSrcStr));
strcpy(*xStrDst,xSrcStr);
}
else
{
*xStrDst = (char*) malloc(strlen(lPtr));
strcpy(*xStrDst,lPtr+1);
}
}
void usage()
{
printf("Usage: nrfile [-e] filename\n");
}
int main(int argc, char *argv[])
{
long i;
printf("NRFile, version 1.0\n");
if ((argc!=2)&&(argc!=3))
{
usage();
return -1;
}
if (argv[1][0]=='-')
{
if (argc!=3)
{
usage();
return -1;
}
if (argv[1][1] == 'e')
{
gExtract = 1;
}
else
{
usage();
return -1;
}
} else if (argc!=2)
{
usage();
return -1;
}
if (gExtract)
{
ExtractFilename(argv[2],&gFilename);
gSource = fopen(argv[2],"rb");
} else
{
ExtractFilename(argv[1],&gFilename);
gSource = fopen(argv[1],"rb");
}
if (gSource == NULL)
{
printf("Error: cannot open file.\n");
free(gFilename);
return -2;
}
fseek(gSource,0,SEEK_END);
gSize = ftell(gSource);
fseek(gSource,0,SEEK_SET);
gBuffer = malloc(gSize);
if (gBuffer == NULL)
{
printf("Error: cannot allocate memory.\n");
free(gFilename);
fclose(gSource);
return -3;
}
memset(gBuffer,0,gSize);
fread(gBuffer,1,gSize,gSource);
fclose(gSource);
if (strnicmp((char*)gBuffer,"*NRUSTL*",8))
{
printf("Error: this file is not Nanoreseau compatible.\n");
free(gBuffer);
free(gFilename);
return -4;
}
printf("\nFile: %s (%lu bytes)\n\n",gFilename,gSize);
printf("Header:\n");
strncpy(gIdentifier,(char *)gBuffer+8,8);
printf(" Station identifier: \"%s\"",gIdentifier);
if (strncmp(gIdentifier," ",8) == 0)
{
printf(" (default)");
}
printf("\n");
gFileType = gBuffer[17];
printf(" File type: ");
switch (gFileType)
{
case 0:
printf("BASIC program");
break;
case 1:
printf("BASIC data");
break;
case 2:
printf("binary");
break;
case 3:
printf("source code");
break;
case 5:
printf("indexed data");
break;
default:
printf("unknown");
}
printf("\n");
printf(" File mode: ");
switch (gBuffer[18])
{
case 0:
printf("binary");
break;
case 0xff:
printf("ASCII");
break;
default:
printf("unknown");
}
printf("\n");
printf(" File status: ");
switch (gBuffer[23])
{
case 0:
printf("read/write");
break;
case 0xff:
printf("write protected");
break;
default:
printf("unknown");
}
printf("\n");
printf(" Nanoreseau version: %d.%d\n",gBuffer[24],gBuffer[25]);
printf(" Creation date: %02d/%02d/%02d\n",gBuffer[28],gBuffer[27],gBuffer[26]);
printf(" Last modification date: ");
if ((gBuffer[29] == 0)&&(gBuffer[30] == 0)&&(gBuffer[31] == 0))
{
printf("never");
}
else
{
printf("%02d/%02d/%02d",gBuffer[31],gBuffer[30],gBuffer[29]);
}
printf("\n");
printf(" Created on a: ");
TargetComputer(gBuffer[32]);
printf("\n");
printf(" Created with: ");
TargetApp(gBuffer[33]);
printf("\n");
printf(" File attributes: ");
for (i=80;i<96;i++)
{
printf("%02X ",gBuffer[i]);
}
for (i=96;i<128;i++)
{
if (i%16==0)
{
printf("\n ");
}
printf("%02X ",gBuffer[i]);
}
printf("\n\n");
if (gFileType == 2)
{
AnalyseBin(gBuffer+128);
}
free(gBuffer);
free(gFilename);
return 0;
}