diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/riff.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/lib/riff.b')
| -rw-r--r-- | appl/lib/riff.b | 225 |
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]; +} |
