ref: 6fee0412330c64804d8401ec61cb725b41517bd0
parent: acd94a2a4561fe213b2706681c40b199a1ecf164
author: qwx <qwx@sciops.net>
date: Mon Jan 4 21:46:09 EST 2021
remove imported programs
--- a/dpic.c
+++ /dev/null
@@ -1,132 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <bio.h>
-
-int dx = 64, dy = 64;
-Biobuf *bi, *bo;
-u32int pal[256];
-
-u8int
-get8(void)
-{
- uchar v;
-
- if(Bread(bi, &v, 1) != 1)
- sysfatal("get8: short read");
- return v;
-}
-
-u16int
-get16(void)
-{
- u8int v;
-
- v = get8();
- return get8() << 8 | v;
-}
-
-u32int
-get32(void)
-{
- u16int v;
-
- v = get16();
- return get16() << 16 | v;
-}
-
-u32int*
-unpic(void)
-{
- int n, h;
- u32int *p, *d, *cols, *buf;
-
- dx = get16();
- dy = get16();
- cols = mallocz(dx * sizeof *cols, 1);
- buf = mallocz(dx * dy * sizeof *buf, 1);
- if(cols == nil || buf == nil)
- sysfatal("mallocz: %r");
- get32();
- for(p=cols; p<cols+dx; p++)
- *p = get32();
- for(p=cols; p<cols+dx; p++){
- Bseek(bi, *p, 0);
- for(;;){
- if((h = get8()) == 0xff)
- break;
- n = get8();
- get8();
- for(d=buf+(p-cols)+h*dx; n-->0; d+=dx)
- *d = pal[get8()];
- get8();
- }
- }
- free(cols);
- return buf;
-}
-
-u32int*
-unflat(void)
-{
- u32int *p;
- static u32int buf[4096];
-
- for(p=buf; p<buf+nelem(buf); p++)
- *p = pal[get8()];
- return buf;
-}
-
-void
-getpal(char *f)
-{
- uchar u[3];
- u32int *p;
- Biobuf *bp;
-
- if((bp = Bopen(f, OREAD)) == nil)
- sysfatal("getpal: %r");
- for(p=pal; p<pal+nelem(pal); p++){
- if(Bread(bp, u, 3) != 3)
- sysfatal("getpal: short read: %r");
- *p = u[2]<<16 | u[1]<<8 | u[0];
- }
- Bterm(bp);
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: %s [-f] [-p palette] pic\n", argv0);
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int fd, flat;
- char *p, c[9];
- u32int *buf;
-
- flat = 0;
- p = "/mnt/wad/playpal";
- ARGBEGIN{
- case 'f': flat = 1; break;
- case 'p': p = EARGF(usage()); break;
- default: usage();
- }ARGEND
- if(*argv == nil)
- usage();
- if((fd = open(*argv, OREAD)) < 0)
- sysfatal("open: %r");
- getpal(p);
- bi = Bfdopen(fd, OREAD);
- bo = Bfdopen(1, OWRITE);
- if(bi == nil || bo == nil)
- sysfatal("Bfdopen: %r");
- buf = flat ? unflat() : unpic();
- Bprint(bo, "%11s %11d %11d %11d %11d ",
- chantostr(c, XBGR32), 0, 0, dx, dy);
- Bwrite(bo, buf, dx * dy * sizeof *buf);
- exits(nil);
-}
--- a/man/1/dpic
+++ /dev/null
@@ -1,118 +1,0 @@
-.TH DPIC 1
-.SH NAME
-dpic, todpic \- Doom picture decoder and encoder
-.SH SYNOPSIS
-.B dpic
-[
-.B -f
-] [
-.B -p
-.I palette
-] [
-.I pic
-]
-.PP
-.B todpic
-[
-.B -fw
-] [
-.B -b
-.I bgcol
-] [
-.B -p
-.I palette
-] [
-.I image
-]
-.SH DESCRIPTION
-.I Dpic
-reads a doom picture formatted image (default standard input),
-converts it to a Plan 9
-.IR image (6)
-and writes it to standard out.
-.I Todpic
-does the opposite transformation.
-.PP
-A color palette is needed for the process;
-its location is set to
-.B /mnt/wad/playpal
-by default.
-This may be overridden with the
-.B -p
-command line option.
-Both programs also accept an
-.B -f
-flag to indicate processing a doom 64x64 flat picture.
-.PP
-When encoding a doom picture,
-x and y offsets are set to the input's top left corner coordinates.
-The
-.B -w
-flag sets the offsets so as to center the picture when drawn by the doom engine,
-which is useful for wall patches.
-The
-.B -b
-option sets the RGB24 color to signal transparent pixels,
-.L 0x00FFFF
-by default.
-.SH EXAMPLES
-Create a patch
-.I WAD
-(see
-.IR wadfs (4))
-replacing a sky texture.
-First, create a 256x128 image, mirror it, and convert it for use with
-.IR tweak (1).
-.IP
-.EX
-% png -9t tuttleglenda.png \\
- | resample -x 128 -y 128 \\
- | crop -r 0 0 256 128 \\
- | rotate -l \\
- | iconv -c m8 > tuttlesky
-.EE
-.PP
-Next, use
-.IR tweak (1)
-to tile the 128x128 picture.
-Then, mount an
-.I IWAD
-containing the base color palette, convert to a doom picture,
-create a patch
-.IR WAD ,
-then launch doom using it.
-.IP
-.EX
-% games/wadfs /sys/games/lib/doom/doom2.wad
-createfile SW18_7: file already exists
-% games/wadfs -m /mnt/new
-% games/todpic tuttlesky > /mnt/new/rsky1
-% cp /mnt/new/WAD tuttle.wad
-% games/doom -file tuttle.wad
-.EE
-.PP
-Create a crude catclock weapon sprite.
-.IP
-.EX
-% games/wadfs /sys/games/lib/doom/doom2.wad
-createfile SW18_7: file already exists
-% mkdir /mnt/new/s
-adding end marker S_END
-% cp /mnt/wad/s/* /mnt/new/s/
-% crop -r 0 0 114 120 -t -120 -60 catclock.bit \\
- | games/todpic -b 0xffffff > /mnt/new/s/punga0
-% games/doom -file /mnt/new/WAD
-.EE
-.SH SOURCE
-.B /sys/src/games/dpic.c
-.br
-.B /sys/src/games/todpic.c
-.SH "SEE ALSO"
-.IR games (1),
-.IR tweak (1),
-.IR wadfs (4)
-.SH HISTORY
-.I Dpic
-and
-.I todpic
-first appeared in 9front (July, 2018).
--- a/man/1/mus
+++ /dev/null
@@ -1,23 +1,0 @@
-.TH MUS 1
-.SH NAME
-mus \- MUS to MIDI converter
-.SH SYNOPSIS
-.B games/mus
-[
-.I musfile
-]
-.SH DESCRIPTION
-The MUS format is a simplified MIDI music format used in doom
-and several related games.
-.PP
-.I Mus
-decodes MIDI music encoded in MUS format, either from
-.B musfile
-or from standard input, and produces a MIDI format file on standard output.
-.SH "SEE ALSO"
-.IR games (1)
-.SH SOURCE
-.B /sys/src/games/mus.c
-.SH HISTORY
-.I Mus
-first appeared in 9front (September, 2015).
--- a/man/4/wadfs
+++ /dev/null
@@ -1,192 +1,0 @@
-.TH WADFS 4
-.SH NAME
-wadfs \- WAD file system
-.SH SYNOPSIS
-.B wadfs
-[
-.B -Dr
-] [
-.B -m
-.I mtpt
-] [
-.B -S
-.I srvname
-] [
-.I WAD
-]
-.SH DESCRIPTION
-.I Wadfs
-serves a file tree mounted at
-.I mtpt
-(default
-.BR /mnt/wad )
-that provides access to a
-.I WAD
-file's contents.
-.PP
-The command line options are:
-.TF "-S srvname"
-.TP
-.B -D
-Enable 9P debugging messages.
-.TP
-.B -r
-Set read-only file tree.
-.TP
-.BI -S \ srvname
-Post channel on
-.RI /srv/ srvname .
-.TP
-.BI -m \ mtpt
-Set mountpoint.
-.PD
-.PP
-A
-.I WAD
-is a concatenation of uncompressed files, referred to as lumps.
-A lump may contain either data,
-or be used as a marker to indicate the beginning or end of a section,
-segregating lumps of the same format.
-.PP
-.I Wadfs
-represents section start markers as directories,
-and regular lumps and end markers as files.
-For convenience, lump file names are in lower case,
-and are translated to the upper case internally.
-.PP
-At startup, if the path to a
-.I WAD
-file is provided as argument,
-.I wadfs
-will attempt to parse it and construct a file tree.
-Otherwise,
-.I wadfs
-starts with a blank tree instead.
-.PP
-Two additional files are provided in the file system's root directory:
-.L SIG
-and
-.LR WAD .
-Reading from and writing to
-.L SIG
-allows accessing and changing the
-.IR WAD 's
-type.
-The only possible values are
-.L PWAD
-(the default) and
-.LR IWAD .
-.PP
-.L WAD
-returns the new
-.I WAD
-file resulting from the recompilation of the lump tree.
-.SS "WAD file structure"
-There are few restrictions on the structure of
-.I WAD
-files.
-Excepting maps, sections can nest and may have no end marker,
-or one named differently than the section itself.
-Regular sections typically have one-letter names,
-and nested sections use the same name appended by a digit.
-By convention,
-lump names may only contain visible printing
-.SM ASCII
-characters,
-excepting lower-case letters.
-Map sections do not end at a marker but at the next non map lump,
-and use hardcoded names, depending on game version.
-.PP
-.I Wadfs
-imposes a number of additional restrictions on structure and naming:
-.IP • 3
-Lump names may not contain upper-case letters and the
-.L /
-character.
-.IP •
-A map section may only contain map lumps, which use hardcoded names.
-Ordering is significant, but is handled automatically.
-Map sections may not nest.
-.IP •
-Regular sections may not nest beyond one level,
-and may not contain more than one end marker.
-End markers may not exist outside of a section.
-Directory names omit the start marker's
-.L "_START"
-suffix.
-.IP •
-Excepting map lumps, no two lumps, including markers,
-may have the same name.
-.IP •
-Once created, a lump may not be renamed so as to change its type.
-.SS "Error recovery"
-Upon parsing the initial
-.I WAD
-file, if one of the restrictions for
-.I WAD
-file structure outlined in the sections above is not respected,
-a warning is issued, and the offending lump is potentially skipped.
-Some recovery is attempted,
-but one must systematically recheck the tree.
-When duplicate non marker lumps are encountered,
-each will overwrite the previous entry.
-.SH EXAMPLES
-Open
-.B doom2.wad
-and play a MUS file:
-.IP
-.EX
-% games/wadfs /sys/games/lib/doom/doom2.wad
-createfile SW18_7: file already exists
-% games/mus /mnt/wad/d_romero | games/midi
-.EE
-.PP
-Now create a blank
-.IR WAD ,
-then one section
-.LR FF ;
-copy a flat from
-.B doom2.wad
-to the directory,
-then rename the end marker to
-.L F_END
-to have the
-.B doom
-engine find the flat;
-finally, compile and save the new
-.I WAD
-file.
-.IP
-.EX
-% games/wadfs -m /mnt/wad2
-% cd /mnt/wad2
-% mkdir ff
-adding end marker FF_END
-% cp ../wad/f/f1/f_sky1 ff/
-% mv ff/ff_end ff/f_end
-% cp WAD /sys/games/lib/doom/sky.wad
-.EE
-.SH SOURCE
-.B /sys/src/games/wadfs.c
-.SH "SEE ALSO"
-.IR games (1),
-.IR mus (1)
-.SH HISTORY
-.I Wadfs
-first appeared in 9front (August, 2017).
-.SH BUGS
-Many
-.I WAD
-files in the wild do not conform to all the rules exposed above,
-in particular ones using
-.SM DeHackEd
-engine modifications.
-.IR WAD 's
-using end markers outside of a section,
-typically
-.LR F_END ,
-will lose them.
-.PP
-Repairing broken
-.I WAD
-files can be a pain.
--- a/mus.c
+++ /dev/null
@@ -1,219 +1,0 @@
-#include <u.h>
-#include <libc.h>
-
-typedef struct Trk Trk;
-struct Trk{
- u32int len;
- uchar *dat;
- uchar *p;
- uchar *end;
- uchar v[16];
- int done;
-};
-Trk t;
-uchar *mcmd, *mp, *me;
-int fd;
-
-#define PBIT16(p,v) (p)[0]=(v);(p)[1]=(v)>>8
-#define BBIT32(p,v) (p)[3]=(v);(p)[2]=(v)>>8;(p)[1]=(v)>>16;(p)[0]=(v)>>24
-
-void
-eread(int fd, void *u, long n)
-{
- if(readn(fd, u, n) != n)
- sysfatal("readn: %r");
-}
-
-uchar
-r8(void)
-{
- return *t.p++;
-}
-
-void
-delay(void)
-{
- uchar v;
-
- do{
- v = r8();
- *mp++ = v;
- }while(v & 0x80);
-}
-
-void
-putcmd(uchar *cmd, int n)
-{
- if(mp + n >= me){
- me += 8192;
- mcmd = realloc(mcmd, me - mcmd);
- if(mcmd == nil)
- sysfatal("realloc: %r");
- }
- memcpy(mp, cmd, n);
- mp += n;
-}
-
-void
-ev(void)
-{
- uchar e, v, cmd[3], *p;
-
- e = r8();
- p = cmd;
- switch(e >> 4 & 7){
- case 0:
- v = r8() & 0x7f;
- *p++ = e | 0x80;
- *p++ = v;
- *p++ = 0x40;
- break;
- case 1:
- v = r8();
- *p++ = e | 0x80;
- *p++ = v & 0x7f;
- if(v & 0x80)
- t.v[e & 15] = r8() & 0x7f;
- *p++ = t.v[e & 15];
- break;
- case 2:
- v = r8();
- *p++ = e | 0xc0;
- PBIT16(p, v << 7 & 0x7f7f);
- p += 2;
- break;
- case 3:
- v = r8();
- *p++ = 0xb | e & 15;
- switch(v){
- case 10: *p++ = 0x78; break;
- case 11: *p++ = 0x7b; break;
- case 12: *p++ = 0x7e; break;
- case 13: *p++ = 0x7f; break;
- case 14: *p++ = 0x79; break;
- default: sysfatal("unknown system event %ux\n", v);
- }
- *p++ = 0;
- break;
- case 4:
- v = r8();
- if(v > 9)
- sysfatal("unknown controller %ux\n", v);
- *p++ = 0xb0 | e & 15;
- switch(v){
- case 1: *p++ = 0x00; break;
- case 2: *p++ = 0x01; break;
- case 3: *p++ = 0x07; break;
- case 4: *p++ = 0x0a; break;
- case 5: *p++ = 0x0b; break;
- case 6: *p++ = 0x5b; break;
- case 7: *p++ = 0x5d; break;
- case 8: *p++ = 0x40; break;
- case 9: *p++ = 0x43; break;
- }
- *p++ = r8() & 0x7f;
- if(v == 0)
- cmd[0] += 0x10;
- break;
- case 6:
- *p++ = 0xff;
- *p++ = 0x2f;
- e = 0;
- t.done++;
- break;
- default:
- sysfatal("unknown event %ux\n", e >> 4 & 7);
- }
- if((e & 15) == 9)
- cmd[0] |= 6;
- if((e & 15) == 15)
- cmd[0] &= ~6;
- putcmd(cmd, p-cmd);
- if(e & 0x80)
- delay();
- else
- *mp++ = 0;
-}
-
-void
-reset(void)
-{
- memset(t.v, 0x7f, sizeof t.v);
- mcmd = mallocz(t.len * 2, 1);
- if(mcmd == nil)
- sysfatal("mallocz: %r");
- mp = mcmd;
- me = mcmd + t.len * 2;
-}
-
-void
-barf(void)
-{
- static uchar hdr[] = {
- 'M', 'T', 'h', 'd',
- 0x00, 0x00, 0x00, 0x06,
- 0x00, 0x00,
- 0x00, 0x01,
- 0x01, 0x01,
- 'M', 'T', 'r', 'k',
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xb0, 0x07, 0x7f,
- 0x00, 0xb1, 0x07, 0x7f,
- 0x00, 0xb2, 0x07, 0x7f,
- 0x00, 0xb3, 0x07, 0x7f,
- 0x00, 0xb4, 0x07, 0x7f,
- 0x00, 0xb5, 0x07, 0x7f,
- 0x00, 0xb6, 0x07, 0x7f,
- 0x00, 0xb7, 0x07, 0x7f,
- 0x00, 0xb8, 0x07, 0x7f,
- 0x00, 0xb9, 0x07, 0x7f,
- 0x00, 0xba, 0x07, 0x7f,
- 0x00, 0xbb, 0x07, 0x7f,
- 0x00, 0xbc, 0x07, 0x7f,
- 0x00, 0xbd, 0x07, 0x7f,
- 0x00, 0xbe, 0x07, 0x7f,
- 0x00, 0xbf, 0x07, 0x7f,
- 0x00, 0xff, 0x51, 0x03, 0x1b, 0x8a, 0x06,
- 0x00
- };
- int n;
-
- n = sizeof(hdr) - 22 + mp - mcmd;
- BBIT32(hdr + 18, n);
- write(1, hdr, sizeof hdr);
- write(1, mcmd, mp - mcmd);
-}
-
-void
-main(int argc, char *argv[])
-{
- int n, ofs;
- uchar s[8], b[1024];
-
- if(argc > 1){
- fd = open(argv[1], OREAD);
- if(fd < 0)
- sysfatal("open: %r");
- }
- eread(fd, s, sizeof s);
- if(memcmp(s, "MUS\x1a", 4) != 0)
- sysfatal("invalid mus file: %r");
- t.len = s[5] << 8 | s[4];
- ofs = (s[7] << 8 | s[6]) - 8;
- while(ofs > 0){
- n = ofs > sizeof b ? sizeof b : ofs;
- eread(fd, b, n);
- ofs -= n;
- }
- t.dat = malloc(t.len);
- if(t.dat == nil)
- sysfatal("malloc: %r");
- t.p = t.dat;
- t.end = t.dat + t.len;
- eread(fd, t.dat, t.len);
- reset();
- while(!t.done && t.p < t.end)
- ev();
- barf();
- exits(nil);
-}
--- a/todpic.c
+++ /dev/null
@@ -1,190 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <draw.h>
-#include <memdraw.h>
-#include <bio.h>
-
-int wofs;
-u32int pal[256], bg = 0x00ffff;
-Biobuf *bp;
-
-#define abs(x) ((x) < 0 ? -(x) : (x))
-
-void
-put8(u8int v)
-{
- if(Bwrite(bp, &v, sizeof v) != sizeof v)
- sysfatal("put8: short write");
-}
-
-void
-put16(u16int v)
-{
- put8(v);
- put8(v >> 8);
-}
-
-void
-put32(u32int v)
-{
- put16(v);
- put16(v >> 16);
-}
-
-int
-pali(u32int v)
-{
- int i, Δ, Δ´;
- u32int *p;
-
- i = 0;
- Δ = abs((char)v - (char)*pal)
- + abs((char)(v >> 8) - (char)(*pal >> 8))
- + abs((char)(v >> 16) - (char)(*pal >> 16));
- for(p=pal; p<pal+nelem(pal); p++){
- Δ´ = abs((char)v - (char)*p)
- + abs((char)(v >> 8) - (char)(*p >> 8))
- + abs((char)(v >> 16) - (char)(*p >> 16));
- if(Δ´ < Δ){
- Δ = Δ´;
- i = p - pal;
- if(Δ == 0)
- break;
- }
- }
- return i;
-}
-
-void
-topic(Memimage *i)
-{
- int w, h, dx, dy;
- uchar *np, *b, *buf, *p, *pp;
- u32int v;
-
- p = i->data->bdata;
- dx = Dx(i->r);
- dy = Dy(i->r);
- if(dy > 254)
- sysfatal("topic: invalid pic height");
- put16(dx);
- put16(dy);
- put16(wofs ? dx / 2 - 1 : i->r.min.x);
- put16(wofs ? dy - 5 : i->r.min.y);
- if(i->r.min.x != 0)
- dx = i->width;
- buf = mallocz((5 * dy / 2 + 5) * dx, 1);
- if(buf == nil)
- sysfatal("mallocz: %r");
- for(w=dx, b=buf; w>0; w--, p+=3){
- put32(b - buf + 8 + dx * 4);
- for(h=0, np=b+1, pp=p; h<dy; h++, pp+=dx*3){
- v = pp[2] << 16 | pp[1] << 8 | pp[0];
- if(v == bg){
- if(b - np - 2 > 0){
- *np = b - np - 2;
- *b++ = 0;
- np = b + 1;
- }
- continue;
- }
- if(b - np - 2 < 0){
- *b++ = h;
- b++;
- *b++ = 0;
- }
- *b++ = pali(v);
- }
- if(b - np - 2 >= 0){
- *np = b - np - 2;
- *b++ = 0;
- }
- *b++ = 0xff;
- }
- Bwrite(bp, buf, b - buf);
- free(buf);
-}
-
-void
-toflat(Memimage *i)
-{
- int n;
- uchar *p;
-
- if(Dx(i->r) != 64 || Dy(i->r) != 64)
- sysfatal("toflat: invalid flatpic dimensions");
- p = i->data->bdata;
- n = 64*64;
- while(n-- > 0){
- put8(pali(p[2] << 16 | p[1] << 8 | p[0]));
- p += 4;
- }
-}
-
-static Memimage*
-iconv(Memimage *i)
-{
- Memimage *ni;
-
- if(i->chan == RGB24)
- return i;
- if((ni = allocmemimage(i->r, RGB24)) == nil)
- sysfatal("allocmemimage: %r");
- memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S);
- freememimage(i);
- return ni;
-}
-
-void
-getpal(char *f)
-{
- uchar u[3];
- u32int *p;
- Biobuf *bp;
-
- if((bp = Bopen(f, OREAD)) == nil)
- sysfatal("getpal: %r");
- for(p=pal; p<pal+nelem(pal); p++){
- if(Bread(bp, u, 3) != 3)
- sysfatal("getpal: short read: %r");
- *p = u[0]<<16 | u[1]<<8 | u[2];
- }
- Bterm(bp);
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: %s [-fw] [-b bgcol] [-p palette] [image]\n", argv0);
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int fd, flat;
- char *p;
- Memimage *i;
-
- fd = 0;
- flat = 0;
- p = "/mnt/wad/playpal";
- ARGBEGIN{
- case 'b': bg = strtoul(EARGF(usage()), nil, 0); break;
- case 'f': flat = 1; break;
- case 'p': p = EARGF(usage()); break;
- case 'w': wofs = 1; break;
- default: usage();
- }ARGEND
- if(*argv != nil)
- if((fd = open(*argv, OREAD)) < 0)
- sysfatal("open: %r");
- getpal(p);
- if((bp = Bfdopen(1, OWRITE)) == nil)
- sysfatal("Bfdopen: %r");
- memimageinit();
- if((i = readmemimage(fd)) == nil)
- sysfatal("readmemimage: %r");
- (flat ? toflat : topic)(iconv(i));
- exits(nil);
-}
--- a/wadfs.c
+++ /dev/null
@@ -1,864 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-#include <bio.h>
-
-enum{
- Nsig = 4,
- Nhdr = Nsig+4+4,
- Ndict = 4+4+8,
- Nname = 8,
- Nbuf = 8192,
- Maxsz = 0x7fffffff - Nhdr
-};
-
-enum{
- LTnil,
- LTreg,
- LTmap,
- LTmrk,
- LTend
-};
-typedef struct Lump Lump;
-struct Lump{
- char name[Nname+1];
- u32int ofs;
- uchar *buf;
- ulong nbuf;
- int type;
- File *f;
- Lump *l;
- Lump *lp;
-};
-Lump l1 = {.l = &l1, .lp = &l1}, *lumps = &l1;
-
-Biobuf *wad;
-u32int nlmp;
-File *ldir, *fsig, *fwad;
-int rdonly, dirty;
-
-Srv fs;
-
-char *mapn[] = {
- "things", "linedefs", "sidedefs", "vertexes", "segs",
- "ssectors", "nodes", "sectors", "reject", "blockmap"
-};
-
-void
-strupr(char *s, char *p)
-{
- char c;
-
- do{
- c = *p++;
- *s++ = toupper(c);
- }while(c != 0);
-}
-
-void
-strlwr(char *s, char *p)
-{
- char c;
-
- do{
- c = *p++;
- *s++ = tolower(c);
- }while(c != 0);
-}
-
-void
-link(Lump *l, Lump *lp, int len)
-{
- l->lp = lp;
- l->l = lp->l;
- lp->l->lp = l;
- lp->l = l;
- nlmp++;
- fwad->length += Ndict + len;
-}
-
-void
-unlink(Lump *l)
-{
- if(l->l == nil)
- return;
- l->lp->l = l->l;
- l->l->lp = l->lp;
- l->l = nil;
- nlmp--;
- fwad->length -= Ndict + (l->f != nil ? l->f->length : 0);
-}
-
-void
-freelump(Lump *l)
-{
- unlink(l);
- free(l->buf);
- free(l);
-}
-
-void
-readlump(Lump *l, uchar *p, long n)
-{
- if(n <= 0)
- return;
- Bseek(wad, l->ofs, 0);
- if(Bread(wad, p, n) != n)
- fprint(2, "readlump: short read: %r\n");
-}
-
-void
-loadlump(File *f, ulong n)
-{
- Lump *l;
-
- l = f->aux;
- if(f->length > n)
- n = f->length;
- l->buf = emalloc9p(n);
- l->nbuf = n;
- l->ofs = 0;
- readlump(l, l->buf, f->length);
-}
-
-Lump *
-lastlump(Lump *lp)
-{
- File *f, *dir;
-
- for(dir=lp->f, f=lp->l->f; lp->l!=lumps; lp=lp->l, f=lp->l->f)
- if(f->parent != dir && f->parent->parent != dir)
- break;
- if(lp->type == LTend && lp->f->parent == dir)
- lp = lp->lp;
- return lp;
-}
-
-int
-nextmaplump(char *s)
-{
- char **p;
-
- for(p=mapn; p<mapn+nelem(mapn); p++)
- if(strcmp(s, *p) == 0)
- return p-mapn;
- return -1;
-}
-
-Lump *
-sortmap(Lump *lp, Lump *l)
-{
- int ip, i;
-
- i = nextmaplump(l->f->name);
- for(; lp->l != lumps; lp=lp->l){
- ip = nextmaplump(lp->l->f->name);
- if(ip < 0 || ip > i)
- break;
- }
- return lp;
-}
-
-int
-ismaplump(char *s)
-{
- return nextmaplump(s) >= 0;
-}
-
-int
-ismapname(char *s)
-{
- if(strncmp(s, "map", 3) == 0)
- return isdigit(s[3]) && isdigit(s[4]);
- return s[0] == 'e' && isdigit(s[1])
- && s[2] == 'm' && isdigit(s[3]);
-}
-
-int
-ismarkname(char *s, char *m)
-{
- char *p;
-
- p = strstr(s, m);
- if(p == nil || p[strlen(m)] != 0)
- return 0;
- if(p - s > 2)
- return 0;
- return 1;
-}
-
-int
-validname(char *s, File *dir, int *type, int isnew, int isdir)
-{
- int n;
- char c, *p;
- Lump *lp;
-
- *type = LTnil;
- n = strlen(s);
- if(n < 1 || n > sizeof(lp->name)-1){
- werrstr("invalid lump name");
- return 0;
- }
- for(p=s+n-1; c=*p, p-->=s;)
- if(!isprint(c) || isupper(c) || c == '/'){
- werrstr("invalid char %c in filename", c);
- return 0;
- }
- if(isnew && !ismaplump(s))
- for(lp=lumps->l; lp!=lumps; lp=lp->l)
- if(cistrcmp(s, lp->name) == 0){
- werrstr("duplicate non map lump");
- return 0;
- }
- *type = LTreg;
- lp = dir->aux;
- if(ismapname(s)){
- *type = LTmap;
- if(isnew && !isdir){
- werrstr("map marker not a directory");
- return 0;
- }else if(dir != fs.tree->root){
- werrstr("nested map directory");
- return 0;
- }
- return 1;
- }else if(ismarkname(s, "_end")){
- *type = LTend;
- if(dir == fs.tree->root || lp == nil || lp->type == LTmap){
- werrstr("orphaned end marker");
- return 0;
- }
- return 1;
- }else if(ismarkname(s, "_start")){
- *type = LTmrk;
- if(isnew){
- werrstr("not allowed");
- return 0;
- }
- goto mrkchk;
- }else if(isnew && isdir){
- *type = LTmrk;
- if(n > 2){
- werrstr("marker name too long");
- return 0;
- }
-mrkchk:
- if(dir->parent != fs.tree->root){
- werrstr("start marker nested too deep");
- return 0;
- }else if(lp != nil && lp->type == LTmap){
- werrstr("start marker within map directory");
- return 0;
- }
- return 1;
- }else if(ismaplump(s) ^ (lp != nil && lp->type == LTmap)){
- werrstr("map lump outside of map directory");
- return 0;
- }
- return 1;
-}
-
-int
-endldir(Lump *lp, Lump *le)
-{
- char *s, name[sizeof lp->name];
- Lump *l;
- File *f;
-
- l = emalloc9p(sizeof *l);
- strcpy(l->name, lp->name);
- s = strrchr(l->name, '_');
- strcpy(s, "_END");
- strlwr(name, l->name);
- fprint(2, "adding end marker %s\n", l->name);
- if(!validname(name, lp->f, &l->type, 1, 0) || l->type != LTend)
- goto err;
- f = createfile(lp->f, name, nil, lp->f->mode & 0666, l);
- if(f == nil)
- goto err;
- closefile(f);
- l->f = f;
- link(l, le, 0);
- return 0;
-err:
- free(l);
- return -1;
-}
-
-void
-accessfile(File *f, int mode)
-{
- f->atime = time(nil);
- if(mode & AWRITE){
- f->mtime = f->atime;
- f->qid.vers++;
- dirty = 1;
- }
-}
-
-void
-fswstat(Req *r)
-{
- int type;
- char *e;
- File *f, *fp;
- Lump *lp;
-
- e = "permission denied";
- if(rdonly)
- goto err;
- if(r->d.mode != ~0 || r->d.gid[0] != 0)
- goto err;
- f = r->fid->file;
- lp = f->aux;
- if(r->d.length != ~0 && r->d.length != f->length){
- if(f == fsig || f->mode & DMDIR)
- goto err;
- if(!hasperm(f, r->fid->uid, AWRITE))
- goto err;
- if(r->d.length < 0){
- e = "invalid file length";
- goto err;
- }
- if(fwad->length - f->length + r->d.length >= Maxsz){
- e = "lump size exceeds wad limit";
- goto err;
- }
- }
- if(r->d.name[0] != 0 && strcmp(r->d.name, f->name) != 0){
- fp = f->parent;
- if(fp == nil){
- e = "orphaned file";
- goto err;
- }
- if(!hasperm(fp, r->fid->uid, AWRITE))
- goto err;
- if(!validname(r->d.name, fp, &type, 1, f->mode & DMDIR)){
- responderror(r);
- return;
- }
- if(lp->type != type){
- e = "incompatible lump type";
- goto err;
- }
- incref(fp);
- fp = walkfile(fp, r->d.name);
- if(fp != nil){
- e = "file already exists";
- goto err;
- }
- }
-
- if(r->d.length != ~0 && r->d.length != f->length){
- if(lp->buf == nil)
- loadlump(f, r->d.length);
- fwad->length += r->d.length - f->length;
- f->length = r->d.length;
- }
- if(r->d.name[0] != 0 && strcmp(r->d.name, f->name) != 0){
- free(f->name);
- f->name = estrdup9p(r->d.name);
- strupr(lp->name, f->name);
- if(lp->type == LTmrk)
- strcat(lp->name, "_START");
- }
- accessfile(f, AWRITE);
- if(r->d.mtime != ~0)
- f->mtime = r->d.mtime;
- respond(r, nil);
- return;
-err:
- respond(r, e);
-}
-
-void
-fsremove(Req *r)
-{
- File *f;
- Lump *lp;
-
- f = r->fid->file;
- lp = f->aux;
- if(f == fsig || f == fwad){
- respond(r, "not allowed");
- return;
- }else if(lp->l->f != nil && lp->l->f->parent == f){
- respond(r, "has children");
- return;
- }
- unlink(f->aux);
- dirty = 1;
- respond(r, nil);
-}
-
-char *
-writesig(uchar *buf, char *s, vlong n)
-{
- if(n > Nsig+1 || strncmp(s, "IWAD", Nsig) != 0 && strncmp(s, "PWAD", Nsig) != 0)
- return "invalid wad signature";
- memcpy(buf, s, Nsig);
- dirty = 1;
- return nil;
-}
-
-void
-fswrite(Req *r)
-{
- vlong n, m, ofs, end;
- File *f;
- Lump *l;
-
- f = r->fid->file;
- n = r->ifcall.count;
- ofs = r->ifcall.offset;
- if(f->mode & DMAPPEND)
- ofs = f->length;
- end = ofs + n;
- l = f->aux;
- if(f == fsig){
- respond(r, writesig(l->buf, r->ifcall.data, n));
- return;
- }
- if(l->buf == nil)
- loadlump(f, end + Nbuf);
- if(end > l->nbuf){
- m = l->nbuf + Nbuf > end ? l->nbuf + Nbuf : end;
- if(fwad->length - l->nbuf + m >= Maxsz){
- respond(r, "lump size exceeds wad limit");
- return;
- }
- l->buf = erealloc9p(l->buf, m);
- l->nbuf = m;
- }
- memcpy(l->buf + ofs, r->ifcall.data, n);
- m = end - f->length;
- if(m > 0){
- f->length += m;
- fwad->length += m;
- }
- accessfile(f, AWRITE);
- r->ofcall.count = n;
- respond(r, nil);
-}
-
-void
-makewad(void)
-{
- vlong n;
- uchar *p;
- u32int ofs;
- Lump *l, *lp;
-
- l = fwad->aux;
- free(l->buf);
- l->buf = emalloc9p(fwad->length);
- p = l->buf;
- lp = fsig->aux;
- memcpy(p, lp->buf, 4), p += 4;
- PBIT32(p, nlmp);
- p += 8;
- for(lp=lumps->l; lp!=lumps; p+=n, lp=lp->l){
- n = lp->f->length;
- if(lp->buf != nil)
- memcpy(p, lp->buf, n);
- else
- readlump(lp, p, n);
- }
- PBIT32(l->buf + 8, p - l->buf);
- ofs = Nhdr;
- for(lp=lumps->l; lp!=lumps; ofs+=n, lp=lp->l){
- n = lp->f->length;
- PBIT32(p, ofs);
- p += 4;
- PBIT32(p, n);
- p += 4;
- memcpy(p, lp->name, 8), p += 8;
- }
- dirty = 0;
-}
-
-void
-fsread(Req *r)
-{
- vlong n, ofs, end;
- File *f;
- Lump *l;
-
- f = r->fid->file;
- l = f->aux;
- ofs = r->ifcall.offset + l->ofs;
- end = l->ofs + f->length;
- n = r->ifcall.count;
- if(ofs + n >= end)
- n = end - ofs;
- if(n <= 0){
- r->ofcall.count = 0;
- respond(r, nil);
- return;
- }
- if(f == fwad && dirty)
- makewad();
- if(l->buf != nil)
- memcpy(r->ofcall.data, l->buf+ofs, n);
- else{
- Bseek(wad, ofs, 0);
- n = Bread(wad, r->ofcall.data, n);
- if(n < 0){
- responderror(r);
- return;
- }
- }
- accessfile(f, AREAD);
- r->ofcall.count = n;
- respond(r, nil);
-}
-
-int
-addlump(Lump *l, File *dir)
-{
- Lump *lp;
-
- lp = lumps->lp;
- if(dir != fs.tree->root){
- lp = dir->aux;
- lp = lp->type == LTmap ? sortmap(lp, l) : lastlump(lp);
- }
- if(l->type == LTend && lp->l->type == LTend && lp->l->f->parent == dir){
- werrstr("an end marker already exists");
- return -1;
- }
- link(l, lp, 0);
- if(l->type == LTmrk){
- strcat(l->name, "_START");
- if(endldir(l, l) < 0)
- return -1;
- }else if(l->type == LTreg){
- l->buf = emalloc9p(Nbuf);
- l->nbuf = Nbuf;
- }
- dirty = 1;
- return 0;
-}
-
-Lump *
-createlump(char *s, File *dir, int ismark)
-{
- int type;
- Lump *l;
-
- if(!validname(s, dir, &type, 1, ismark))
- return nil;
- l = emalloc9p(sizeof *l);
- l->type = type;
- strupr(l->name, s);
- return l;
-}
-
-void
-fscreate(Req *r)
-{
- int p;
- File *f;
- Lump *l;
-
- f = r->fid->file;
- p = r->ifcall.perm;
- if(p & DMDIR)
- p = p & ~0777 | p & f->mode & 0777;
- else
- p = p & ~0666 | p & f->mode & 0666;
- l = createlump(r->ifcall.name, f, p & DMDIR);
- if(l == nil)
- goto err;
- f = createfile(f, r->ifcall.name, r->fid->uid, p, l);
- if(f == nil){
- free(l);
- goto err;
- }
- l->f = f;
- if(addlump(l, r->fid->file) < 0){
- removefile(f);
- goto err;
- }
- r->fid->file = f;
- r->ofcall.qid = f->qid;
- respond(r, nil);
- return;
-err:
- responderror(r);
-}
-
-void
-fsopen(Req *r)
-{
- File *f;
-
- f = r->fid->file;
- if((f->mode & DMAPPEND) == 0 && (r->ifcall.mode & OTRUNC) != 0
- && f != fsig){
- fwad->length -= f->length;
- f->length = 0;
- dirty = 1;
- }
- respond(r, nil);
-}
-
-void
-fsdestroyfile(File *f)
-{
- freelump(f->aux);
-}
-
-Srv fs = {
- .open = fsopen,
- .create = fscreate,
- .read = fsread,
- .write = fswrite,
- .remove = fsremove,
- .wstat = fswstat
-};
-
-int
-get32(Biobuf *bf, u32int *v)
-{
- int n;
- uchar u[4];
-
- n = Bread(bf, u, sizeof u);
- if(n != sizeof u)
- return -1;
- *v = GBIT32(u);
- return 0;
-}
-
-File *
-replacefile(File *dir, char *fname, int mode, Lump *l)
-{
- File *f;
-
- incref(dir);
- f = walkfile(dir, fname);
- if(f == nil)
- return nil;
- if(removefile(f) < 0)
- return nil;
- f = createfile(dir, fname, nil, mode, l);
- return f;
-}
-
-void
-addsigfile(char *sig)
-{
- int n;
- Lump *l;
- File *f;
-
- n = strlen(sig) + 1;
- l = emalloc9p(sizeof *l);
- l->buf = (uchar *)estrdup9p(sig);
- l->buf[n-1] = '\n';
- f = createfile(fs.tree->root, "SIG", nil, rdonly ? 0444 : 0666, l);
- if(f == nil)
- sysfatal("addsigfile: %r");
- else{
- fsig = f;
- f->length = n;
- }
-}
-
-void
-addwadfile(void)
-{
- Lump *l;
- File *f;
-
- l = emalloc9p(sizeof *l);
- f = createfile(fs.tree->root, "WAD", nil, 0444, l);
- if(f == nil)
- sysfatal("addwadfile: %r");
- else{
- fwad = f;
- f->length = Nhdr;
- }
- dirty++;
-
-}
-
-void
-checkends(void)
-{
- Lump *lp;
-
- if(ldir == fs.tree->root)
- return;
- lp = ldir->aux;
- if(lp->type != LTmap && endldir(lp, lastlump(lp)) < 0)
- fprint(2, "checkends: %r\n");
- ldir = ldir->parent;
- checkends();
-}
-
-int
-addfile(Lump *l, u32int *len, int mode)
-{
- int err;
- char fname[sizeof l->name], *s;
- Lump *lp;
- File *f;
-
- *len = 0;
- if(get32(wad, &l->ofs) < 0 || get32(wad, len) < 0)
- return -1;
- if(Bread(wad, l->name, sizeof(l->name)-1) != sizeof(l->name)-1)
- return -1;
- strlwr(fname, l->name);
-
- lp = ldir->aux;
- err = !validname(fname, ldir, &l->type, 0, 0);
- switch(l->type){
- case LTmap:
- closefile(ldir);
- ldir = fs.tree->root;
- if(err && lp != nil && lp->type != LTmap){
- fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, *len);
- if(endldir(lp, lastlump(lp)) < 0)
- fprint(2, "endldir: %r\n");
- }
- mode |= DMDIR|0111;
- *len = 0;
- break;
- case LTmrk:
- if(err){
- if(lp != nil && lp->type == LTmap){
- closefile(ldir);
- ldir = fs.tree->root;
- }else{
- fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, *len);
- if(endldir(lp, lastlump(lp)) < 0)
- return -1;
- ldir = ldir->parent;
- }
- }
- s = strrchr(fname, '_');
- *s = 0;
- mode |= DMDIR|0111;
- *len = 0;
- break;
- case LTend:
- if(err){
- ldir = ldir->parent;
- return -1;
- }
- *len = 0;
- break;
- case LTreg:
- if(err){
- if(ismaplump(fname))
- fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, *len);
- else
- ldir = fs.tree->root;
- }
- break;
- default:
- return -1;
- }
-
- f = createfile(ldir, fname, nil, mode, l);
- if(f == nil){
- fprint(2, "createfile %s: %r\n", l->name);
- if(mode & DMDIR)
- return -1;
- f = replacefile(ldir, fname, mode, l);
- if(f == nil)
- return -1;
- }
- if(mode & DMDIR)
- ldir = f;
- else if(l->type == LTend)
- ldir = ldir->parent;
- else
- closefile(f);
- f->length = *len;
- l->f = f;
- return 0;
-}
-
-void
-parsewad(void)
-{
- int n, ne, mode;
- u32int len;
- Lump *l;
-
- mode = rdonly ? 0444 : 0666;
- ldir = fs.tree->root;
- for(n=0, ne=nlmp, nlmp=0; n<ne; n++){
- l = emalloc9p(sizeof *l);
- if(addfile(l, &len, mode) < 0){
- fprint(2, "addfile %s ofs=%#ux len=%#ux: %r\n", l->name, l->ofs, len);
- free(l);
- continue;
- }
- link(l, lumps->lp, len);
- }
- checkends();
-}
-
-void
-wadinfo(char *sig)
-{
- int n;
- u32int dictofs;
-
- n = Bread(wad, sig, Nsig);
- if(n != Nsig)
- sysfatal("readwad: short read: %r");
- sig[4] = 0;
- if(strcmp(sig, "IWAD") != 0 && strcmp(sig, "PWAD") != 0)
- sysfatal("invalid wad signature");
- if(get32(wad, &nlmp) < 0 || get32(wad, &dictofs) < 0)
- sysfatal("wadinfo: %r");
- Bseek(wad, dictofs, 0);
-}
-
-void
-usage(void)
-{
- fprint(2, "usage: %s [-Dr] [-m mtpt] [-S srvname] [wad]\n", argv0);
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int fl, p;
- char *mtpt, *srvname, sig[Nsig+1] = "PWAD";
-
- mtpt = "/mnt/wad";
- srvname = nil;
- fl = MREPL|MCREATE;
- p = DMDIR|0777;
- ARGBEGIN{
- case 'D': chatty9p++; break;
- case 'S': srvname = EARGF(usage()); break;
- case 'm': mtpt = EARGF(usage()); break;
- case 'r': rdonly++; p &= ~0222; fl &= ~MCREATE; break;
- default: usage();
- }ARGEND
- if(*argv != nil){
- wad = Bopen(*argv, OREAD);
- if(wad == nil)
- sysfatal("Bopen: %r");
- wadinfo(sig);
- }
- fs.tree = alloctree(nil, nil, p, fsdestroyfile);
- addsigfile(sig);
- addwadfile();
- parsewad();
- postmountsrv(&fs, srvname, mtpt, fl);
- exits(nil);
-}