/* Uncompress program. Adapted from a version written by Keith Calkins that was last modified Nov 29, 1996. Written in C by Tom Watson Jan 08,'97. */ /* How to use: The program has ONE parameter. It is the file name of the Sigma format compressed file. It creates a text file with the suffix ".co" added to the original file that is the uncompressed file. The program allows the input to be either 108 bytes (without sequence numbers) or 120 bytes (with sequence numbers) as long as the compressed data is intact. The de- blocker program takes the record size of the original file when it is written out, so this is a necessary feature. When writing the compressed file, trailing blanks are removed, as this can take up considerable space, and the line terminator '\n' is inserted. On various systems this will add (Unix), MS-DOS or Mac's MPW. It should be proper for the system. If there are any questions, or comments, please contact the author at "tsw@johana.com" (home email address), or "tsw@3do.com" (present employer's address). */ /* Please note that some debugging stuff has been "#ifdef'd" out. I used it to make sure the program was operational. Some of the trailing bits in a record gets very tricky at times. */ /* The author would like to know of your successes/failures/etc. in using this program. Notes to the email addresses above are appreciated. Please do not publish/distrubute this program without notifying the author. I'd just like to know where it has been. Tom Watson Jan 10, 1997 */ #include #include /* #define DEBUG */ /* #define DEBUG1 */ #include "ebcdictw.h" /* Translate table */ #define REC_LEN 108 /* Standard compressed record length, with no sequence numbers (col 73-80). */ #define ID_BYTE 0x18 /* Binary record type (0x38/0x18) */ /* Global thing to translate */ static unsigned char alpha[] = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.<(+|&$*);~-/,%_>:'="; int chars_in_debug = 0; #ifdef DEBUG FILE *debug; static void test_debug(int incr); #endif int get_bits (FILE *file_ref, int num_bits); int main (int argc, char *argv[]) { FILE *input; FILE *output = NULL; int six_bit; int end_file; int rec_pos; int i; unsigned char out_rec[8192]; char out_file_name[200]; /* It may have a path!! */ if (argc != 2) { fprintf (stderr, "File specification??\n"); exit (1); } input = fopen (argv[1], "rb"); if (input == NULL) { fprintf (stderr, "Input file error. Name? \n"); exit (1); } strcpy (out_file_name, argv[1]); strcat (out_file_name, ".so"); output = fopen (out_file_name, "w"); if (output == NULL) { fprintf (stderr, "Can't open output file named: %s\n", out_file_name); exit (1); } #ifdef DEBUG debug = fopen ("debug_file", "w"); #endif end_file = 0; rec_pos = 0; /* Position in record */ /* Gather the input, send to output */ while (!end_file) { six_bit = get_bits (input, 6); #ifdef DEBUG fprintf (debug, "RP: %d ", rec_pos); test_debug (7); if (rec_pos > 100) /* I'm getting an error here?!? */ { fprintf (stderr, "Record position out of range: %d\n", rec_pos); exit (1); } #endif switch (six_bit) { case 0: /* Padding */ break; case 1: fprintf (stderr, "Illegal 6 bit goodie (0x%02X)\n", six_bit); break; case 2: /* End of record */ /* Strip off blanks, so we won't take up so much room!! */ for (i = 0; i < rec_pos; i++) { if (out_rec[rec_pos - i - 1] != ' ') break; } #ifdef DEBUG fprintf (debug, "I: %d ", i); test_debug (6); #endif out_rec[rec_pos - i] = '\n'; fwrite (out_rec, 1, rec_pos - i + 1, output); rec_pos = 0; /* So we can fill it up from the beginning!! */ break; case 3: /* End of file */ end_file = 1; break; case 4: /* Get the next 8 bits */ #ifdef DEBUG fprintf (debug, "8B"); #endif out_rec[rec_pos++] = ebcdic [get_bits (input, 8)]; break; case 5: /* n + 1 blanks */ six_bit = get_bits (input, 6); six_bit += 1; for (i = 0; i < six_bit; i++) out_rec[rec_pos++] = ' '; break; case 6: /* n + 65 blanks */ six_bit = get_bits (input, 6); six_bit += 65; for (i = 0; i < six_bit; i++) out_rec[rec_pos++] = ' '; break; default: out_rec[rec_pos++] = alpha[six_bit]; #ifdef DEBUG fputc (alpha[six_bit], debug); fputc (' ', debug); test_debug (2); #endif break; } } fclose (output); fclose (input); return 0; } int get_bits (FILE *file_ref, int num_bits) { static unsigned char in_rec[REC_LEN]; static int bit_pos = -1; /* No record read in yet. */ static int rec_seq = 0; static int bytes_in_rec; int bytes_read; int temp_char; int result = 0; int i; int checksum; int the_byte; int bits_avail; static int mask[8] = {0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; while (num_bits != 0) { if (bit_pos == -1 || bit_pos + num_bits > bytes_in_rec * 8) { /* We need to read a new record */ while (1) { temp_char = fgetc (file_ref); if (temp_char == EOF) { fprintf (stderr, "End file encountered abnormally\n"); exit (1); } if ((temp_char | 0x20) == 0x38) { /* We have the proper first byte of a record!! */ ungetc (temp_char, file_ref); /* Put it back */ break; } } bytes_read = fread (in_rec, 1, REC_LEN, file_ref); if (bytes_read != REC_LEN) { fprintf (stderr, "Funny record correspondance\n"); exit (1); } /* See that record sequence matches */ if (in_rec[1] != (rec_seq & 0xFF)) { fprintf (stderr, "Sequence match. Is: 0x%02X, Should be: 0x%02X\n", in_rec[1], (rec_seq & 0xFF)); exit (1); } #ifdef DEBUG fprintf (debug, "S:%d ", rec_seq); test_debug (5); #endif rec_seq++; /* Increment the sequence number */ /* See that things are in the correct range */ bytes_in_rec = in_rec[3]; if (bytes_in_rec <= 5 || bytes_in_rec > 108) { fprintf (stderr, "Record size (%d) out of range\n", in_rec[3]); exit (1); } /* Calculate the checksum */ checksum = 0; for (i = 0; i < bytes_in_rec; i++) { if (i == 2) continue; /* Not the checksum byte */ checksum += in_rec[i]; } if ((checksum & 0xFF) != in_rec[2]) { fprintf (stderr, "Checksum doesn't match. Is: 0x%02X, Should be: 0x%02X\n", checksum & 0xFF, in_rec[2]); exit (1); } bit_pos = 32; /* Skip the first 4 bytes */ } /* We have a position here, get some */ the_byte = in_rec[bit_pos >> 3]; /* fprintf (debug, "B: 0x%03X ", the_byte); */ /* test_debug (9); */ bits_avail = 8 - (bit_pos & 0x07); if (bits_avail >= num_bits) { /* We can get them all!! */ result <<= num_bits; the_byte >>= bits_avail - num_bits; result |= the_byte & mask[num_bits - 1]; bit_pos += num_bits; /* We got this many */ num_bits = 0; } else { /* Only partial in a byte */ /* fprintf (debug, "OR: 0x%02X ", result); */ result <<= bits_avail; /* fprintf (debug, "MR: 0x%02X ", result); */ result |= the_byte & mask[bits_avail - 1]; /* fprintf (debug, "NR: 0x%02X ", result); */ /* test_debug (9 * 3); */ bit_pos += bits_avail; num_bits -= bits_avail; } #ifdef DEBUG1 fprintf (debug, "BP: %d ", bit_pos); test_debug (7); #endif } #ifdef DEBUG1 fprintf (debug, "0x%02X ", result); test_debug(5); #endif return result; } #ifdef DEBUG static void test_debug(int incr) { chars_in_debug += incr; if (chars_in_debug > 80) { fputc ('\n', debug); chars_in_debug = 0; } fflush (debug); } #endif