home *** CD-ROM | disk | FTP | other *** search
/ Ultimate DOOM Companion / PowersourceMultimedia-UltimateDOOMCompanion.iso / goodies / textusrc.zip / TEXTURES.C < prev    next >
C/C++ Source or Header  |  1994-07-30  |  27KB  |  968 lines

  1. /*
  2.  
  3.     textures: a utility to merge new textures with textures from DOOM.WAD
  4.     Copyright (C) 1994  Robert H. Forsman Jr.
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20. */
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <ctype.h>
  26.  
  27. #include "wad.h"
  28.  
  29. #define TEXTURE_SIZE(npatches)    (sizeof(struct dw_one_texture) + (npatches-1)*sizeof(struct dw_patchdesc))
  30.  
  31. /* this structure stores all the information necessary to interpret a
  32.    texture resource.  The pnames are clumped in with the texture data
  33.    because the texture data contains indexes into the pnames and we
  34.    load several different pnames which go with different texture data.
  35.    */
  36.  
  37. struct texture_gob {
  38.     struct dw_texture_list    *tdata;        /* TEXTURE resource */
  39.     INT32    tlen;
  40.     /* the pndata can be shared by several textures */
  41.     struct dw_pnames    *pndata;    /* PNAMES resource */
  42.      INT32    pnlen;
  43. };
  44.  
  45. /* all the texture/pname gobs we've loaded in */
  46. struct texture_gob    *allgobs=0;
  47. int    numgobs=0;
  48.  
  49. /* we're about to add another gob.  make sure there's space and give
  50.    us a pointer */
  51. struct texture_gob *extra_gob(void)
  52. {
  53.     if (allgobs) {
  54.     allgobs = (struct texture_gob*)realloc(allgobs,
  55.                            sizeof(*allgobs)*(numgobs+1));
  56.     return &allgobs[numgobs++];
  57.     } else {
  58.     allgobs = (struct texture_gob*)malloc(sizeof(*allgobs)*(numgobs=1));
  59.     return &allgobs[0];
  60.     }
  61. }
  62.  
  63. /* This is the entire reason this program exists.  These resources are
  64.    constructed and mangled together from the input files.  The result
  65.    is a single texture resource and a single pnames resource that can
  66.    be written to a final output WAD file */
  67. struct dw_texture_list    *output_texture;
  68. int    otlen;
  69. struct dw_pnames    *output_pnames;
  70. int    oplen;
  71.  
  72. void compile_textures(void)
  73. {
  74.     char    (*tnames)[8];
  75.     int        *offsets;
  76.     int        ntnames=0;
  77.     char    (*pnames)[8];
  78.     int        npnames=0;
  79.     int        *idxcache;
  80.  
  81.     char    *data;
  82.     int/*damn, is this big enough?*/    datalen, datasize;
  83.  
  84.     int    i,j,k;
  85.  
  86.     datalen = 0;
  87.     data = malloc(datasize=4096); /* don't shrink this */
  88.  
  89.     /* just to make sure realloc doesn't puke */
  90.     offsets = malloc(1);
  91.     pnames = malloc(1);
  92.     tnames = malloc(1);
  93.  
  94.     for (i=numgobs-1; i>=0; i--) {
  95.     idxcache = malloc(sizeof(*idxcache) * (size_t)allgobs[i].pndata->count);
  96.  
  97.     for (j=0; j<allgobs[i].pndata->count; j++) {
  98.         for (k=0; k<npnames; k++)
  99.         if (0==strncasecmp(pnames[k],
  100.                    allgobs[i].pndata->names[j], 8))
  101.             break;
  102.         if (k<npnames)
  103.         idxcache[j] = k;
  104.         else {
  105.         pnames = realloc(pnames, sizeof(*pnames)*(++npnames));
  106.         idxcache[j] = k;
  107.         strncpy(pnames[k], allgobs[i].pndata->names[j], 8);
  108.         }
  109.     }
  110.  
  111.     if (allgobs[i].tdata)
  112.         for (j=0; j<allgobs[i].tdata->ntextures; j++) {
  113.         struct dw_one_texture    *curr;
  114.         if (4+j*4 >= allgobs[i].tlen ||
  115.             Itohl(allgobs[i].tdata->offsets[j]) >= allgobs[i].tlen ||
  116.             Itohl(allgobs[i].tdata->offsets[j]) + sizeof(struct dw_one_texture) > allgobs[i].tlen) {
  117.             fprintf(stderr, "corrupt texture list in gob #%d\n", i);
  118.             break;
  119.         }
  120.         curr = (struct dw_one_texture*)(((char*)allgobs[i].tdata)
  121.                         + (int)Itohl(allgobs[i].tdata->
  122.                             offsets[j]));
  123.         if (Itohl(allgobs[i].tdata->offsets[j]) +
  124.             sizeof(struct dw_one_texture) +
  125.             (curr->npatches-1)*sizeof(struct dw_patchdesc)
  126.              > allgobs[i].tlen) {
  127.             fprintf(stderr, "corrupt texture list in gob #%d\n", i);
  128.             break;
  129.         }
  130.         for (k=0; k<ntnames; k++) {
  131.             if (0==strncasecmp(tnames[k], curr->name, 8))
  132.             break;
  133.         }
  134.         if (k<ntnames) {
  135.             fprintf(stderr, "ignoring duplicate texture %s\n",
  136.                 curr->name);
  137.             continue;
  138.         }
  139.         tnames = realloc(tnames, sizeof(*tnames)*(++ntnames));
  140.         offsets = realloc(offsets, sizeof(*offsets)*ntnames);
  141.         offsets[ntnames-1] = datalen;
  142.         strncpy(tnames[k], curr->name, 8);
  143.  
  144.         /* this following process is destructive! */
  145.         for (k=0; k<curr->npatches; k++) {
  146.             curr->patches[k].pnames_idx
  147.             = htoIs(idxcache[Itohs(curr->patches[k].pnames_idx)]);
  148.         }
  149.  
  150.         while (datalen+TEXTURE_SIZE(curr->npatches) >= datasize)
  151.             data = realloc(data, datasize*=2);
  152.  
  153.         memcpy(data+datalen, curr, TEXTURE_SIZE(curr->npatches));
  154.  
  155.         datalen += TEXTURE_SIZE(curr->npatches);
  156.         }
  157.  
  158.     free(idxcache);
  159.     }
  160.  
  161.     output_texture = malloc(otlen = 4+4*ntnames+ datalen);
  162.     output_texture->ntextures = htoIl(ntnames);
  163.     for (i=0; i<ntnames; i++)
  164.     output_texture->offsets[i] = htoIl(4+4*ntnames+offsets[i]);
  165.     free(offsets);
  166.     memcpy(&output_texture->offsets[ntnames], data, datalen);
  167.     free(data);
  168.  
  169.     output_pnames = malloc(oplen = 4+8*npnames);
  170.     output_pnames->count = htoIl(npnames);
  171.     memcpy(output_pnames->names, pnames, 8*npnames);
  172. }
  173.  
  174. /**********************************************************************/
  175.  
  176. /* this procedure prints the compiled texures into an ASCII form that
  177.    is self-contained (it doesn't need a PNAMES).  The format output by
  178.    this procedure is compatible with this programs -at format */
  179. void pretty_print(FILE *fp)
  180. {
  181.     struct dw_texture_list    *tl;
  182.     int    i,j;
  183.  
  184.     tl = output_texture;
  185.  
  186.     for (i=0; i< Itohl(tl->ntextures); i++) {
  187.     struct dw_one_texture    *curr;
  188.     curr = (struct dw_one_texture *)((char*)(tl) + (int)Itohl(tl->offsets[i]));
  189.     fprintf(fp, "%-8s : %dx%d\n", curr->name,
  190.         Itohs(curr->width), Itohs(curr->height));
  191.     for (j=0; j<Itohs(curr->npatches); j++) {
  192.         struct dw_patchdesc    *patch = &curr->patches[j];
  193.         char    buf[9];
  194.         upcopy8(buf, output_pnames->names[Itohs(patch->pnames_idx)]);
  195.         buf[8] = 0;
  196.         fprintf(fp, "\t%-8s %+d%+d %d %d\n", buf,
  197.             Itohs(patch->xoff), Itohs(patch->yoff),
  198.             Itohs(patch->stepdir), Itohs(patch->colormap));
  199.     }
  200.     }
  201. }
  202.  
  203. /* This procedure reads a list of patch names from the specified file.
  204.    It constructs a PNAMES resource from them */
  205. struct dw_pnames *read_ascii_pnames(char *fname, INT32 *len)
  206. {
  207.     FILE    *fp;
  208.     struct dw_pnames    *rval;
  209.     int    size;
  210.      fp = fopen_b(fname, 0, 0);
  211.      if (fp==0) {
  212.     *len = 0;
  213.     return 0;
  214.     }
  215.  
  216.     size = 4096;
  217.      rval = malloc(size);
  218.     rval->count = 0;
  219.     while (!feof(fp)) {
  220.     int    j, ch;
  221.  
  222.     if (size <4+(rval->count+1)*8)
  223.         rval = realloc(rval, size*=2);
  224.     for (j=0; j<8; j++) {
  225.         ch = getc(fp);
  226.         if (ch==EOF || ch=='\n')
  227.         break;
  228.          rval->names[(int)rval->count][j] = islower(ch) ? toupper(ch) : ch;
  229.     }
  230.     if (j<8) {
  231.         for (; j<8; j++)
  232.         rval->names[(int)rval->count][j] = 0;
  233.     } else {
  234.         int    first =1;
  235.         while (1) {
  236.         ch = getc(fp);
  237.         if (ch==EOF||ch=='\n')
  238.             break;
  239.         if (first) {
  240.             fprintf(stderr, "pname on line %ld of file %s too long\n",
  241.                 rval->count+1, fname);
  242.             first = 0;
  243.         }
  244.         }
  245.     }
  246.     rval->count++;
  247.     }
  248.  
  249.     fclose_b(fp);
  250.  
  251.      rval = realloc(rval, (size_t)(*len = 4 + rval->count*8));
  252.     rval->count = htoIl(rval->count);
  253.  
  254.     return rval;
  255. }
  256.  
  257. /* This is used by make_gob_from_textfile.  Since the ascii texture
  258.    file format contains patch NAMES rather than indices, when we read
  259.    it into core memory we must convert these names into indices. */
  260. INT32 maybe_add_pname(char *name, struct texture_gob *gob)
  261. {
  262.   int    i;
  263.  
  264.   if (gob->pndata==0) {
  265.      gob->pndata = malloc( (size_t)gob->pnlen = 1024);
  266.     gob->pndata->count = 0;
  267.   }
  268.     
  269.   for (i=0; i<gob->pndata->count; i++) {
  270.     if (0==strncasecmp(name, gob->pndata->names[i], 8))
  271.       break;
  272.   }
  273.  
  274.   if (i<gob->pndata->count)
  275.     return i;
  276.  
  277.   if (gob->pnlen < (gob->pndata->count+1)*8 + 4)
  278.      gob->pndata = realloc(gob->pndata, (size_t)gob->pnlen*=2);
  279.  
  280.   upcopy8(gob->pndata->names[i], name);
  281.   return gob->pndata->count++;
  282. }
  283.  
  284. /* creates a TEXTURE and PNAMES resource from an ascii file.  The file
  285.    has several "paragraph"s.  Each paragraph describes one texture.
  286.  
  287.    The first line of the pargraph has the texture name, a colon, the
  288.    width, an 'x', then the height.
  289.  
  290.    The subsequent lines of the paragraph begin with a TAB character
  291.    and contain the patch name, two integers for the patch X and Y
  292.    offset, the stepdir (always 1) and the colormap (always 0)
  293.  
  294.    The first line that doesn't start with a TAB must belong to the
  295.    next paragraph.
  296.  
  297.    No extraneous blank lines are allowed, and there are no such things
  298.    as comments.  If this is a serious problem for you, drop me a line.
  299.    I'll see what I can do.
  300.  
  301. */
  302.  
  303. void make_gob_from_textfile(char *fname, struct texture_gob *gob)
  304. {
  305.     FILE    *fp;
  306.     char    *data;
  307.     int        datalen, datasize;
  308.     int        *offsets, noffsets;
  309.     int        numtextures;
  310.     int        linen;
  311.     char    buf[1024];
  312.  
  313.     gob->tdata=0;
  314.     gob->tlen =0;
  315.     gob->pndata=0;
  316.     gob->pnlen=0;
  317.  
  318.     if (!(fp = fopen_b(fname, 0, 0)))
  319.     return;
  320.  
  321.     datalen=0;
  322.     data = malloc(datasize=4096);
  323.  
  324. #define    TEXTURE    ((struct dw_one_texture*)(data+datalen))
  325.  
  326.     numtextures = 0;
  327.     noffsets=16;
  328.     offsets = malloc(sizeof(*offsets)*noffsets);
  329.     linen=1;            /* jumpstart the input loop */
  330.     if (0==fgets(buf, sizeof(buf), fp))
  331.     return;
  332.     while (!feof(fp)) {
  333.     char    name[9];
  334.     int    width,height;
  335.     int    npatches;
  336.  
  337.     if (3!=sscanf(buf, "%8s : %dx%d", name, &width, &height)) {
  338.         fprintf(stderr, "error parsing ascii texture file %s on line %d\n",
  339.             fname, linen);
  340.         return;
  341.     }
  342.  
  343.     if (datalen+sizeof(struct dw_one_texture) >= datasize)
  344.         data = realloc(data, datasize *=2);
  345.     if (numtextures >= noffsets)
  346.         offsets = realloc(offsets, sizeof(*offsets)*(noffsets*=2));
  347.     offsets[numtextures] = datalen;
  348.     numtextures++;
  349.  
  350.     upcopy8(TEXTURE->name, name);
  351.     TEXTURE->width  = htoIs(width);
  352.     TEXTURE->height = htoIs(height);
  353.     TEXTURE->zero1 = TEXTURE->zero2 = TEXTURE->zero3 = TEXTURE->zero4 = 0;
  354.     for (npatches=0; ; npatches++) {
  355.         int    xoff, yoff, stepdir, colormap;
  356.         if (0==fgets(buf, sizeof(buf), fp)) {
  357.         buf[0] = 0;
  358.         break;
  359.         }
  360.         linen++;
  361.         if (buf[0]!='\t')
  362.         break;
  363.         
  364.         if (5!=sscanf(buf, "\t%8s  %d%d %d %d", name,
  365.               &xoff, &yoff, &stepdir, &colormap)) {
  366.         fprintf(stderr, "error parsing patch from ascii texture file %s on line %d\n",
  367.             fname, linen);
  368.         return;
  369.         }
  370.         if (datalen+TEXTURE_SIZE(npatches+1) >= datasize) {
  371.         data = realloc(data, datasize *=2);
  372.         }
  373.         TEXTURE->patches[npatches].xoff = htoIs(xoff);
  374.         TEXTURE->patches[npatches].yoff = htoIs(yoff);
  375.         TEXTURE->patches[npatches].stepdir = htoIs(stepdir);
  376.         TEXTURE->patches[npatches].colormap = htoIs(colormap);
  377.         TEXTURE->patches[npatches].pnames_idx =
  378.         htoIs(maybe_add_pname(name, gob));
  379.     }
  380.     TEXTURE->npatches = htoIs(npatches);
  381.     datalen += TEXTURE_SIZE(npatches);
  382.     }
  383.  
  384.      gob->tdata = malloc( (size_t)gob->tlen = 4 + 4*numtextures + datalen);
  385.     gob->tdata->ntextures = htoIl(numtextures);
  386.     {
  387.     int i;
  388.     for (i=0; i<numtextures; i++)
  389.         gob->tdata->offsets[i] = htoIl(offsets[i]+4+4*numtextures);
  390.     }
  391.     memcpy( 4 + 4*numtextures + (char*)gob->tdata, data, datalen);
  392.  
  393.     /* squish down the pnames */
  394.      gob->pnlen = 4+8*gob->pndata->count;
  395.      gob->pndata = realloc(gob->pndata, (size_t)gob->pnlen);
  396.  
  397.     free(offsets);
  398.     free(data);
  399.  
  400.     fclose_b(fp);
  401. }
  402.  
  403. /**********************************************************************/
  404.  
  405. struct wadcache {
  406.      INT32    nentries;
  407.     union {
  408.     /* this structure caches the directory of a WAD file.  We do
  409.        not load the entire file into core because DOS is pretty
  410.        darn short on memory.  We keep the FILE pointer so we can
  411.        later seek through it reading in resources. */
  412.     struct {
  413.         char    *passthru;    /* should these be passed through to
  414.                        the output wad? */
  415.         struct dw_direntry *entries;
  416.         FILE    *fp;
  417.     } realwad;
  418.     /* this structure holds one single raw resource. */
  419.     struct {
  420.         char    *data;
  421.          INT32        len;
  422.         char    name[8];
  423.     } oneres;
  424.     }u;
  425. };
  426.  
  427. /* a list of WAD files and individual resources */
  428. struct wadcache *allwads=0;
  429. int    nwads=0;
  430.  
  431.  
  432. struct wadcache *new_wadcache(void)
  433. {
  434.     if (allwads) {
  435.     allwads = realloc(allwads, sizeof(*allwads)*(nwads+1));
  436.     } else {
  437.     allwads = malloc(sizeof(*allwads));
  438.     }
  439.     return &allwads[nwads++];
  440. }
  441.  
  442. /* This procedure loads an input wad, extracts the pnames and any
  443.    texture resources that might be in it, and (if the user specifies a
  444.    +) stores the directory so that the resources may be later copied
  445.    from the file into an output wad file. */
  446.  
  447. /* argv[*argi] is the "-" or "+" string when we're done */
  448. void slurp_iwad(char **argv, int *argi)
  449. {
  450.     FILE    *fp;
  451.     char    magic[4];
  452.     INT32    nentries;
  453.     INT32    offset;
  454.     struct wadcache    *curr;
  455.  
  456.      if (!(fp = fopen_b(argv[*argi+1], 0, 1)))
  457.     exit(1);
  458.  
  459.     if (1!=fread(magic, 4, 1, fp) ||
  460.     1!=fread(&nentries, 4, 1, fp) ||
  461.     1!=fread(&offset, 4, 1, fp)) {
  462.     if (0!=memcmp("IWAD", magic, 4) &&
  463.         0!=memcmp("PWAD", magic, 4)) {
  464.         fprintf(stderr, "File %s not an IWAD or PWAD\n", argv[*argi+1]);
  465.         fclose_b(fp);
  466.         exit(1);        /* we're not eating *argi */
  467.     }
  468.     }
  469.      if (Itohs(nentries)<1) {
  470.     return;            /* nothing interesting here */
  471.     }
  472.  
  473.      curr = new_wadcache();
  474.  
  475.      curr->nentries = nentries = Itohl(nentries);
  476.      curr->u.realwad.entries = malloc(sizeof(*curr->u.realwad.entries)
  477.                       *(size_t)nentries);
  478.      curr->u.realwad.passthru = malloc(sizeof(*curr->u.realwad.passthru)
  479.                         *(size_t)nentries);
  480.     curr->u.realwad.fp = fp;
  481.  
  482.     fseek(fp, (long) Itohl(offset), SEEK_SET);
  483.  
  484.     if (nentries != fread(curr->u.realwad.entries,
  485.               sizeof(*curr->u.realwad.entries),
  486.               (size_t)nentries, fp)) {
  487.     fprintf(stderr, "short read on WAD directory entries\n");
  488.     exit(1);
  489.     }
  490.  
  491.     if (0==strcmp(argv[2+*argi], "+")) {
  492.     int    j;
  493.     for (j=0; j<curr->nentries; j++)
  494.         curr->u.realwad.passthru[j] = 1;
  495.  
  496.     *argi += 2;
  497.  
  498.     } else {
  499.     int    i;
  500.     int    j;
  501.     struct dw_pnames    *pndata;
  502.     long    pnlen;
  503.  
  504.     for (j=0; j<curr->nentries; j++)
  505.         curr->u.realwad.passthru[j] = 1;
  506.  
  507.     for (j=0; j<curr->nentries; j++) {
  508.         if (0==strncasecmp(curr->u.realwad.entries[j].name , argv[2+*argi], 8))
  509.         break;
  510.     }
  511.     if (j>=curr->nentries) {
  512.         fprintf(stderr, "Warning: couldn't find resource %s in WAD file %s\n", argv[2+*argi], argv[*argi+1]);
  513.         pnlen = 0;
  514.         pndata = malloc(1);
  515.     } else {
  516.         curr->u.realwad.passthru[j] = 0;
  517.         pnlen = Itohl(curr->u.realwad.entries[j].length);
  518.         fseek(fp, (long) Itohl(curr->u.realwad.entries[j].offset), SEEK_SET);
  519.          pndata = malloc((size_t)pnlen);
  520.          fread(pndata, (size_t)pnlen, 1, fp);
  521.     }
  522.  
  523.     for (i=*argi+3;
  524.          argv[i] && 0!=strcmp("-", argv[i]) && 0!=strcmp("+", argv[i]);
  525.          i++) {
  526.         struct texture_gob    *gob;
  527.         for (j=0; j<curr->nentries; j++) {
  528.         if (0==strncasecmp(curr->u.realwad.entries[j].name , argv[i],8))
  529.             break;
  530.         }
  531.         if (j>=curr->nentries) {
  532.         fprintf(stderr, "Warning: couldn't find resource %s in WAD file %s\n", argv[i], argv[*argi+1]);
  533.         continue;
  534.         }
  535.  
  536.         curr->u.realwad.passthru[j] = 0;
  537.  
  538.         gob = extra_gob();
  539.         gob->tlen = Itohl(curr->u.realwad.entries[j].length);
  540.         fseek(fp, (long) Itohl(curr->u.realwad.entries[j].offset), SEEK_SET);
  541.          gob->tdata = malloc((size_t)gob->tlen);
  542.          fread(gob->tdata, (size_t)gob->tlen, 1, fp);
  543.  
  544.         gob->pndata = pndata;
  545.         gob->pnlen = pnlen;
  546.     }
  547.  
  548.     if (i==*argi+3) {
  549.         struct texture_gob    *gob;
  550.         /* no textures! */
  551.         gob = extra_gob();
  552.         gob->tlen = 0;
  553.         gob->tdata = 0;
  554.         gob->pndata = pndata;
  555.         gob->pnlen = pnlen;
  556.     }
  557.  
  558.     if (!(argv[i] && 0==strcmp("+", argv[i]))) {
  559.         /* don't leak */
  560.         nwads--;
  561.         free(allwads[nwads].u.realwad.entries);
  562.         free(allwads[nwads].u.realwad.passthru);
  563.     } 
  564.  
  565.     *argi=i;
  566.     }
  567.  
  568. }
  569.  
  570. /* loads a single raw resource for later writing with the -owad option */
  571.  
  572. void slurp_resource(char *fname, char *resname)
  573. {
  574.     FILE    *fp;
  575.     struct wadcache    *curr;
  576.      INT32    size = 4096;
  577.  
  578.     /* special case for lame DOS */
  579.     if (0==strcasecmp(fname, "/dev/null")) {
  580.     curr = new_wadcache();
  581.     curr->nentries = 1;
  582.     upcopy8(curr->u.oneres.name, resname);
  583.     curr->u.oneres.data = 0;
  584.     curr->u.oneres.len = 0;
  585.     return;
  586.     }
  587.  
  588.     if (!(fp = fopen_b(fname, 0, 1)))
  589.     exit(1);
  590.  
  591.     curr = new_wadcache();
  592.  
  593.     curr->nentries = 0;
  594.     upcopy8(curr->u.oneres.name, resname);
  595.     
  596.     curr->u.oneres.data = malloc(size);
  597.     curr->u.oneres.len = 0;
  598.     while (1) {
  599.     INT32    n = size - curr->u.oneres.len;
  600.     int    i;
  601.     if (((int)n)!=(i=fread(curr->u.oneres.data+(int)curr->u.oneres.len, 1, (size_t)n, fp))) {
  602.         if (i<0) {
  603.         fprintf(stderr, "error during read from file %s\n", fname);
  604.         } else if (i==0)
  605.         break;
  606.     }
  607.     curr->u.oneres.len += i;
  608.     if (size<=curr->u.oneres.len)
  609.         curr->u.oneres.data = realloc(curr->u.oneres.data, size*=2);
  610.     }
  611.  
  612.      curr->u.oneres.data = realloc(curr->u.oneres.data, (size_t)curr->u.oneres.len);
  613.  
  614.     fclose_b(fp);
  615. }
  616.  
  617. /* writes a PWAD file containing the compiled texture and pnames
  618.    resource.  It also has any raw resources and -iwads that were
  619.    loaded with + instead of - */
  620.  
  621. void spurt_owad(char *fname, char *pname, char *tname)
  622. {
  623.     FILE    *fp;
  624.  
  625.      if (!(fp = fopen_b(fname, 1, 1)))
  626.     return;
  627.  
  628.     {
  629.     struct wadhandle    *wh;
  630.     char    *buffer;
  631.     INT32    buffersize;
  632.     int    i,j;
  633.  
  634.     buffer = malloc((size_t)buffersize=4096);
  635.  
  636.     wh = open_wadfile(fp);
  637.  
  638.     write_entry_to_wadfile(wh, output_texture, otlen, tname);
  639.     write_entry_to_wadfile(wh, output_pnames, oplen, pname);
  640.     for (i=nwads-1; i>=0; i--) {
  641.         if (allwads[i].nentries) {
  642.         for (j=0; j<allwads[i].nentries; j++) {
  643.              INT32    len;
  644.             if (!allwads[i].u.realwad.passthru[j])
  645.             continue;    /* skip this entry */
  646.             fseek(allwads[i].u.realwad.fp, (long)Itohl(allwads[i].u.realwad.entries[j].offset),
  647.               SEEK_SET);
  648.              len = Itohl(allwads[i].u.realwad.entries[j].length);
  649.             if (len>buffersize)
  650.             buffer = realloc(buffer, (size_t)(buffersize = len));
  651.              if (len != 0 && 1!=fread(buffer, (size_t)len, 1, allwads[i].u.realwad.fp)) {
  652.             fprintf(stderr, "error reading resource from wad during owad stage: ") ;
  653.             perror("");
  654.             }
  655.             write_entry_to_wadfile(wh, buffer, len,
  656.                        allwads[i].u.realwad.entries[j].name);
  657.         }
  658.         } else {
  659.         write_entry_to_wadfile
  660.             (wh, allwads[i].u.oneres.data,
  661.              allwads[i].u.oneres.len, allwads[i].u.oneres.name);
  662.         }
  663.     }
  664.     close_wadfile(wh);
  665.     }
  666.  
  667.     fclose_b(fp);
  668. }
  669.  
  670. /* read all the bytes from a file and return them.
  671.  
  672.    fname is the name of the file.  If it happens to be "-" then we
  673.    read from stdin.
  674.  
  675.    len is a pointer to where we should store the length of the data.
  676.  
  677.    the pointer to the beginning of the data is returned from the function.
  678.  
  679.    */
  680.  
  681. void *slurp_file(char *fname, INT32 *len)
  682. {
  683.     int    n;
  684.     char    *rawdata;
  685.     int    rd_len, rd_size;
  686.  
  687.     FILE    *fp;
  688.  
  689.      if (!(fp = fopen_b(fname, 0, 1)))
  690.     return 0;
  691.  
  692.     rawdata = malloc(rd_size=4096);
  693.     rd_len=0;
  694.  
  695.     while (1) {
  696.     n = rd_size-rd_len;
  697.     if (0 >= (n=fread(rawdata+rd_len, 1, n, fp))) {
  698.         if (n==0)
  699.         break;
  700.         if (n<0) {
  701.         fprintf(stderr, "Error reading texture resource from stdin: ");
  702.         perror("");
  703.         exit(1);
  704.         }
  705.     }
  706.     /* fprintf(stderr, "read %d\n", n); */
  707.     rd_len += n;
  708.     rawdata = realloc(rawdata, rd_size*=2);
  709.     }
  710.  
  711.     /* data is now read into rawdata. */
  712.  
  713.     realloc(rawdata, rd_len);    /* we don't need all those other bytes
  714.                    anymore */
  715.     fclose_b(fp);
  716.  
  717.     *len = rd_len;
  718.     return rawdata;
  719. }
  720.  
  721. char ** load_argfile(char *argv0, char *fname, int *argc)
  722. {
  723.     FILE    *fp;
  724.     char    buf[1024];
  725.     char    **rval;
  726.     int    size;
  727.  
  728.     *argc=0;
  729.  
  730.     if (!(fp = fopen_b(fname, 0, 0)))
  731.     return 0;
  732.  
  733.     rval = (char**)malloc(sizeof(*rval)*(size=32));
  734.  
  735.     rval[(*argc)++] = argv0;
  736.  
  737.     while (0!=fgets(buf, sizeof(buf), fp)) {
  738.     int    len = strlen(buf);
  739.     if (buf[len-1]=='\n')
  740.         buf[--len] = 0;
  741.     if (len==0)
  742.         continue;        /* totally empty lines don't count */
  743.     if (*argc>=size)
  744.         rval = (char**)realloc(rval, sizeof(*rval)*(size*=2));
  745.     rval[(*argc)++] = strdup(buf);
  746.     }
  747.  
  748.     fclose_b(fp);
  749.  
  750.     return rval;
  751. }
  752.  
  753. void Pause( char *message )
  754. {
  755. #ifdef __MSDOS__
  756.     fprintf(stderr, "%s", message );
  757.     getch();
  758. #endif
  759. }
  760.  
  761. void usage(char *progname)
  762. {
  763.     fprintf(stderr, "Usage:\n");
  764.     fprintf(stderr, "  %s  options  \n", progname);
  765.     fprintf(stderr, "\n");
  766.     fprintf(stderr, "  Options:\n");
  767.     fprintf(stderr, "-argfile file    specifies a file containing command-line arguments (one\n");
  768.     fprintf(stderr, "        per line).  All command-line arguments following this one\n");
  769.     fprintf(stderr, "        will be discarded\n");
  770.     fprintf(stderr, "-bp file    specifies input binary pnames file (such as the PNAMES\n");
  771.     fprintf(stderr, "        resource)\n");
  772.     fprintf(stderr, "-bt file    specifies input binary texture file (such as the TEXTURE1\n");
  773.     fprintf(stderr, "        or TEXTURE2 resource)\n");
  774.     fprintf(stderr, "-ap file    specifies an ascii pnames file (1 name to a line)\n");
  775.     fprintf(stderr, "-at file    specifies an ascii texture file (format NYD)\n");
  776.     fprintf(stderr, "-res file name    loads a raw resource from file and gives it name.  This\n");
  777.      fprintf(stderr, "        option is only effective if the -owad option is used.\n");
  778.     fprintf(stderr, "-iwad file +    specifies an input WAD file to be included in the WAD file\n");
  779.     fprintf(stderr, "        written by the -owad option.  Good for merging in mission\n");
  780.     fprintf(stderr, "        data.\n");
  781.     fprintf(stderr, "-iwad file pname texture ... [+-]\n");
  782.     fprintf(stderr, "        specifies an input WAD file.  The arguments after the\n");
  783.     Pause( "Press any key to see the rest of help...\n" );
  784.     fprintf(stderr, "        file name specify what to search for in the input wad\n");
  785.     fprintf(stderr, "        file's directory to extract the pnames and texture data.\n");
  786.     fprintf(stderr, "        A + or - is required and terminates the list of texture\n");
  787.     fprintf(stderr, "        resources.  If it's a plus and the -owad option is used\n");
  788.     fprintf(stderr, "        then all resources BESIDES the pname and textures are\n");
  789.     fprintf(stderr, "        passed through unmodified to the output WAD.\n");
  790.     fprintf(stderr, "-obp file    specifies an output binary pnames filename\n");
  791.     fprintf(stderr, "-obt file    specifies an output binary texture filename\n");
  792.     fprintf(stderr, "-oap file    specifies an output ascii pnames filename\n");
  793.     fprintf(stderr, "-oat file    specifies an output ascii texture filename\n");
  794.     fprintf(stderr, "-owad file pname texture\n");
  795.     fprintf(stderr, "        specifies an output WAD file.  The arguments before the\n");
  796.     fprintf(stderr, "        file name specify what to call the pnames and texture data\n");
  797.     fprintf(stderr, "        in the output wad file's directory.\n\n");
  798. }
  799.  
  800. /* this is where we store the output filenames. */
  801. struct {
  802.     char    *obp, *obt,
  803.         *oap, *oat,
  804.         *owad, *pname, *texture;
  805. } outfiles = {
  806.     0, 0,
  807.     0, 0,
  808.     0, 0, 0
  809. };
  810.  
  811. #define DEMAND_ARGC(off)    do { if ((i+off)>=argc) { fprintf(stderr, "Too few arguments to option %s (expected %d)\n", argv[i], off); exit(1); } } while (0)
  812.  
  813. int main(int argc, char **argv)
  814. {
  815.     void    *currpnames=0;
  816.     INT32    currpnlen;
  817.     int    i;
  818.  
  819.     fprintf(stderr, "Textures utility version 1.04\n");
  820.     fprintf(stderr, "Copyright (C) 1994 Robert Forsman\n");
  821.      fprintf(stderr, "Gnu General Public License\n");
  822.     fprintf(stderr, "Ported to DOS by Robert Forsman and David Allen\n");
  823.  
  824.     /* parse arguments */
  825.  
  826.     if (argc<2) {
  827.     usage(argv[0]);
  828.     exit(1);
  829.     }
  830.  
  831.     for (i=1; i<argc; i++) {
  832.     if (0==strcmp(argv[i], "-argfile")) {
  833.         DEMAND_ARGC(1);
  834.         argv = load_argfile(argv[0], argv[i+1], &argc);
  835.         if (argv==0) {
  836.         fprintf(stderr, "argfile load aborting\n");
  837.         exit(1);
  838.         }
  839.         i=0;
  840.     } else if (0==strcmp(argv[i], "-bp")) {
  841.         DEMAND_ARGC(1);
  842.         currpnames = slurp_file(argv[i+1], &currpnlen);
  843.          i++;
  844.     } else if (0==strcmp(argv[i], "-bt")) {
  845.          struct texture_gob    *curr = extra_gob();
  846.         if (currpnames==0) {
  847.         fprintf(stderr, "Must specify at least one pnames resource before specifying a binary\ntexture file.  Aborting.\n");
  848.         exit(1);
  849.         }
  850.          DEMAND_ARGC(1);
  851.          curr->tdata = slurp_file(argv[i+1], &curr->tlen);
  852.         curr->pndata = currpnames;
  853.         curr->pnlen = currpnlen;
  854.         i++;
  855.     } else if (0==strcmp(argv[i], "-ap")) {
  856.         DEMAND_ARGC(1);
  857.          currpnames = read_ascii_pnames(argv[i+1], &currpnlen);
  858.         i++;
  859.     } else if (0==strcmp(argv[i], "-at")) {
  860.          struct texture_gob    *curr = extra_gob();
  861.         DEMAND_ARGC(1);
  862.         make_gob_from_textfile(argv[i+1], curr);
  863.         i++;
  864.     } else if (0==strcmp(argv[i], "-iwad")) {
  865.         DEMAND_ARGC(3);
  866.         slurp_iwad(argv, &i);
  867.     } else if (0==strcmp(argv[i], "-res")) {
  868.         DEMAND_ARGC(2);
  869.         slurp_resource(argv[i+1], argv[i+2]);
  870.         i+=2;
  871.     } else if (0==strcmp(argv[i], "-obt")) {
  872.         DEMAND_ARGC(1);
  873.         if (outfiles.obt!=0) {
  874.         fprintf(stderr, "One output-binary-texture file already specified, ignoring second\n");
  875.         } else {
  876.         outfiles.obt = argv[i+1];
  877.         }
  878.         i++;
  879.     } else if (0==strcmp(argv[i], "-obp")) {
  880.         DEMAND_ARGC(1);
  881.         if (outfiles.obp!=0) {
  882.         fprintf(stderr, "One output-binary-pnames file already specified, ignoring second\n");
  883.         } else {
  884.         outfiles.obp = argv[i+1];
  885.         }
  886.         i++;
  887.     } else if (0==strcmp(argv[i], "-oat")) {
  888.         DEMAND_ARGC(1);
  889.         if (outfiles.oat!=0) {
  890.         fprintf(stderr, "One output-ascii-texture file already specified, ignoring second\n");
  891.         } else {
  892.         outfiles.oat = argv[i+1];
  893.         }
  894.         i++;
  895.     } else if (0==strcmp(argv[i], "-oap")) {
  896.         DEMAND_ARGC(1);
  897.         if (outfiles.oap!=0) {
  898.         fprintf(stderr, "One output-ascii-pnames file already specified, ignoring second\n");
  899.         } else {
  900.         outfiles.oap = argv[i+1];
  901.         }
  902.         i++;
  903.     } else if (0==strcmp(argv[i], "-owad")) {
  904.         DEMAND_ARGC(3);
  905.         if (outfiles.owad!=0) {
  906.         fprintf(stderr, "One output WAD file already specified, ignoring second\n");
  907.         } else {
  908.         outfiles.owad = argv[i+1];
  909.         outfiles.pname = argv[i+2];
  910.         outfiles.texture = argv[i+3];
  911.         }
  912.         i+=3;
  913.     } else {
  914.         static int once = 0;
  915.         fprintf(stderr, "Unknown option %s\n", argv[i]);
  916.         if (!once) {
  917.         usage(argv[0]);
  918.         once = 1;
  919.         }
  920.     }
  921.     }
  922.  
  923.     /* merge all the texture resources we've been given into one big gob. */
  924.  
  925.     compile_textures();
  926.  
  927.     /* start writing output files. */
  928.  
  929.     if (outfiles.owad!=0) {
  930.     spurt_owad(outfiles.owad, outfiles.pname, outfiles.texture);
  931.     }
  932.     if (outfiles.obp) {
  933.     FILE    *fp = fopen_b(outfiles.obp, 1, 1);
  934.     if (fp) {
  935.         fwrite(output_pnames, oplen, 1, fp);
  936.         fclose_b(fp);
  937.     }
  938.     }
  939.     if (outfiles.obt) {
  940.     FILE    *fp = fopen_b(outfiles.obt, 1, 1);
  941.     if (fp) {
  942.         fwrite(output_texture, otlen, 1, fp);
  943.         fclose_b(fp);
  944.     }
  945.     }
  946.     if (outfiles.oap) {
  947.     FILE    *fp = fopen_b(outfiles.oap, 1, 0);
  948.     if (fp) {
  949.         int    i,j;
  950.         for (i=0; i<output_pnames->count; i++) {
  951.         for (j=0; output_pnames->names[i][j] && j<8; j++)
  952.             putc(output_pnames->names[i][j], fp);
  953.         putc('\n', fp);
  954.         }
  955.         fclose_b(fp);
  956.     }
  957.     }
  958.     if (outfiles.oat) {
  959.     FILE    *fp = fopen_b(outfiles.oat, 1, 0);
  960.     if (fp) {
  961.         pretty_print(fp);
  962.         fclose_b(fp);
  963.     }
  964.     }
  965.  
  966.     return 0;
  967. }
  968.