Skip to content

Commit

Permalink
cmd/list: Implement list command
Browse files Browse the repository at this point in the history
  • Loading branch information
pg9182 committed Apr 14, 2024
1 parent ffedb5e commit 21d6c45
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
_ "github.com/pg9182/tf2vpk/cmd/chflg"
_ "github.com/pg9182/tf2vpk/cmd/filter"
_ "github.com/pg9182/tf2vpk/cmd/init"
_ "github.com/pg9182/tf2vpk/cmd/list"
_ "github.com/pg9182/tf2vpk/cmd/lzham"
_ "github.com/pg9182/tf2vpk/cmd/tarzip"
_ "github.com/pg9182/tf2vpk/cmd/verify"
Expand Down
145 changes: 145 additions & 0 deletions cmd/list/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package ls

import (
"fmt"
"io"
"os"
"strings"

"github.com/pg9182/tf2vpk"
"github.com/pg9182/tf2vpk/cmd/root"
"github.com/pg9182/tf2vpk/internal"
"github.com/spf13/cobra"
)

var Flags struct {
VPK tf2vpk.ValvePakRef
HumanReadable bool
HumanReadableFlags bool
Long bool
Test bool
IncludeExclude func(tf2vpk.ValvePakFile) (bool, error)
}

var Command = &cobra.Command{
GroupID: root.GroupVPKRead.ID,
Use: "list vpk_path",
Short: "Lists the contents of a VPK",
Args: cobra.ExactArgs(1),
Aliases: []string{"ls"},
Run: func(cmd *cobra.Command, args []string) {
main()
},
}

func init() {
Command.Flags().Bool("help", false, "help for "+Command.Name()) // prevent the default short help flag from being set
Command.Flags().BoolVarP(&Flags.HumanReadable, "human-readable", "h", false, "Show values in human-readable form")
Command.Flags().BoolVarP(&Flags.HumanReadableFlags, "human-readable-flags", "f", false, "If displaying flags, also show them in human-readable form at the very end of the line (delimited by a #)")
Command.Flags().BoolVarP(&Flags.Long, "long", "l", false, "Show detailed file metadata (adds the following columns to the beginning: block_index load_flags[binary] texture_flags[binary] crc32[hex] compressed_size[bytes] uncompressed_size[bytes] compressed_percent)")
Command.Flags().BoolVarP(&Flags.Test, "test", "t", false, "Also attempt to read contents and compute checksums (adds a column with OK/ERR to the end)")
root.FlagIncludeExclude(&Flags.IncludeExclude, Command, true)
root.ArgVPK(&Flags.VPK, Command, -1, false, false, false)
root.Command.AddCommand(Command)
}

func main() {
r, err := tf2vpk.NewReader(Flags.VPK)
if err != nil {
fmt.Fprintf(os.Stderr, "error: open vpk: %v\n", err)
os.Exit(1)
}

var pathLen int
for _, f := range r.Root.File {
pathLen = max(pathLen, min(len(f.Path), 64))
}

var testErrCount int
for _, f := range r.Root.File {
if skip, err := Flags.IncludeExclude(f); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
} else if skip {
continue
}

load, err := f.LoadFlags()
if err != nil {
fmt.Fprintf(os.Stderr, "warning: entry %q: compute load flags: %v\n", f.Path, err)
load = 0
load--
}
texture, err := f.TextureFlags()
if err != nil {
fmt.Fprintf(os.Stderr, "warning: entry %q: compute texture flags: %v\n", f.Path, err)
load = 0
load--
}

var compressed, uncompressed uint64
for _, c := range f.Chunk {
compressed += c.CompressedSize
uncompressed += c.UncompressedSize
}

if Flags.Long {
if Flags.HumanReadable {
fmt.Printf("%s %032b %016b %08X %6.2f %% %9s %9s ", f.Index, load, texture, f.CRC32, float64(compressed)/float64(uncompressed)*100, formatBytesSIAligned(int64(compressed)), formatBytesSIAligned(int64(uncompressed)))
} else {
fmt.Printf("%s %032b %016b %08X %6.2f %% %9d %9d ", f.Index, load, texture, f.CRC32, float64(compressed)/float64(uncompressed)*100, compressed, uncompressed)
}
}
if Flags.Test || (Flags.Long && Flags.HumanReadableFlags) {
fmt.Printf("%*s", -pathLen, f.Path)
} else {
fmt.Printf("%s", f.Path)
}
if Flags.Test {
os.Stdout.Sync()
}

var testErr error
if Flags.Test {
if fr, err := r.OpenFileParallel(f, root.Flags.Threads); err != nil {
testErr = err
} else if _, err = io.Copy(io.Discard, fr); err != nil {
testErr = err
}
if testErr != nil {
testErrCount++
}
}

if Flags.Test {
if testErr != nil {
fmt.Printf(" ERR")
} else {
fmt.Printf(" OK")
}
}
if Flags.Long && Flags.HumanReadableFlags {
fmt.Printf(" # load=%s texture=%s", tf2vpk.DescribeLoadFlags(load), tf2vpk.DescribeTextureFlags(texture))
}
fmt.Printf("\n")

if Flags.Test && testErr != nil {
fmt.Fprintf(os.Stderr, "warning: entry %q: test: %v\n", f.Path, testErr)
}
}
if Flags.Test {
fmt.Fprintf(os.Stderr, "%d/%d files valid", testErrCount, len(r.Root.File))
if testErrCount != 0 {
os.Exit(1)
}
}
}

func formatBytesSIAligned(b int64) string {
s := internal.FormatBytesSI(b)
s, isB := strings.CutSuffix(s, " B")
if isB {
s += " B"
}
return s
}

0 comments on commit 21d6c45

Please sign in to comment.