// Extrahieren der "Rohen" Lump-Bytes einer WAD-Datei // siehe def Lumps: https://doomwiki.org/wiki/Lump package wad import ( "encoding/binary" "fmt" "io" "os" "strings" ) type header struct { Ident [4]byte // "IWAD" or "PWAD" NumLumps int32 DirOffset int32 } type DirEntry struct { FilePos int32 Size int32 Name8 [8]byte } func (d DirEntry) Name() string { return trimName(d.Name8) } type Wad struct { f *os.File dir []DirEntry fsize int64 isIWAD bool isPWAD bool path string } // Öffnen der WAD und checks func Open(path string) (*Wad, error) { f, err := os.Open(path) if err != nil { return nil, fmt.Errorf("open wad: %w", err) } st, err := f.Stat() if err != nil { _ = f.Close() return nil, fmt.Errorf("stat wad: %w", err) } var hdr header if err := binary.Read(f, binary.LittleEndian, &hdr); err != nil { _ = f.Close() return nil, fmt.Errorf("read header: %w", err) } id := string(hdr.Ident[:]) if id != "IWAD" && id != "PWAD" { _ = f.Close() return nil, fmt.Errorf("not a WAD file (ident=%q)", id) } if hdr.DirOffset < 0 || int64(hdr.DirOffset) > st.Size() { _ = f.Close() return nil, fmt.Errorf("bad directory offset: %d", hdr.DirOffset) } if _, err := f.Seek(int64(hdr.DirOffset), io.SeekStart); err != nil { _ = f.Close() return nil, fmt.Errorf("seek directory: %w", err) } if hdr.NumLumps < 0 || hdr.NumLumps > 1<<20 { _ = f.Close() return nil, fmt.Errorf("unreasonable lump count: %d", hdr.NumLumps) } dir := make([]DirEntry, hdr.NumLumps) if err := binary.Read(f, binary.LittleEndian, &dir); err != nil { _ = f.Close() return nil, fmt.Errorf("read directory: %w", err) } for i, d := range dir { if d.FilePos < 0 || d.Size < 0 { _ = f.Close() return nil, fmt.Errorf("dir[%d]: negative pos/size", i) } end := int64(d.FilePos) + int64(d.Size) if end < 0 || end > st.Size() { _ = f.Close() return nil, fmt.Errorf("dir[%d:%s]: out of file bounds", i, trimName(d.Name8)) } } w := &Wad{ f: f, dir: dir, fsize: st.Size(), isIWAD: id == "IWAD", isPWAD: id == "PWAD", path: path, } return w, nil } // WAD Closing func (w *Wad) Close() error { if w == nil || w.f == nil { return nil } err := w.f.Close() w.f = nil return err } func (w *Wad) Dir() []DirEntry { return w.dir } // Lessen der Lump roh Bytes func (w *Wad) ReadLump(i int) (name string, data []byte, err error) { if i < 0 || i >= len(w.dir) { return "", nil, fmt.Errorf("lump index out of range: %d", i) } de := w.dir[i] name = trimName(de.Name8) if _, err := w.f.Seek(int64(de.FilePos), io.SeekStart); err != nil { return name, nil, fmt.Errorf("seek %s: %w", name, err) } buf := make([]byte, de.Size) _, err = io.ReadFull(w.f, buf) if err != nil { return name, nil, fmt.Errorf("read %s: %w", name, err) } return name, buf, nil } // Extrahieren der Lump Namen aus den rohen Bytes func (w *Wad) ReadLumpByName(name string) ([]byte, int, error) { want := strings.ToUpper(name) for i, d := range w.dir { if trimName(d.Name8) == want { _, b, err := w.ReadLump(i) return b, i, err } } return nil, -1, fmt.Errorf("lump %q not found", want) } // Finden der Map-Marker(start und ende) in der WAD func (w *Wad) FindMap(marker string) (start, end int, err error) { m := strings.ToUpper(marker) start = -1 for i, d := range w.dir { if d.Size == 0 && trimName(d.Name8) == m { start = i break } } if start < 0 { return -1, -1, fmt.Errorf("map marker %q not found", m) } end = len(w.dir) for i := start + 1; i < len(w.dir); i++ { if w.dir[i].Size == 0 { end = i break } } return start, end, nil } // Laden der Map Lumps func (w *Wad) LoadMapLumps(marker string, names ...string) (map[string][]byte, error) { start, end, err := w.FindMap(marker) if err != nil { return nil, err } want := make(map[string]struct{}, len(names)) for _, n := range names { want[strings.ToUpper(n)] = struct{}{} } out := make(map[string][]byte, len(names)) for i := start + 1; i < end; i++ { n := trimName(w.dir[i].Name8) if _, ok := want[n]; !ok { continue } _, b, err := w.ReadLump(i) if err != nil { return nil, err } out[n] = b if len(out) == len(want) { break } } missing := make([]string, 0) for n := range want { if _, ok := out[n]; !ok { missing = append(missing, n) } } if len(missing) > 0 { return nil, fmt.Errorf("map %s: missing lumps: %v", strings.ToUpper(marker), missing) } return out, nil } func trimName(n8 [8]byte) string { n := string(n8[:]) if i := strings.IndexByte(n, 0); i >= 0 { n = n[:i] } return strings.ToUpper(strings.TrimSpace(n)) }