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 <stdio.h> #include <stdlib.h> #include <string.h> // 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; }