// zipx.go — Five-native ZIP container access (FV_ZIPENTRIES / FV_ZIPREAD). // // Reads an in-memory ZIP archive. No filesystem path — callers that // downloaded the ZIP via FV_HTTPGET hand the raw bytes here directly, // which is exactly the DART corpCode flow. package hbrtl import ( "archive/zip" "bytes" "io" "five/hbrt" ) // FV_ZIPENTRIES(cZipBytes) -> [ { name, size }, ... ] // Returns an empty array if the input isn't a valid ZIP. func FvZipEntries(t *hbrt.Thread) { t.Frame(1, 0) defer t.EndProc() data := []byte(t.Local(1).AsString()) zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) if err != nil { t.RetVal(hbrt.MakeArrayFrom(nil)) return } items := make([]hbrt.Value, 0, len(zr.File)) for _, f := range zr.File { row := &hbrt.HbHash{} row.Append(hbrt.MakeString("name"), hbrt.MakeString(f.Name)) row.Append(hbrt.MakeString("size"), hbrt.MakeInt(int(f.UncompressedSize64))) items = append(items, hbrt.MakeHashFrom(row)) } t.RetVal(hbrt.MakeArrayFrom(items)) } // FV_ZIPREAD(cZipBytes, cEntryName) -> cContents // Returns "" if the ZIP is invalid or the entry isn't present. func FvZipRead(t *hbrt.Thread) { t.Frame(2, 0) defer t.EndProc() data := []byte(t.Local(1).AsString()) name := t.Local(2).AsString() zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) if err != nil { t.RetString("") return } for _, f := range zr.File { if f.Name != name { continue } rc, err := f.Open() if err != nil { t.RetString("") return } buf, err := io.ReadAll(rc) rc.Close() if err != nil { t.RetString("") return } t.RetVal(hbrt.MakeStringBytes(buf)) return } t.RetString("") }