#include #include /* Force stdin into binary mode if running cygwin */ #ifdef __CYGWIN__ #include #include void stdin_setup() { if (setmode(0,O_BINARY)==EOF) { fprintf(stderr,"\nImage read error.\n"); exit(1); } } #else void stdin_setup() {} #endif #define min(a,b) (((a)>(b))?(b):(a)) #define TOKEN_RECORD 0 #define TOKEN_NUMBER 1 #define TOKEN_FUNCTION 2 #define FUNCTION_STARTLIST 0 #define FUNCTION_ENDLIST 1 #define FUNCTION_STARTFOLD 2 #define FUNCTION_ENDFOLD 3 #define FUNCTION_STARTFILED 4 #define FUNCTION_ENDFILED 5 /* Declaration needed here as they can get called mutually recursively */ void parse_fold_body(void); void parse_filed_body(void); /* We hold the current fold name as a global because only one * copy is ever needed; it is not used accross recursive calls. * Making it a single global saves a lot of stack space compared * to declaring it inside parse_fold_body and parse_filed_body */ unsigned char ns[2048]; int current_byte = 0; int current_indent; /* We default current_type to default to a binary type for worst-case * readabilityas text */ int current_type=1; void indent() { int i=current_indent; while (i--) putchar(' '); } void fold_error() { fprintf(stderr,"\nFolded file format error at byte %d\n",current_byte); exit(1); } int safe_getchar() { int c; if ((c=getchar())==EOF) fold_error(); current_byte++; return c; } int get_token(int *value) { int c; *value = 0; /* Handle prefix bytes */ while (((c=safe_getchar())&0xc0)==0xc0) { *value |= c&0x3f; *value <<= 6; } *value |= c&0x3f; return (c &0xc0) >> 6; } void check_function(int f) { int v; if (get_token(&v) != TOKEN_FUNCTION || v != f) fold_error(); } void parse_record_body(int v) { int i; switch (current_type) { case 1: case 2: for (i=0;i= ARRAY_SIZE(attribute_type)) fold_error(); if (get_token(attr_content) != TOKEN_NUMBER) fold_error(); if (*attr_content<0 || *attr_content >= ARRAY_SIZE(attribute_content)) fold_error(); if (get_token(local_indent) != TOKEN_NUMBER) fold_error(); if (*local_indent<0) fold_error(); } void parse_elements() { int v; while(1) { switch(get_token(&v)) { case TOKEN_RECORD: parse_record_body(v); break; case TOKEN_NUMBER: printf("N %d\n",v); break; case TOKEN_FUNCTION: switch (v) { case FUNCTION_STARTFOLD: parse_fold_body(); break; case FUNCTION_STARTFILED: parse_filed_body(); break; case FUNCTION_ENDLIST: return; break; default: fold_error(); break; } break; default: fold_error(); break; } } } void parse_list() { int v; check_function(FUNCTION_STARTLIST); parse_elements(); } void parse_fold_body() { unsigned char ns[2048]; int i, len, attr_type, attr_content, local_indent; check_function(FUNCTION_STARTLIST); if (get_token(&len) != TOKEN_RECORD) fold_error(); if (len > 2048) { fprintf(stderr,"\nFold header overflow at byte %d\n",current_byte); exit(1); } for (i=0;i 2048) { fprintf(stderr,"\nFold header overflow at byte %d\n",current_byte); exit(1); } for (i=0;i 1) { if (argc ==2 && !strcmp("-t",argv[1])) current_type = 0; else { fprintf(stderr,"Usage: tdsfile [-t] < disk_image\n" " -t: Assume data outside any fold is text.\n" "Decodes folded file to stdout. Non-text folds and, by default (no -t), the outermost\n" "data is dumped as 16 byte hex lines, with additional newline between records.\n"); exit(1); } } parse_list(); if (current_indent!=0 ) /* This is really an internal error---it can't(!) happen */ fold_error(); exit(0); }