/* unmsa.c vi: set ts=8 sw=8: */ /* unmsa--Expands Magic Shadow Archiver .MSA into raw disk images * Copyright (C) 2002--2004 Peter Backes * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include /* EXIT_FAILURE, EXIT_SUCCESS */ #include /* stderr, fprintf(), fread() */ #include /* memset() */ #include #include #define MSHSIZ 10 #define pop16b(s, d) (d = *s++ << 8, d |= *s++) #define copy16b(s, d) (d = *s << 8 | s[1]) static char *file; struct msainfo { unsigned short ident, nsecpt, nside; unsigned short strk, etrk; }; static size_t freadz(void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t got = fread(ptr, size, nmemb, stream); if (got == nmemb) return got; fprintf(stderr, "%s: fread failed, want=%u*%u, got=%u\n", file, nmemb, size, got); memset((unsigned char *)ptr + got * size, 0x00, (nmemb - got) * size); return got; } static int copy_rle(FILE *os, FILE *is, struct msainfo *header, int len) { unsigned char buffer[512], track[516]; int sec = 0, rle = 0, chr = '\0'; register unsigned char *top = track + sizeof track; #ifdef EBUG fprintf(stderr, "copy_rle\n"); #endif while (sec++ < header->nsecpt) { register unsigned char *tar = buffer; #ifdef EBUG fprintf(stderr, "sector: %d\n", sec); #endif while (tar < buffer + sizeof buffer) { /* XXX doesn't check whether the input stream has * enough data. */ if (rle != 0) { *tar++ = chr; rle--; continue; } if (top >= track + sizeof track - 4) { register int blksiz = len < 512 ? len : 512; memcpy(track, track + sizeof track - 4, 4); if (len < 0) return len; top -= 512; len -= blksiz; if (blksiz) freadz(track + 4, blksiz, 1, is); #ifdef EBUG fprintf(stderr, "debug: reading %d bytes " "rlap at %d.\n", blksiz, top - track); #endif } if (*top == 0xE5) { top++; chr = *top++; pop16b(top, rle); continue; } *tar++ = *top++; } fwrite(buffer, sizeof buffer, 1, os); } #ifdef EBUG fprintf(stderr, "len: %d\n", len); #endif if (len != 0) return len; return 0; } static void copy_verb(FILE *os, FILE *is, struct msainfo *header) { unsigned char track[512]; int sec = 0; #ifdef EBUG fprintf(stderr, "copy_verb\n"); #endif while (sec++ < header->nsecpt) { freadz(track, sizeof track, 1, is); fwrite(track, sizeof track, 1, os); } } int extrmsa(FILE *os, FILE *is) { struct msainfo header; unsigned char buffer[MSHSIZ]; register unsigned char *top = buffer; int trk, ntrks, result; freadz(top, MSHSIZ, 1, is); pop16b(top, header.ident); pop16b(top, header.nsecpt); pop16b(top, header.nside); pop16b(top, header.strk); pop16b(top, header.etrk); if (header.ident != 0x0E0F) { fprintf(stderr, "%s: bad format, skipping\n", file); return EXIT_FAILURE; } #ifdef EBUG fprintf(stderr, "nsecpt= %hu, nside= %hu, strk= %hu, etrk= %hu\n", header.nsecpt, header.nside, header.strk, header.etrk); #endif header.nside++; header.etrk++; ntrks = header.etrk * header.nside; for (trk = header.strk * header.nside; trk < ntrks; trk++) { int len; if (fread(buffer, 2, 1, is) != 1) { fprintf(stderr, "%s: Couldn't read length " "of track %d, side %d, skipping.\n", file, trk / header.nside, trk % header.nside); return EXIT_FAILURE; } copy16b(buffer, len); #ifdef EBUG fprintf(stderr, "track %d, side %d, len= %d\n", trk / header.nside, trk % header.nside, len); #endif if (len == header.nsecpt * 512) copy_verb(os, is, &header); else if ((result = copy_rle(os, is, &header, len))) { fprintf(stderr, "%s: Couldn't expand track %d, " "side %d, len %d: leftover %d, skipping.\n", file, trk / header.nside, trk % header.nside, len, result); return EXIT_FAILURE; } } return EXIT_SUCCESS; } int main(int argc, char *argv[]) { int optind; for (optind = 1; optind < argc; optind++) { int err; char *ep = strrchr(argv[optind], '.'); FILE *is, *os; file = argv[optind]; if (!ep || (strcmp(ep, ".msa") && strcmp(ep, ".MSA"))) { fprintf(stderr, "Unidentifiable suffix on %s.\n", argv[optind]); return EXIT_FAILURE; } if (!(is = fopen(argv[optind], "rb"))) { fprintf(stderr, "Couldn't open %s for reading: %s.\n", argv[optind], strerror(errno)); return EXIT_FAILURE; } strcpy(ep, ep[1] == 'm' ? ".img" : ".IMG"); if (!(os = fopen(argv[optind], "wb"))) { fclose(is); fprintf(stderr, "Couldn't open %s for writing: %s.\n", argv[optind], strerror(errno)); return EXIT_FAILURE; } err = extrmsa(os, is); fclose(os); fclose(is); /*if (err) return err;*/ } return EXIT_SUCCESS; }