/* * intstk.c * * This program stacks executable code into a file. The file format is as * follows: * * 0000 - 0040 Header * 0040 - xxxx Interface 1 * xxxx - yyyy Interface 2 * yyyy - zzzz Interface 3 * ... * * We assume the file is at most SEG_MAX bytes long. Any bytes beyond this * limit is ignored. * * Syntax: intstk [-a] -o outfile intfc1 [...] * * -a Append to output file. * -o Filename of output file. */ #include #include #include #include #define HDR_MAGIC 0x5d5e #define HDR_MAX 31 #define SEG_MAX 4096 /* Data structure containing interface executable code information. */ struct header { short offset; short len; }; /* * Array of interface information. This is written to the output file * as the header. */ struct header_list { short magic; short len; struct header hdr[HDR_MAX]; }; short file_size(FILE *fp) { long size; if (fseek(fp, 0L, SEEK_END) != 0) return 0; size = ftell(fp); if (fseek(fp, 0L, SEEK_SET) != 0) return 0; if (size == -1L) return 0; return (short) size; } int file_copy(FILE *out, FILE *in, short len) { short *buf; if (out == 0 || in == 0 || len > SEG_MAX) return 1; buf = calloc(sizeof(short), len); fread(buf, sizeof(short), len, in); if (ferror(in) != 0) goto error_handler; if (fwrite(buf, sizeof(short), len, out) != (size_t) len) goto error_handler; return 0; error_handler: free(buf); return 1; } void calc_chksum(const char *fn) { unsigned short chksum = 0; unsigned short value; FILE *fp = fopen(fn, "r+b"); if (fp == 0) { fprintf(stderr, "File '%s' not found.\n", fn); return; } while (1 == 1) { fread(&value, sizeof(value), 1, fp); if (feof(fp)) break; chksum += value; } /* Write checksum to end of file. Checksum is in ones-complement. */ chksum = ~(chksum); if (fwrite(&chksum, sizeof(chksum), 1, fp) != 1) fprintf(stderr, "Error writing to file '%s'.\n", fn); } int main(int argc, char *argv[]) { int idx = 1; int append = 0; struct header_list hdr; char *out_filename = 0; FILE *out_file = 0; FILE *in_file = 0; if (argc < 2) { fprintf(stderr, "syntax: %s [-a] -o outfile intfc1 [...]\n", argv[0]); return 0; } /* Parse commad line. It is an error if outfile is not specified. */ if (strcmp(argv[idx], "-a") == 0) { ++idx; append = 1; } if (strcmp(argv[idx], "-o") == 0) { ++idx; out_filename = argv[idx]; if (append) out_file = fopen(out_filename, "r+b"); else out_file = fopen(out_filename, "w+b"); ++idx; } if (out_file == 0) { fprintf(stderr, "syntax: %s [-a] -o outfile intfc1 [...]\n", argv[0]); return 0; } if (append) { /* * Append to output file. Must first read the original header. * Modify this header and write it back when done. We must * also move the file pointer to the end of the file. */ int chk; int pos = sizeof(hdr); chk = fread(&hdr, sizeof(hdr), 1, out_file); if (chk != 1 || ferror(out_file) != 0 || hdr.magic != HDR_MAGIC) { fprintf(stderr, "File '%s'(%04x) is an invalid output file.\n", out_filename, hdr.magic); goto error_handler; } /* Move to the checksum location. This will overwrite the current checksum. */ for (chk = 0; chk < hdr.len; ++chk) pos += (hdr.hdr[chk].len * 2); /* Length value is word count. */ if (fseek(out_file, pos, SEEK_SET) != 0) { fprintf(stderr, "File '%s' has zero length, or error accessing file.\n", out_filename); goto error_handler; } } else { /* Fill first 128 bytes of file with stub header. */ memset(&hdr, '\0', sizeof(hdr)); hdr.magic = HDR_MAGIC; if (fwrite(&hdr, sizeof(hdr), 1, out_file) != 1) { fprintf(stderr, "Error writing to file '%s'.\n", out_filename); goto error_handler; } } /* Write input files to output file. */ while (idx < argc && hdr.len < HDR_MAX) { in_file = fopen(argv[idx], "rb"); if (in_file == 0) { fprintf(stderr, "Unable to open input file '%s'.\n", argv[idx]); goto error_handler; } hdr.hdr[hdr.len].offset = (short) ftell(out_file); hdr.hdr[hdr.len].len = file_size(in_file); if (hdr.hdr[hdr.len].len == 0) { fprintf(stderr, "File '%s' has zero length, or error accessing file.\n", argv[idx]); goto error_handler; } /* * Convert offset and length to word count. Add one to length value in case it * is odd. The offset should always be even since we only wirte shorts to the * output file. */ hdr.hdr[hdr.len].offset = hdr.hdr[hdr.len].offset / 2; hdr.hdr[hdr.len].len = (hdr.hdr[hdr.len].len + 1) / 2; /* Append input file to output file. */ if (file_copy(out_file, in_file, hdr.hdr[hdr.len].len)) { fprintf(stderr, "Can't copy file '%s'.\n", argv[idx]); goto error_handler; } ++idx; ++hdr.len; fclose(in_file); } /* Fill in header stub in file with valid information. */ if (fseek(out_file, 0L, SEEK_SET) != 0) { fprintf(stderr, "File '%s' has zero length, or error accessing file.\n", out_filename); goto error_handler; } if (fwrite(&hdr, sizeof(hdr), 1, out_file) != 1) { fprintf(stderr, "Error writing to file '%s'.\n", out_filename); goto error_handler; } fclose(out_file); calc_chksum(out_filename); return 0; error_handler: fclose(out_file); remove(out_filename); return 1; }