home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / qube / pak.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-07  |  8.0 KB  |  348 lines

  1. /***
  2. ****  QuBE --- .PAK file editing routines.
  3. ****
  4. ****  Note that these are based partially on that posting on the Net.
  5. ****  Would the author of that please contact me so I can give him some
  6. ****  credit?
  7. ***/
  8.  
  9. #include "qube.h"
  10. #include "pak.h"
  11.  
  12. #include <fcntl.h>
  13. #include <sys/stat.h>
  14. #include <sys/types.h>
  15. #include <errno.h>
  16.  
  17. /* A single filename entry in a .PAK file */
  18.  
  19. typedef struct {
  20.     unsigned char filename[56];
  21.     long pos, len;
  22. } pakentry;
  23.  
  24. /* The .PAK file entries.  512 of them.  This should be dynamically allocated
  25.    in a linked list or something.  Any volunteers? */
  26.  
  27. static pakentry entries[512];
  28. static long entrycount = 0;
  29.  
  30. static void extract(char *filename);
  31. static void makepath(unsigned char *path);
  32.  
  33. /*
  34. **  PakXtract.    Extract *all* files from a .PAK file.
  35. */
  36.  
  37. void PakXtract(void)
  38. {
  39.     extract("*");
  40. }
  41.  
  42. /*
  43. **  PakXtract2.  Extract file(s) from a .PAK file.
  44. */
  45.  
  46. void PakXtract2(int argnum, char **argv)
  47. {
  48.     extract(argv[argnum+1]);
  49. }
  50.  
  51. static void extract(char *filename)
  52. {
  53.     FILE *fo;
  54.     long table, tablelen, dummy;
  55.     long i, j, k;
  56.     unsigned char *temp;
  57.     int readsize;
  58.  
  59.     /* Make sure it's a .PAK file --- they start with "PACK" */
  60.  
  61.         if (header.id != 0x4B434150)
  62.         Error("Not a valid .PAK file");
  63.  
  64.     /* Go back to the beginning, since we already read a header */
  65.  
  66.     fseek(fi, 0, SEEK_SET);
  67.     fread(&dummy, sizeof(long), 1, fi);
  68.     fread(&table, sizeof(long), 1, fi);
  69.     fread(&tablelen, sizeof(long), 1, fi);
  70.  
  71.         fseek(fi, table, SEEK_SET);
  72.  
  73.     /* Load in the filename table.    Like I said, this ought to be a
  74.        linked list or something. */
  75.  
  76.     for (i = 0; i < tablelen / 64; i++)
  77.         fread(entries+i, sizeof(pakentry), 1, fi);
  78.  
  79.     /* Temporary small buffer for copying files.  We can't just allocate
  80.        all the space because DOS has these memory limitation thingys. */
  81.  
  82.     temp = Qmalloc(32768);
  83.  
  84.     /* Do it. */
  85.  
  86.     for (i = 0; i < tablelen / 64; i++) {
  87.  
  88.         /* Match it. */
  89.         if (MatchName(filename, entries[i].filename)) {
  90.  
  91.             /* Print it. */
  92.  
  93.             if (verbose)
  94.                 printf("Extracting %s, address %08lX (size %ld)\n",
  95.                     entries[i].filename, entries[i].pos, entries[i].len);
  96.  
  97.             /* Locate it. */
  98.  
  99.             makepath(entries[i].filename);
  100.             if ((fo = fopen(entries[i].filename, "wb")) == NULL)
  101.                 Error("Unable to get permission to write files.");
  102.             fseek(fi, entries[i].pos, SEEK_SET);
  103.  
  104.             /* Write it. */
  105.  
  106.             for (j = 0L; j < entries[i].len; j += 32768L) {
  107.                 if (entries[i].len - j >= 32768) k = 32768;
  108.                 else k = entries[i].len - j;
  109.                 readsize = fread(temp, sizeof(char), k, fi);
  110.                 fwrite(temp, sizeof(char), readsize, fo);
  111.             }
  112.  
  113.             fclose(fo);
  114.         }
  115.         }
  116.     Qfree(temp);
  117. }
  118.  
  119. /*
  120. **  PakList.  List all files in a .PAK file.  Based on the above subroutine;
  121. **    see it for comments on how it works.
  122. */
  123.  
  124. void PakList(void)
  125. {
  126.     FILE *fo;
  127.     long pos, len, dummy;
  128.     long i, j, k;
  129.     unsigned char *temp;
  130.     int readsize;
  131.  
  132.         if (header.id != 0x4B434150)
  133.         Error("Not a valid .PAK file");
  134.  
  135.     fseek(fi, 0, SEEK_SET);
  136.     fread(&dummy, sizeof(long), 1, fi);
  137.     fread(&pos, sizeof(long), 1, fi);
  138.     fread(&len, sizeof(long), 1, fi);
  139.     fseek(fi, pos, SEEK_SET);
  140.  
  141.     for (i = 0; i < len / 64; i++)
  142.         fread(entries+i, sizeof(pakentry), 1, fi);
  143.  
  144.     if (verbose)
  145.         printf("%-8s %-8s %-60s\n", "Address", "Size", "FileName");
  146.  
  147.     for (i = 0; i < len / 64; i++) {
  148.         if (verbose)
  149.             printf("%08lX %-8ld %s\n", entries[i].pos, entries[i].len, entries[i].filename);
  150.         else printf("%s\n", entries[i].filename);
  151.         }
  152. }
  153.  
  154. /*
  155. **  PakDelete.    Zorch file(s) from a .PAK file.
  156. */
  157.  
  158. void PakDelete(int argnum, char **argv)
  159. {
  160.     FILE *fo;
  161.     long pos, len, dummy;
  162.     long newpos, newlen;
  163.         long i, j, k;
  164.     unsigned char *temp;
  165.     int readsize;
  166.  
  167.         if (header.id != 0x4B434150)
  168.         Error("Not a valid .PAK file");
  169.  
  170.     fseek(fi, 0, SEEK_SET);
  171.     fread(&dummy, sizeof(long), 1, fi);
  172.     fread(&pos, sizeof(long), 1, fi);
  173.     fread(&len, sizeof(long), 1, fi);
  174.     fseek(fi, pos, SEEK_SET);
  175.  
  176.     for (i = 0; i < len / 64; i++)
  177.         fread(entries+i, sizeof(pakentry), 1, fi);
  178.  
  179.     if ((fo = fopen("$$$_temp.pak", "wb")) == NULL)
  180.         Error("Unable to get permission to write files.");
  181.  
  182.         k = fwrite(&dummy, 1, sizeof(long), fo);
  183.     k += fwrite(&pos, 1, sizeof(long), fo);
  184.     k += fwrite(&len, 1, sizeof(long), fo);
  185.  
  186.     if (k < 12) {
  187.         fclose(fo);
  188.         unlink("$$$_temp.pak");
  189.         Error("Insufficient disk space");
  190.     }
  191.  
  192.     newpos = 12L;
  193.  
  194.     temp = Qmalloc(32768);
  195.  
  196.         for (i = 0; i < len / 64; i++) {
  197.         if (MatchName(argv[argnum+1], entries[i].filename)) {
  198.             if (verbose)
  199.                 printf("Deleting %s\n", entries[i].filename, entries[i].pos, entries[i].len);
  200.         }
  201.                 else {
  202.             fseek(fi, entries[i].pos, SEEK_SET);
  203.             if (verbose)
  204.                 printf("Keeping %s\n", entries[i].filename, entries[i].pos, entries[i].len);
  205.                         entries[i].pos = newpos;
  206.                         for (j = 0L; j < entries[i].len; j += 32768L) {
  207.                 if (entries[i].len - j >= 32768) k = 32768;
  208.                 else k = entries[i].len - j;
  209.                 readsize = fread(temp, sizeof(char), k, fi);
  210.                 newpos += (k = fwrite(temp, sizeof(char), readsize, fo));
  211.                 if (k < readsize) {
  212.                     fclose(fo);
  213.                     unlink("$$$_temp.pak");
  214.                                         Error("Insufficient disk space");
  215.                                 }
  216.                         }
  217.                 }
  218.         }
  219.  
  220.     Qfree(temp);
  221.  
  222.         newlen = 0L;
  223.  
  224.     for (i = 0; i < len / 64; i++) {
  225.         if (!MatchName(argv[argnum+1], entries[i].filename)) {
  226.             k = fwrite(entries+i, 1, sizeof(pakentry), fo);
  227.             if (k < sizeof(pakentry)) {
  228.                 fclose(fo);
  229.                 unlink("$$$_temp.pak");
  230.                 Error("Insufficient disk space");
  231.             }
  232.                         newlen++;
  233.                 }
  234.     }
  235.  
  236.         newlen *= 64;
  237.  
  238.     fseek(fo, 0, SEEK_SET);
  239.     fwrite(&dummy, 1, sizeof(long), fo);
  240.     fwrite(&newpos, 1, sizeof(long), fo);
  241.     fwrite(&newlen, 1, sizeof(long), fo);
  242.  
  243.     fclose(fo);
  244.     fclose(fi);
  245.  
  246.     unlink(argv[filenamearg]);
  247.     rename("$$$_temp.pak", argv[filenamearg]);
  248. }
  249.  
  250. /*
  251. **  PakAdd.  Zorch file(s) from a .PAK file.
  252. */
  253.  
  254. void PakAdd(int argnum, char **argv)
  255. {
  256.     FILE *fo;
  257.     long pos, len, dummy;
  258.     long newpos, newlen;
  259.         long i, j, k;
  260.     unsigned char *temp;
  261.     int readsize;
  262.  
  263.     if (justcreated) {
  264.         pos = 12;
  265.         len = 0;
  266.         header.id = dummy = 0x4B434150;
  267.         fwrite(&dummy, sizeof(long), 1, fi);
  268.         fwrite(&pos, sizeof(long), 1, fi);
  269.         fwrite(&len, sizeof(long), 1, fi);
  270.         }
  271.  
  272.         if (header.id != 0x4B434150)
  273.         Error("Not a valid .PAK file");
  274.  
  275.     if ((fi = freopen(argv[filenamearg], "r+b", fi)) == NULL)
  276.         Error("Unable to get permission to update files.");
  277.  
  278.         fseek(fi, 0, SEEK_SET);
  279.     fread(&dummy, sizeof(long), 1, fi);
  280.     fread(&pos, sizeof(long), 1, fi);
  281.     fread(&len, sizeof(long), 1, fi);
  282.     fseek(fi, pos, SEEK_SET);
  283.  
  284.     for (i = 0; i < len / 64; i++)
  285.         fread(entries+i, sizeof(pakentry), 1, fi);
  286.  
  287.     fseek(fi, pos, SEEK_SET);
  288.  
  289.     newlen = 0L;
  290.  
  291.     if ((fo = fopen(argv[argnum+1], "rb")) == NULL)
  292.         Error(strerror(errno));
  293.  
  294.     temp = Qmalloc(32768);
  295.  
  296.         while (!feof(fo)) {
  297.                 readsize = fread(temp, sizeof(char), 32768, fo);
  298.         newlen += (k = fwrite(temp, sizeof(char), readsize, fi));
  299.         if (k < readsize) {
  300.             fclose(fo);
  301.             Error("Insufficient disk space");
  302.         }
  303.     }
  304.         fclose(fo);
  305.  
  306.     Qfree(temp);
  307.  
  308.     entries[len/64].pos = pos;
  309.     entries[len/64].len = newlen;
  310.         strcpy(entries[len/64].filename, argv[argnum+1]);
  311.     len += 64;
  312.         pos += newlen;
  313.  
  314.         fseek(fi, 0, SEEK_SET);
  315.     fwrite(&dummy, sizeof(long), 1, fi);
  316.     fwrite(&pos, sizeof(long), 1, fi);
  317.     fwrite(&len, sizeof(long), 1, fi);
  318.     fseek(fi, pos, SEEK_SET);
  319.  
  320.     for (i = 0; i < len / 64; i++)
  321.         fwrite(entries+i, sizeof(pakentry), 1, fi);
  322. }
  323.  
  324. /*
  325. **  makepath.  Create a pathname based on a path.
  326. */
  327.  
  328. static void makepath(unsigned char *path)
  329. {
  330.     unsigned char *temp2;
  331.     unsigned char temp[64];
  332.  
  333.     strncpy(temp, path, 64);
  334.     temp[63] = '\0';
  335.  
  336.     temp2 = temp;
  337.  
  338.     while (*temp2) {
  339.         if(*temp2 == '/') {
  340.             *temp2 = '\0';
  341.             mkdir(temp);
  342.             *temp2 = '/';
  343.         }
  344.         temp2++;
  345.     }
  346. }
  347.  
  348.