#include #include #include #include #include #include #include "CRTDBG.H" #include "version.h" #ifndef TRUE #define TRUE (-1) #endif #ifndef FALSE #define FALSE (0) #endif #define MAX_LINE_LEN 1024 typedef enum { BIG_ENDIAN, LITTLE_ENDIAN } endian_t; /* * GLOBAL DATA */ FILE *op_stream; FILE *ip_stream; FILE *cmd_stream; int i_op_file_opened = FALSE; int i_ip_file_opened = FALSE; char cmd_line[MAX_LINE_LEN]; int i_had_input_stream_errors = FALSE; fpos_t ip_stream_pos; int ip_stream_pos_valid = FALSE; int ip_stream_pos_cmdLineNumber; long cmdLineNum = 0; int endianism = BIG_ENDIAN; long op_stream_tell[10]; long base_reference = 0; int debug_level = 0; int mustAbort = 0; int exitCode = 0; typedef struct { int cmdLineNumber; fpos_t filepos; } stack_t; #define MAX_STACK 50 stack_t stack[MAX_STACK]; int stackptr = -1; int skippingPastSub = 0; #define DEBUG_CONTROL_CMD_MASK 0x0001 #define DEBUG_OUTPUT_CMD_MASK 0x0002 #define DEBUG_INPUT_CMD_MASK 0x0004 /**************************************************************************/ /* COMMAND REPEAT support */ typedef struct { int cmdLineNumber; fpos_t cmd_stream_pos; int cmd_stream_repeat; } cmd_rep_type; #define MAX_NEST_LEVEL 10 cmd_rep_type cmd_repeat_stack[MAX_NEST_LEVEL]; int cmd_repeat_nest_level = -1; /**************************************************************************/ /* PROTOTYPES */ void ins_quad(unsigned __int64 value); void ins_long(unsigned long value); void ins_word(unsigned long value); void ins_byte(unsigned long value); /**************************************************************************/ char * skip_to_spaces(char * strptr) { while ( (isspace(*strptr) == 0) && (*strptr != 0) ) strptr++; return strptr; } char * skip_past_spaces(char * strptr) { while ( (isspace(*strptr) != 0) && (*strptr != 0) ) strptr++; return strptr; } char * next_value(char * arg_ptr, unsigned long * value, int * got_a_value) { char * endp; unsigned long arg_val = 0; *got_a_value = FALSE; // skip to the first numeric while ( ((*arg_ptr < '0') || (*arg_ptr > '9')) && (*arg_ptr != 0) ) { arg_ptr++; } arg_val = strtoul( arg_ptr, &endp, 0 ); *value = arg_val; if (endp > arg_ptr) *got_a_value = TRUE; arg_ptr = endp; return arg_ptr; } char * next_value64(char * arg_ptr, unsigned __int64 * value, int * got_a_value) { char * endp; unsigned __int64 calc = 0; unsigned long arg_val = 0; *got_a_value = FALSE; // skip to the first numeric while ( ((*arg_ptr < '0') || (*arg_ptr > '9')) && (*arg_ptr != 0) ) { arg_ptr++; } // Process Data endp = arg_ptr; while ( ((*endp >= '0') && (*endp <= '9')) && (*endp != 0) ) { calc = calc * 10; calc += *endp - '0'; endp++; } *value = calc; if (endp > arg_ptr) *got_a_value = TRUE; arg_ptr = endp; return arg_ptr; } char * remove_trailing_spaces(char * pStr) { int str_len = strlen(pStr); if (str_len > 0) { while ( (--str_len >= 0) && (pStr[str_len] == ' ') ) { pStr[str_len] = 0; } } return pStr; } void strip_trailing_comment(char * pStr) { char * comment_ptr; comment_ptr = strchr(pStr, '#'); if (comment_ptr != NULL) *comment_ptr = 0; } void strip_trailing_comment_and_spaces(char * pStr) { char * comment_ptr; comment_ptr = strchr(pStr, '#'); if (comment_ptr != NULL) *comment_ptr = 0; (void)remove_trailing_spaces(pStr); } char * remove_newline_char(char * pStr) { // look for a \n at the end of the string, and if found, remove it int str_len = strlen(pStr); if (str_len > 0) { if (pStr[str_len - 1] == '\n') { pStr[str_len - 1] = 0; } } return pStr; } char * fgets_and_strip_newline(char * s, int n, FILE * stream) { char * retVal; if ((retVal = fgets( s, n, stream )) != NULL) { remove_newline_char(s); } return retVal; } /**************************************************************************/ /* * Errors - Where output file will be compromised * Warnings - less serious ?? */ void ERROR(char * str) { printf("ERROR Line %05ld : %s\n", cmdLineNum, str); mustAbort = 1; } void WARNING(char * str) { printf("WARNING Line %05ld : %s\n", cmdLineNum, str); } void DEBUG( int level, char * fmt, ... ) { if (level & debug_level) { char buff[256]; long offset; va_list arg; va_start(arg, fmt); vsprintf( buff, fmt, arg ); if (i_op_file_opened) { offset = ftell(op_stream); printf( "DEBUG CmdFileLine:%05ld, OutputFilePos:%06ld : %s\n", cmdLineNum, offset, buff ); } else { printf( "DEBUG CmdFileLine:%05ld, OutputFilePos:------ : %s\n", cmdLineNum, buff ); } va_end(arg); } } /**************************************************************************/ long adjusted_op_stream_tell( long var ) { if (op_stream_tell[var] >= base_reference) { return op_stream_tell[var] - base_reference; } else { ERROR("Negative offset"); } return op_stream_tell[var]; } /**************************************************************************/ void fn_DEBUG(char * arg_ptr) { unsigned long value; int got_a_value = TRUE; (void)next_value(arg_ptr, &value, &got_a_value); if (got_a_value) { debug_level = value; } } /**************************************************************************/ void fn_DUP(char * arg_ptr) { unsigned long count, value, i; int got_a_value; DEBUG( DEBUG_OUTPUT_CMD_MASK, "DUP %s", arg_ptr ); arg_ptr = next_value(arg_ptr, &count, &got_a_value); if (got_a_value) { arg_ptr = next_value(arg_ptr, &value, &got_a_value); if (got_a_value) { if (value <= 255) { for (i=0; i 0) ) { fputc(*arg_ptr++, op_stream); value--; } /* Pad output with 0's if necessary */ while ( value > 0) { fputc(0, op_stream); value--; } } else { ERROR("Missing text from NTEXT command"); } } else { ERROR("Bad/missing count/value in NTEXT command"); } } void fn_ZTEXT(char * arg_ptr) { char * initial_arg_ptr = arg_ptr; unsigned long value; int got_a_value; arg_ptr = next_value(arg_ptr, &value, &got_a_value); if (got_a_value) { if ( value <= 1 ) { ERROR("ZTEXT length too short"); } arg_ptr++; /* skip past ',' character */ if (*arg_ptr != 0) { DEBUG( DEBUG_OUTPUT_CMD_MASK, "ZTEXT %s", initial_arg_ptr ); /* feed text to output */ while ( (*arg_ptr != 0) && (value > 1) ) { fputc(*arg_ptr++, op_stream); value--; } /* Pad output with 0's if necessary */ while ( value > 0) { fputc(0, op_stream); value--; } } else { ERROR("Missing text from ZTEXT command"); } } else { ERROR("Bad/missing count/value in ZTEXT command"); } } /**************************************************************************/ void fn_FEED(char * arg_ptr) { unsigned long count, i; int c, got_a_value; (void)next_value(arg_ptr, &count, &got_a_value); if (got_a_value) { DEBUG( DEBUG_OUTPUT_CMD_MASK | DEBUG_INPUT_CMD_MASK, "FEED %s", arg_ptr ); for (i=0; i= 1 && var <= 10) { offset = ftell(op_stream); if (offset == -1L) { ERROR("TELL command failed on output file"); } else { op_stream_tell[var] = offset; DEBUG( DEBUG_CONTROL_CMD_MASK, "TELL %s (result:%ld)", arg_ptr, offset ); } } else { ERROR("Out of range variable number in TELL command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in TELL command"); } } void fn_SEEKTELL(char * arg_ptr) { unsigned long var; int got_a_value; (void)next_value(arg_ptr, &var, &got_a_value); if (got_a_value) { if (var >= 1 && var <= 10) { DEBUG( DEBUG_CONTROL_CMD_MASK, "SEEKTELL %s (offset:%ld)", arg_ptr, op_stream_tell[var] ); if (fseek(op_stream, op_stream_tell[var], SEEK_SET)) { ERROR("SEEKTELL command failed on output file"); } } else { ERROR("Out of range variable number in SEEKTELL command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in SEEKTELL command"); } } void fn_ALIGNMENT(char * arg_ptr, unsigned long requested_alignment) { long offset; offset = ftell(op_stream); if (offset == -1L) { ERROR("ALIGNMENT command failed on output file (ftell)"); } else { unsigned long required_alignment; int got_a_value; (void)next_value(arg_ptr, &required_alignment, &got_a_value); if (got_a_value || requested_alignment) { // allow caller to override the alignment value if (requested_alignment) required_alignment = requested_alignment; if (required_alignment == 2 || required_alignment == 4 || required_alignment == 8) { if (offset & (required_alignment - 1)) { int padding_required = required_alignment - (offset & (required_alignment - 1)); // find out the current output file size if (0==fseek(op_stream, 0, SEEK_END)) { long filesize = ftell(op_stream); if (filesize!=-1L) { // get back to where we were if (0==fseek(op_stream, offset, SEEK_SET)) { if (offset == filesize) { // current position is at the end of the file // We need to append a null byte for the alignment command DEBUG( DEBUG_OUTPUT_CMD_MASK, "ALIGNMENT (appended %d null byte(s))", padding_required ); while (padding_required--) { if (EOF==fputc(0, op_stream)) { ERROR("ALIGNMENT command failed on output file (fputc)"); break; } } } else if (offset < filesize) { // current position is not at the end of the file // We simply need to advance the position by one byte DEBUG( DEBUG_OUTPUT_CMD_MASK, "ALIGNMENT (advanced filepos %d bytes only)", padding_required ); while (padding_required--) { if (0!=fseek(op_stream, 1, SEEK_CUR)) { ERROR("ALIGNMENT command failed on output file (fseek)"); break; } } } else { ERROR("ALIGNMENT command failed on output file (offset)"); } } else { ERROR("ALIGNMENT command failed on output file (fseek)"); } } else { ERROR("ALIGNMENT command failed on output file (ftell)"); } } else { ERROR("ALIGNMENT command failed on output file (fseek)"); } } else { DEBUG( DEBUG_OUTPUT_CMD_MASK, "ALIGNMENT (no padding required)" ); } } else { ERROR("Invalid alignment number in ALIGNMENT command (must be 2, 4, or 8)"); } } else { ERROR("Bad/missing variable number in ALIGNMENT command"); } } } void fn_DWTELL(char * arg_ptr) { unsigned long var; int got_a_value; (void)next_value(arg_ptr, &var, &got_a_value); if (got_a_value) { if (var >= 1 && var <= 10) { DEBUG( DEBUG_OUTPUT_CMD_MASK, "DWTELL %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var) ); ins_word( adjusted_op_stream_tell(var) ); } else { ERROR("Out of range variable number in DWTELL command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in DWTELL command"); } } void fn_DLTELL(char * arg_ptr) { unsigned long var; int got_a_value; (void)next_value(arg_ptr, &var, &got_a_value); if (got_a_value) { if (var >= 1 && var <= 10) { DEBUG( DEBUG_OUTPUT_CMD_MASK, "DLTELL %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var) ); ins_long( adjusted_op_stream_tell(var) ); } else { ERROR("Out of range variable number in DLTELL command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in DLTELL command"); } } void fn_DWTELLSUB(char * arg_ptr) { unsigned long var1; unsigned long var2; int got_a_value; arg_ptr = next_value(arg_ptr, &var1, &got_a_value); if (got_a_value) { if (var1 >= 1 && var1 <= 10) { arg_ptr = next_value(arg_ptr, &var2, &got_a_value); if (got_a_value) { if (var2 >= 1 && var2 <= 10) { DEBUG( DEBUG_OUTPUT_CMD_MASK, "DWTELLSUB %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) ); ins_word( adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) ); } else { ERROR("Out of range variable number in DWTELLSUB command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in DWTELLSUB command"); } } else { ERROR("Out of range variable number in DWTELLSUB command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in DWTELLSUB command"); } } void fn_DLTELLSUB(char * arg_ptr) { unsigned long var1; unsigned long var2; int got_a_value; arg_ptr = next_value(arg_ptr, &var1, &got_a_value); if (got_a_value) { if (var1 >= 1 && var1 <= 10) { arg_ptr = next_value(arg_ptr, &var2, &got_a_value); if (got_a_value) { if (var2 >= 1 && var2 <= 10) { DEBUG( DEBUG_OUTPUT_CMD_MASK, "DLTELLSUB %s (offset value:%ld)", arg_ptr, adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) ); ins_long( adjusted_op_stream_tell(var1) - adjusted_op_stream_tell(var2) ); } else { ERROR("Out of range variable number in DLTELLSUB command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in DLTELLSUB command"); } } else { ERROR("Out of range variable number in DLTELLSUB command (must be 1..10)"); } } else { ERROR("Bad/missing variable number in DLTELLSUB command"); } } void fn_SETBASE(char * arg_ptr) { long offset; offset = ftell(op_stream); if (offset == -1L) { ERROR("SETBASE command failed on output file"); } else { DEBUG( DEBUG_CONTROL_CMD_MASK, "SETBASE %s (base_reference:%ld)", arg_ptr, base_reference ); base_reference = offset; } } /**************************************************************************/ void fn_REPEAT(char * arg_ptr) { unsigned long count; int got_a_value; fpos_t stream_pos; (void)next_value(arg_ptr, &count, &got_a_value); if (got_a_value) { if (fgetpos(cmd_stream, &stream_pos) == 0) { if (cmd_repeat_nest_level < (MAX_NEST_LEVEL - 1)) { cmd_repeat_nest_level++; cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_pos = stream_pos; cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat = count; cmd_repeat_stack[cmd_repeat_nest_level].cmdLineNumber = cmdLineNum; DEBUG( DEBUG_CONTROL_CMD_MASK, "REPEAT %s (nesting:%d, pos:%ld)", arg_ptr, cmd_repeat_nest_level, stream_pos ); } else { ERROR("REPEAT command nested too deeply"); } } else { ERROR("REPEAT command failed to get current cmd file position"); } } else { ERROR("Bad/missing count value in REPEAT command"); } } void fn_END(char * arg_ptr) { if (cmd_repeat_nest_level >= 0) { if (cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat > 0) { cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat--; DEBUG( DEBUG_CONTROL_CMD_MASK, "END-REPEAT (nesting:%d)", cmd_repeat_nest_level ); if (cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_repeat > 0) { if (fsetpos(cmd_stream, &(cmd_repeat_stack[cmd_repeat_nest_level].cmd_stream_pos))) { ERROR("END could not restore cmd file position"); } else { cmdLineNum = cmd_repeat_stack[cmd_repeat_nest_level].cmdLineNumber; } } else { cmd_repeat_nest_level--; } } else { DEBUG( DEBUG_CONTROL_CMD_MASK, "END-REPEAT (nesting:%d)", cmd_repeat_nest_level ); cmd_repeat_nest_level--; } } else { ERROR("END could not be matched to a previous REPEAT command"); } } /**************************************************************************/ void fn_FEEDFILE(char * arg_ptr) { FILE * fip_stream; arg_ptr = skip_past_spaces(arg_ptr); if( (fip_stream = fopen( arg_ptr, "rb" )) != NULL ) { int c; DEBUG( DEBUG_OUTPUT_CMD_MASK, "FEEDFILE %s", arg_ptr ); c = fgetc(fip_stream); while (c != EOF) { fputc(c, op_stream); c = fgetc(fip_stream); } fclose(fip_stream); } else { ERROR("Could not open file"); } } /**************************************************************************/ void fn_NAMEVAR(char * arg_ptr) { char * initial_arg_ptr = arg_ptr; unsigned long variantType; unsigned long dataSize; int got_a_value; arg_ptr = next_value(arg_ptr, &variantType, &got_a_value); if (got_a_value) { while ( (*arg_ptr != ',') ) arg_ptr++; if (*arg_ptr == ',') arg_ptr++; arg_ptr = skip_past_spaces(arg_ptr); // put the representation type variantType = (0x1000 + variantType) & 0xFFFF; dataSize = strlen(arg_ptr); dataSize++; // Account for null trerminator if (dataSize & 1) // Do alignment dataSize++; DEBUG( DEBUG_OUTPUT_CMD_MASK, "NAMEVAR %s (variantType:%d, dataSize:%d)", initial_arg_ptr, variantType, dataSize ); ins_word(variantType); ins_word(dataSize); // put the text while (*arg_ptr != 0) fputc(*arg_ptr++, op_stream); fputc(0, op_stream); // put null terminator fn_ALIGNMENT(arg_ptr, 2); // do alignment } else { ERROR("Bad/missing variantType value in NAMEVAR command"); } } /**************************************************************************/ void fn_GOSUB(char * arg_ptr) { char * initial_arg_ptr = arg_ptr; // Read subroutine name static char subname[256]; static char *subnameptr = &subname[0]; static int subnamelen = 0; static fpos_t subposition; int found = 0; *subnameptr = 0; if (*arg_ptr != 0) { if (stackptr < (MAX_STACK-1)) { fpos_t fposition; if (fgetpos(cmd_stream, &fposition) == 0) { if (strlen(arg_ptr) > 250) { ERROR("GOSUB subroutine name too long"); } else { // Get subname, subnameptr, subnamelen subnameptr = &subname[0]; while (*arg_ptr != 0) *subnameptr++ = *arg_ptr++; *subnameptr = 0; subnamelen = strlen(subname); if (subnamelen == 0) { ERROR("GOSUB subroutine name missing"); } else { // scan cmd file from the beginning, for the subroutine of the required name if (0==fseek(cmd_stream, 0, SEEK_SET)) { char * cmd_args; long tempCmdLineNum = 1; fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream ); do { cmd_args = skip_to_spaces(cmd_line); cmd_args = skip_past_spaces(cmd_args); if (strnicmp(cmd_line, "SUB", 3) == 0) { if (strnicmp(subname, cmd_args, subnamelen) == 0) { // capture cmd file position where the subroutine begins if (fgetpos(cmd_stream, &subposition) == 0) { stackptr++; stack[stackptr].filepos = fposition; stack[stackptr].cmdLineNumber = cmdLineNum; DEBUG( DEBUG_CONTROL_CMD_MASK, "GOSUB %s", subname ); cmdLineNum = tempCmdLineNum; found = 1; break; } else { ERROR("GOSUB failed to get cmd stream subroutine filepos"); } } } tempCmdLineNum++; } while (fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream ) != NULL); if (!found) { ERROR("GOSUB could not find subroutine"); } } else { ERROR("GOSUB failed to seek to beginning of cmd file"); } } } } else { ERROR("GOSUB failed to get cmd stream calling filepos"); } } else { ERROR("GOSUB out of stack space"); } } } /**************************************************************************/ void fn_MSG(char * arg_ptr) { if (*arg_ptr != 0) { printf( arg_ptr ); } } /**************************************************************************/ void fn_OUTPUT_FILE(char * arg_ptr) { char filename[1024]; char * pFilename = filename; if (*arg_ptr != 0) { while (*arg_ptr != 0) { *pFilename++ = *arg_ptr++; } *pFilename = 0; if (i_op_file_opened) { i_op_file_opened = FALSE; fclose(op_stream); } if( (op_stream = fopen( filename, "wb" )) == NULL ) { char buff[2048]; sprintf(buff, "Could not open output file %s", filename ); ERROR( buff ); } else { i_op_file_opened = TRUE; DEBUG( DEBUG_OUTPUT_CMD_MASK, "OUTPUT_FILE %s", filename ); } } else { ERROR("Missing filename from OUTPUT_FILE command"); } } /**************************************************************************/ int InputFileOpen(void) { if (!i_ip_file_opened) { ERROR("No binary input file has been specified"); return FALSE; } else { return TRUE; } } int OutputFileOpen(void) { if (!i_op_file_opened) { ERROR("No binary output file has been specified"); return FALSE; } else { return TRUE; } } /**************************************************************************/ void do_binflow_processing(void) { char * cmd_args; if (fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream ) == NULL) { printf("ERROR : Command File is empty\n"); return; } else { do { cmdLineNum++; if (cmd_line[0] != 0) { cmd_args = skip_to_spaces(cmd_line); cmd_args = skip_past_spaces(cmd_args); if (skippingPastSub) { if (strnicmp(cmd_line, "SUB", 3) == 0) { ERROR("SUBROUTINE definition nesting is prohibited"); } else if (strnicmp(cmd_line, "ENDSUB", 6) == 0) { skippingPastSub = 0; } } else if (strnicmp(cmd_line, "LITTLE_ENDIAN", 13) == 0) { endianism = LITTLE_ENDIAN; } else if (strnicmp(cmd_line, "BIG_ENDIAN", 10) == 0) { endianism = BIG_ENDIAN; } else if (strnicmp(cmd_line, "OUTPUT_FILE", 11) == 0) { strip_trailing_comment_and_spaces( cmd_line ); fn_OUTPUT_FILE(cmd_args); } else if (strnicmp(cmd_line, "BREAKPOINT", 10) == 0) { _CrtDbgBreak(); } else if (strnicmp(cmd_line, "SEEKSTART", 9) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_SEEKSTART(cmd_args); } else if (strnicmp(cmd_line, "DWTELLSUB", 9) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DWTELLSUB(cmd_args); } else if (strnicmp(cmd_line, "DLTELLSUB", 9) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DLTELLSUB(cmd_args); } else if (strnicmp(cmd_line, "ALIGNMENT", 9) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_ALIGNMENT(cmd_args, 0); } else if (strnicmp(cmd_line, "SEEKTELL", 8) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_SEEKTELL(cmd_args); } else if (strnicmp(cmd_line, "FEEDFILE", 8) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_FEEDFILE(cmd_args); } else if (strnicmp(cmd_line, "SEEKEND", 7) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_SEEKEND(cmd_args); } else if (strnicmp(cmd_line, "SEEKCUR", 7) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_SEEKCUR(cmd_args); } else if (strnicmp(cmd_line, "NAMEVAR", 7) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_NAMEVAR(cmd_args); } else if (strnicmp(cmd_line, "SETBASE", 7) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_SETBASE(cmd_args); } else if (strnicmp(cmd_line, "ENDSUB", 6) == 0) { if (stackptr > -1) { if (fsetpos(cmd_stream, &stack[stackptr].filepos)) { ERROR("ENDSUB failed to return to calling point"); } else { DEBUG( DEBUG_CONTROL_CMD_MASK, "ENDSUB" ); cmdLineNum = stack[stackptr].cmdLineNumber; stackptr--; } } else { ERROR("ENDSUB unexpected at this time"); } } else if (strnicmp(cmd_line, "REWIND", 6) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (InputFileOpen()) fn_REWIND(cmd_args); } else if (strnicmp(cmd_line, "REPEAT", 6) == 0) { strip_trailing_comment_and_spaces( cmd_line ); fn_REPEAT(cmd_args); } else if (strnicmp(cmd_line, "DWTELL", 6) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DWTELL(cmd_args); } else if (strnicmp(cmd_line, "DLTELL", 6) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DLTELL(cmd_args); } else if (strnicmp(cmd_line, "DEBUG", 5) == 0) { strip_trailing_comment_and_spaces( cmd_line ); fn_DEBUG(cmd_args); } else if (strnicmp(cmd_line, "NTEXT", 5) == 0) { strip_trailing_comment( cmd_line ); if (OutputFileOpen()) fn_NTEXT(cmd_args); } else if (strnicmp(cmd_line, "ZTEXT", 5) == 0) { strip_trailing_comment( cmd_line ); if (OutputFileOpen()) fn_ZTEXT(cmd_args); } else if (strnicmp(cmd_line, "ALIGN", 5) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_ALIGNMENT(cmd_args, 2); } else if (strnicmp(cmd_line, "GOSUB", 5) == 0) { strip_trailing_comment_and_spaces( cmd_line ); fn_GOSUB(cmd_args); } else if (strnicmp(cmd_line, "FEED", 4) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen() && InputFileOpen()) fn_FEED(cmd_args); } else if (strnicmp(cmd_line, "SKIP", 4) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (InputFileOpen()) fn_SKIP(cmd_args); } else if (strnicmp(cmd_line, "TEXT", 4) == 0) { strip_trailing_comment( cmd_line ); if (OutputFileOpen()) fn_TEXT(cmd_args); } else if (strnicmp(cmd_line, "MARK", 4) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (InputFileOpen()) fn_MARK(cmd_args); } else if (strnicmp(cmd_line, "TELL", 4) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_TELL(cmd_args); } else if (strnicmp(cmd_line, "DUP", 3) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DUP(cmd_args); } else if (strnicmp(cmd_line, "END", 3) == 0) { strip_trailing_comment_and_spaces( cmd_line ); fn_END(cmd_args); } else if (strnicmp(cmd_line, "MSG", 3) == 0) { strip_trailing_comment_and_spaces( cmd_line ); fn_MSG(cmd_args); } else if (strnicmp(cmd_line, "SUB", 3) == 0) { if (stackptr > -1) { ERROR("SUBROUTINE definition nesting is prohibited"); } else { skippingPastSub = 1; } } else if (strnicmp(cmd_line, "DB", 2) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DB(cmd_args); } else if (strnicmp(cmd_line, "DW", 2) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DW(cmd_args); } else if (strnicmp(cmd_line, "DL", 2) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DL(cmd_args); } else if (strnicmp(cmd_line, "DQ", 2) == 0) { strip_trailing_comment_and_spaces( cmd_line ); if (OutputFileOpen()) fn_DQ(cmd_args); } else { if ( ( cmd_line[0] != ' ' ) && ( cmd_line[0] != 0 ) && ( cmd_line[0] != '\n' ) && ( cmd_line[0] != '#' ) ) { printf("ERROR on line %u of command file\n\n", cmdLineNum); printf(" %s\n", cmd_line); printf(" ^\n"); printf(" |\n"); printf(" | Unknown Command\n"); mustAbort = 1; break; } } } if (mustAbort) break; } while (fgets_and_strip_newline( cmd_line, MAX_LINE_LEN, cmd_stream ) != NULL); } } /**************************************************************************/ void newline(void) { printf("\n"); } void header(void) { newline(); printf("%s, by Gordon Huddy, %s\n", BUILDNAME, BUILDDATE); newline(); } void commands(void) { header(); printf("Processor commands:-\n"); newline(); printf(" COMMAND FILE COMMANDS --------------------------------------------------------------------------\n\n"); printf(" # 'Start of comment' marker in command file\n"); printf(" REPEAT n Specify a command block to be repeated n times\n"); printf(" END Marks the end of a repeated command block\n"); printf(" DEBUG mask Turns on debug\n"); printf(" Masks: 1 = Command File Control commands\n"); printf(" 2 = Output Binary File commands\n"); printf(" 4 = Input Binary File commands\n"); printf(" MSG text Sends the message text to stdout\n"); newline(); printf(" NB. REPEAT-END commands can be nested (Max Level %d)\n", MAX_NEST_LEVEL); newline(); printf(" OUTPUT BINARY FILE COMMANDS---------------------------------------------------------------------\n\n"); printf(" DUP n,v Add the 8-bit value v to the output file, n times\n"); printf(" DB v,v,..,v Add the specified list of 8-bit values to the output file\n"); printf(" DW v,v,..,v Add the specified list of 16-bit values to the output file\n"); printf(" DL v,v,..,v Add the specified list of 32-bit values to the output file\n"); printf(" DQ v,v,..,v Add the specified list of 64-bit values to the output file\n"); printf(" TEXT text Add the specified text to the output file\n"); printf(" NTEXT v,text Add exactly v characters of the specified text to the output file\n"); printf(" - pad output file with 0's if insufficient text provided\n"); printf(" ZTEXT v,text Add exactly v-1 characters and a NULL terminator of the specified text to the output file\n"); printf(" BIG_ENDIAN Turn Big-endian on (default behaviour)\n"); printf(" LITTLE_ENDIAN Turn Big-endian off\n"); printf(" OUTPUT_FILE name Opens a new Output File, closing the previous one\n"); printf(" SEEKSTART offset Seeks to the specified offset from the start of the output file\n"); printf(" SEEKEND offset Seeks to the specified offset from the end of the output file\n"); printf(" SEEKCUR offset Seeks to the specified offset from the current position in the output file\n"); printf(" TELL var Saves current position in the output file to internal variable 1..10\n"); printf(" SEEKTELL var Using internal variable 1..10, seeks to the saved position in the output file\n"); printf(" DWTELL var Using internal variable 1..10, adds the saved position as a 16-bit value to the output file\n"); printf(" DLTELL var Using internal variable 1..10, adds the saved position as a 32-bit value to the output file\n"); printf(" DWTELLSUB var1, var2 Using internal variables 1..10, adds the difference between saved positions (var1 - var2)\n"); printf(" as a 16-bit value to the output file\n"); printf(" DLTELLSUB var1, var2 Using internal variables 1..10, adds the difference between saved positions (var1 - var2)\n"); printf(" as a 32-bit value to the output file\n"); printf(" SETBASE Sets the base reference from which offsets in internal variables 1..10 are measured,\n"); printf(" to the current output file position (default = beginning of output file)\n"); printf(" SETBASE only affects the values DLTELL and DWTELL write.\n"); printf(" ALIGN If current file position is odd, advances it by 1 byte (equivalent to 'ALIGNMENT 2' command)\n"); printf(" ALIGNMENT v Performs specified alignment - v must be 2, 4, or 8\n"); printf(" NAMEVAR vt,text Add the specified name variant type to the output file\n"); printf(" SUB name Begin Defining a subroutine\n"); printf(" ENDSUB End the definition of a subroutine\n"); printf(" GOSUB name Call a subroutine\n"); printf(" FEEDFILE filename Feed the entire contents of the file with the given name to the output file\n"); newline(); printf(" INPUT BINARY FILE COMMANDS---------------------------------------------------------------------\n\n"); printf(" FEED n Feed n bytes from the input file to the output file\n"); printf(" SKIP n Skip n bytes of the input file\n"); printf(" MARK 'Marks' current position in input file\n"); printf(" REWIND Return to 'Marked' position in input file\n"); newline(); } void usage(void) { header(); printf("BINFLOW /c=cmdfile [/o=outfile] [/i=infile] [/d=mask] \n"); newline(); printf(" /c=cmdfile : Compulsory - contains your processor command script.\n"); printf(" /o=outfile : Optional - Specifies an output file. This switch can be\n"); printf(" omitted if the cmdfile itself specifies one or more output files.\n"); printf(" /i=infile : Optional - Specifies a binary input file containing some data that must find\n"); printf(" its way through to the outfile under control of the script commands given in\n"); printf(" the cmdfile.\n"); printf(" /d=mask : Optional - Identical to the operation of the DEBUG command inside a cmdfile\n"); newline(); printf(" This program enables you to produce a binary file from a command file\n"); printf(" description using simple commands. Some commands allow data from a source\n"); printf(" binary file to be passed to the output file also. The command file\n"); printf(" is processed sequentially.\n"); newline(); printf(" Type BINFLOW ? for a summary of commands available\n"); newline(); } int main( int argc, /* Number of strings in array argv */ char *argv[], /* Array of command-line argument strings */ char **envp ) /* Array of environment variable strings */ { char * pCmdFilename = NULL; char * pOutputFilename = NULL; char * pInputFilename = NULL; int showUsage = FALSE; int showCommands = FALSE; int argi = 1; if (argi == argc) { showUsage = TRUE; goto binflow_exit; } while (argi < argc) { char * pArg = argv[argi]; if (pArg[0] == '/' || pArg[0] == '\\') { if ( strlen(pArg) > 3 ) { switch(pArg[1]) { case 'c' : pCmdFilename = &pArg[3]; break; case 'i' : pInputFilename = &pArg[3]; break; case 'o': pOutputFilename = &pArg[3]; break; case 'd': fn_DEBUG(pArg); break; default: printf("ERROR : Unrecognized command line switch (%s)\n", pArg ); showUsage = TRUE; goto binflow_exit; break; } } else { printf("ERROR : Command line switch appears incomplete or malformed (%s)\n", pArg ); showUsage = TRUE; goto binflow_exit; } } else if (pArg[0] == '?' ) { showCommands = TRUE; goto binflow_exit; } else { printf("ERROR : Unrecognized command line switch (%s)\n", pArg ); showUsage = TRUE; goto binflow_exit; } argi++; } if (pCmdFilename) { if( (cmd_stream = fopen( pCmdFilename, "r" )) == NULL ) { printf("ERROR : Could not open command file\n"); goto binflow_exit; } } else { printf("ERROR : A command file must be specified\n"); showUsage = TRUE; goto binflow_exit; } if (pOutputFilename) { if( (op_stream = fopen( pOutputFilename, "wb" )) == NULL ) { fclose(cmd_stream); printf("ERROR : Could not open output file\n"); mustAbort = 1; goto binflow_exit; } else { i_op_file_opened = TRUE; } } if (pInputFilename) { if( (ip_stream = fopen( pInputFilename, "rb" )) == NULL ) { fclose(cmd_stream); if (pOutputFilename) fclose(op_stream); printf("ERROR : Could not open binary input file\n"); goto binflow_exit; } else { i_ip_file_opened = TRUE; } } do_binflow_processing(); fclose(op_stream); fclose(cmd_stream); if (i_ip_file_opened) fclose(ip_stream); if (i_had_input_stream_errors) { printf("ERROR : Errors occurred when reading your input data file\n"); mustAbort = 1; } if (mustAbort) { exitCode = 1; if ( pOutputFilename ) unlink (pOutputFilename); } return exitCode; binflow_exit: exitCode = 2; if (showUsage) { usage(); } else if (showCommands) { commands(); } return exitCode; } /************************************************************************************************************/ /** ENDIAN CONVERSION FUNCTIONS *****************************************************************************/ /************************************************************************************************************/ void ins_byte(unsigned long value) { fputc(value & 255, op_stream); } void ins_word(unsigned long value) { if (endianism == BIG_ENDIAN) { fputc((value >> 8) & 255, op_stream); fputc(value & 255, op_stream); } else { fputc(value & 255, op_stream); fputc((value >> 8) & 255, op_stream); } } void ins_long(unsigned long value) { if (endianism == BIG_ENDIAN) { fputc((value >> 24) & 255, op_stream); fputc((value >> 16) & 255, op_stream); fputc((value >> 8 ) & 255, op_stream); fputc(value & 255, op_stream); } else { fputc(value & 255, op_stream); fputc((value >> 8 ) & 255, op_stream); fputc((value >> 16) & 255, op_stream); fputc((value >> 24) & 255, op_stream); } } void ins_quad(unsigned __int64 value) { if (endianism == BIG_ENDIAN) { fputc((int)(value >> 7*8) & 255, op_stream); fputc((int)(value >> 6*8) & 255, op_stream); fputc((int)(value >> 5*8) & 255, op_stream); fputc((int)(value >> 4*8) & 255, op_stream); fputc((int)(value >> 3*8) & 255, op_stream); fputc((int)(value >> 2*8) & 255, op_stream); fputc((int)(value >> 1*8) & 255, op_stream); fputc((int)(value) & 255, op_stream); } else { fputc((int)value & 255, op_stream); fputc((int)(value >> 1*8 )& 255, op_stream); fputc((int)(value >> 2*8) & 255, op_stream); fputc((int)(value >> 3*8) & 255, op_stream); fputc((int)(value >> 4*8) & 255, op_stream); fputc((int)(value >> 5*8) & 255, op_stream); fputc((int)(value >> 6*8) & 255, op_stream); fputc((int)(value >> 7*8) & 255, op_stream); } } /* END OF File */