summaryrefslogtreecommitdiff
path: root/appl/lib/riff.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/riff.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/riff.b')
-rw-r--r--appl/lib/riff.b225
1 files changed, 225 insertions, 0 deletions
diff --git a/appl/lib/riff.b b/appl/lib/riff.b
new file mode 100644
index 00000000..a746486e
--- /dev/null
+++ b/appl/lib/riff.b
@@ -0,0 +1,225 @@
+implement Riff;
+
+include "sys.m";
+
+sys: Sys;
+
+include "riff.m";
+
+init()
+{
+ sys = load Sys Sys->PATH;
+}
+
+open(file: string): (ref RD, string)
+{
+ fd := sys->open(file, sys->OREAD);
+ if(fd == nil)
+ return (nil, "open failed");
+
+ r := ref RD;
+ r.fd = fd;
+ r.buf = array[DEFBUF] of byte;
+ r.ptr = 0;
+ r.nbyte = 0;
+
+ (hdr, l) := r.gethdr();
+ if(hdr != "RIFF")
+ return (nil, "not a RIFF file");
+
+ return (r, nil);
+}
+
+RD.gethdr(r: self ref RD): (string, int)
+{
+ b := array[8] of byte;
+
+ if(r.readn(b, 8) != 8)
+ return (nil, -1);
+
+ return (string b[0:4], ledword(b, 4));
+}
+
+RD.check4(r: self ref RD, code: string): string
+{
+ b := array[4] of byte;
+
+ if(r.readn(b, 4) != 4)
+ return "file i/o error";
+ if(string b != code)
+ return "bad four code header information";
+ return nil;
+}
+
+RD.avihdr(r: self ref RD): (ref AVIhdr, string)
+{
+ (s, l) := r.gethdr();
+ if(s == nil || s != "avih")
+ return (nil, "missing/malformed avih");
+
+ b := array[AVImainhdr] of byte;
+ if(r.readn(b, AVImainhdr) != AVImainhdr)
+ return (nil, "short read in avih");
+
+ h := ref AVIhdr;
+
+ h.usecperframe = ledword(b, 0);
+ h.bytesec = ledword(b, 4);
+ h.flag = ledword(b, 12);
+ h.frames = ledword(b, 16);
+ h.initframes = ledword(b, 20);
+ h.streams = ledword(b, 24);
+ h.bufsize = ledword(b, 28);
+ h.width = ledword(b, 32);
+ h.height = ledword(b, 36);
+
+ return (h, nil);
+}
+
+RD.streaminfo(r: self ref RD): (ref AVIstream, string)
+{
+ (h, l) := r.gethdr();
+ if(h != "LIST")
+ return (nil, "streaminfo expected LIST");
+
+ err := r.check4("strl");
+ if(err != nil)
+ return (nil, err);
+
+ (strh, sl) := r.gethdr();
+ if(strh != "strh")
+ return (nil, "streaminfo expected strh");
+
+ b := array[sl] of byte;
+ if(r.readn(b, sl) != sl)
+ return (nil, "streaminfo strl short read");
+
+ s := ref AVIstream;
+
+ s.stype = string b[0:4];
+ s.handler = string b[4:8];
+ s.flags = ledword(b, 8);
+ s.priority = ledword(b, 12);
+ s.initframes = ledword(b, 16);
+ s.scale = ledword(b, 20);
+ s.rate = ledword(b, 24);
+ s.start = ledword(b, 28);
+ s.length = ledword(b, 32);
+ s.bufsize = ledword(b, 36);
+ s.quality = ledword(b, 40);
+ s.samplesz = ledword(b, 44);
+
+ (strf, sf) := r.gethdr();
+ if(strf != "strf")
+ return (nil, "streaminfo expected strf");
+
+ s.fmt = array[sf] of byte;
+ if(r.readn(s.fmt, sf) != sf)
+ return (nil, "streaminfo strf short read");
+
+ return (s, nil);
+}
+
+RD.readn(r: self ref RD, b: array of byte, l: int): int
+{
+ if(r.nbyte < l) {
+ c := 0;
+ if(r.nbyte != 0) {
+ b[0:] = r.buf[r.ptr:];
+ l -= r.nbyte;
+ c += r.nbyte;
+ b = b[r.nbyte:];
+ }
+ bsize := len r.buf;
+ while(l != 0) {
+ r.nbyte = sys->read(r.fd, r.buf, bsize);
+ if(r.nbyte <= 0) {
+ r.nbyte = 0;
+ return -1;
+ }
+ n := l;
+ if(n > bsize)
+ n = bsize;
+
+ r.ptr = 0;
+ b[0:] = r.buf[0:n];
+ b = b[n:];
+ r.nbyte -= n;
+ r.ptr += n;
+ l -= n;
+ c += n;
+ }
+ return c;
+ }
+ b[0:] = r.buf[r.ptr:r.ptr+l];
+ r.nbyte -= l;
+ r.ptr += l;
+ return l;
+}
+
+RD.skip(r: self ref RD, size: int): int
+{
+ if(r.nbyte != 0) {
+ n := size;
+ if(n > r.nbyte)
+ n = r.nbyte;
+ r.ptr += n;
+ r.nbyte -= n;
+ size -= n;
+ if(size == 0)
+ return 0;
+ }
+ return int sys->seek(r.fd, big size, sys->SEEKRELA);
+}
+
+AVIstream.fmt2binfo(a: self ref AVIstream): string
+{
+ if(len a.fmt < Binfosize)
+ return "format is wrong size for BITMAPINFO";
+
+ b := ref Bitmapinfo;
+
+ # Pull out the bitmap info
+ b.width = ledword(a.fmt, 4);
+ b.height = ledword(a.fmt, 8);
+ b.planes = leword(a.fmt, 12);
+ b.bitcount = leword(a.fmt, 14);
+ b.compression = ledword(a.fmt, 16);
+ b.sizeimage = ledword(a.fmt, 20);
+ b.xpelpermeter = ledword(a.fmt, 24);
+ b.ypelpermeter = ledword(a.fmt, 28);
+ b.clrused = ledword(a.fmt, 32);
+ b.clrimportant = ledword(a.fmt, 36);
+
+ # Parse out the color map
+ ncolor := len a.fmt - Binfosize;
+ if(ncolor & 3)
+ return "wrong size color map";
+ ncolor /= 4;
+
+ b.cmap = array[ncolor] of RGB;
+ idx := 40;
+ for(i := 0; i < ncolor; i++) {
+ b.cmap[i].r = int a.fmt[idx+2];
+ b.cmap[i].g = int a.fmt[idx+1];
+ b.cmap[i].b = int a.fmt[idx+0];
+ idx += 4;
+ }
+
+ a.fmt = nil;
+ a.binfo = b;
+ return nil;
+}
+
+leword(b: array of byte, o: int): int
+{
+ return (int b[o+1] << 8) | int b[o];
+}
+
+ledword(b: array of byte, o: int): int
+{
+ return (int b[o+3] << 24) |
+ (int b[o+2] << 16) |
+ (int b[o+1] << 8) |
+ int b[o];
+}