///////////////////////////////////////////////////////////////////////////////////// // PROGRAM: OD2.exe // // COPYRIGHT: Guillaume Dargaud 2005 - Freeware // // PURPOSE: Similar to Linux od (octal dump) command // // INSTALL: Compile it from a linux command line with: // // cc -o OD2.exe SwapEndian.c OD2.c // // COMPAT: Standard C, works on Windows, Linux... // // HELP: OD2 -h // // TUTORIAL: http://www.gdargaud.net/Hack/BinToAscii.html // // BUGS: There's not a huge amount of error checking being done, so beware // ///////////////////////////////////////////////////////////////////////////////////// #define _VER_ "1.1" // Version 1.0 #define _WEB_ "http://www.gdargaud.net/Hack/BinToAscii.html" #define _COPY_ "© 2005 Guillaume Dargaud" #include #include #include #include #include "SwapEndian.h" #define TRUE 1 #define FALSE 0 #define and && #define or || char HELP[]="OD2 [OPTIONS] [File]\n" "Makes a dump of the binary file specified using various format options.\n" "This program is similar to Unix od (octal dump) but never repeats displays," "it can also intermix formats. Some options are identical:\n" " -A d|o|x|n address radix (decimal, octal, hex or none [default])\n" " -j BYTES skip BYTES bytes at the begining of the file [default 0]\n" " -t FORMAT details the input and output type of the bytes [default u1]\n" " -s Swap endian (apply only to sizes two bytes and above)\n" "\n" "BYTES is hexadecimal with 0x or 0X prefix, it is multiplied by 512 with b suffix, by 1024 with k and by 1048576 with m.\n" "FORMAT is made up of one or more of these specifications:\n" " a named character\n" " c ASCII character or backslash escape\n" " d[SIZE] signed decimal, SIZE bytes per integer (1|2|4)\n" " f[SIZE] floating point, SIZE bytes per integer (4|8)\n" " o[SIZE] octal, SIZE bytes per integer (1|2|4)\n" " u[SIZE] unsigned decimal, SIZE bytes per integer (1|2|4)\n" " x[SIZE] hexadecimal, SIZE bytes per integer (1|2|4)\n\n" "Example: OD2 -A d -t u1u4d2d2d2d2d2d2d2d2 USA.bin\n" "OD2 " _COPY_ ", version " _VER_ ", last compiled on " __DATE__ ; char *Char[256]={"^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "^I", "^J", "^K", "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W", "^X", "^Y", "^Z", "^[", "^\\","^]", "^^", "^_" }; char *Name[256]={"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "TAB", "LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US" }; /////////////////////////////////////////////////////////////////////////////// // Global config char AddressRadix='n'; // d|o|x|n unsigned long SkipBytes=0; // Read from the begining char *Format="u1"; // default int Swap=FALSE; // Swap endian /////////////////////////////////////////////////////////////////////////////// // Read the byte size string. Ex: 0, 0x10, 0100, 10k, 200M... unsigned long BytesStr(char *SizeStr) { unsigned long S; if (strlen(SizeStr)<1) return 0; if (SizeStr[0]=='0') { // hex or octal if (strlen(SizeStr)==1) return 0; if (toupper(SizeStr[1])=='x') S=strtol (SizeStr, NULL, 16); // hex else S=strtol (SizeStr, NULL, 8); // octal } else S=strtol (SizeStr, NULL, 10); // decimal switch (toupper(SizeStr[strlen(SizeStr)-1])) { case 'B': S*=512; break; // blocks case 'K': S*=1024; break; // Kb case 'M': S*=1024*1024; break; // Mb case 'G': S*=1024*1024*1024; break; // Gb // case 'T': S*=1024*1024*1024*1024; break; // Tb } return S; } /////////////////////////////////////////////////////////////////////////////// // Read and convert the file void Dump(FILE *File) { char *FormatRadix=NULL, *CF=NULL; union Multi { signed char C; unsigned char UC; signed short S; unsigned short US; signed long L; unsigned long UL; float F; double D; }; union Multi Buff; unsigned long Size=1, Pos=0; switch (AddressRadix) { case 'd': case 'u':FormatRadix="%08u "; break; case 'o':FormatRadix="%08o "; break; case 'x':FormatRadix="%08X "; break; case 'n': default: FormatRadix=NULL; break; } // Skip initial part // Warning, fseek and fpos are limited to files <2Gb if (0!=fseek (File, SkipBytes, SEEK_SET)) { fprintf(stderr, "Error reading file"); exit(1); } CF=Format; while (! feof(File)) { Pos=ftell(File); switch (*CF) { case 'a': case 'c': Size=1; break; case 'd': case 'o': case 'u': case 'x': switch (*(CF+1)) { case '1': Size=1; break; case '2': Size=2; break; case '4': Size=4; break; default:fprintf(stderr, "Error, integer format must be followed by 1, 2 or 4\n"); exit(1); break; } break; case 'f': switch (*(CF+1)) { case '4': Size=4; break; case '8': Size=8; break; default:fprintf(stderr, "Error, float format must be followed by 4 or 8\n"); exit(1); break; } break; default: fprintf(stderr, "Error, wrong format specification, must be a|c|dN|oN|uN|xN|fN\n"); exit(1); break; } if (1!=fread (&Buff, Size, 1, File)) return; // end of file if (CF==Format and FormatRadix!=NULL) printf(FormatRadix, Pos); if (Size>1 and Swap) memcpy(&Buff, SwapEndian(&Buff, Size), Size); // endian swapping switch (*CF) { case 'a': printf("%s ", Name[Buff.C]); break; case 'c': printf("%s ", Char[Buff.C]); break; case 'd': printf("%d ", Size==1 ? Buff.C : Size==2 ? Buff.S : Buff.L); break; case 'o': printf("%o ", Size==1 ? Buff.UC : Size==2 ? Buff.US : Buff.UL); break; case 'u': printf("%u ", Size==1 ? Buff.UC : Size==2 ? Buff.US : Buff.UL); break; case 'x': printf("%x ", Size==1 ? Buff.UC : Size==2 ? Buff.US : Buff.UL); break; case 'f': printf("%f ", Size==4 ? Buff.F : Buff.D); break; default: fprintf(stderr, "Error, wrong format specification, must be a|c|dN|oN|uN|xN|fN\n"); exit(1); break; } if (*CF=='a' or *CF=='c') CF++; else CF+=2; if (*CF=='\0') { printf("\n"); CF=Format; } // Restart next line } } /////////////////////////////////////////////////////////////////////////////// int main (int argc, char *argv[]) { FILE *File=NULL; int Read=FALSE; int i; // Fill char output arrays for (i=32; i<256; i++) { Char[i]=Name[i]=malloc(2); Char[i][0]=i; Char[i][1]='\0'; } Char[127]=Name[127]="DEL"; // Read command line parameters for (i=1; i