package main import ( "fmt" "os" "path/filepath" "strings" "strconv" "github.com/alexflint/go-arg" "git.zorchenhimer.com/zorchenhimer/go-fds" ) type Arguments struct { Input string `arg:"positional,required"` // for getting a specific file Side int `arg:"--side" default:"-1"` FileNum int `arg:"--file-num" default:"-1"` Range string `arg:"--range"` } func main() { args := &Arguments{} arg.MustParse(args) err := run(args) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func run(args *Arguments) error { rom, err := fds.ReadRomFile(args.Input) if err != nil { return err } outdir := strings.TrimSuffix(args.Input, filepath.Ext(args.Input)) err = os.MkdirAll(outdir, 0775) if err != nil { return err } if args.Side >= 0 && args.FileNum == -1 { if args.Side >= len(rom.Sides) { return fmt.Errorf("--side out of range") } num := 0 for _, s := range rom.Sides[:args.Side] { num += len(s.Files) } side := rom.Sides[args.Side] sideName := fmt.Sprintf("Side%d", side.Header.PhysicalSide) for _, file := range side.Files { fileName := filepath.Join(outdir, fmt.Sprintf("%03d_%s_%02d_%02X", num, sideName, file.Number, file.Id)) err := os.WriteFile(fileName, file.Data, 0664) if err != nil { return err } num++ } return nil } else if args.Side >= 0 && args.FileNum >= 0 { if args.Side >= len(rom.Sides) { return fmt.Errorf("--side out of range") } side := rom.Sides[args.Side] if len(side.Files) <= args.FileNum { return fmt.Errorf("--file-num out of range; %d", len(side.Files)) } sideName := fmt.Sprintf("Side%d", side.Header.PhysicalSide) file := side.Files[args.FileNum] var start int var end int if args.Range != "" { start, end, err = parseRange(args.Range) if err != nil { return err } fmt.Printf("start: %04X\nend: %04X\n", start, end) start = start - int(file.Address) end = end - int(file.Address) fmt.Printf("start: %04X\nend: %04X\n", start, end) } else { start = 0 end = file.Size } fileName := filepath.Join(outdir, fmt.Sprintf("%03d_%s_%02d_%02X", args.FileNum, sideName, file.Number, file.Id)) fmt.Println("fileName:", fileName) err := os.WriteFile(fileName, file.Data[start:end], 0664) if err != nil { return err } return nil } else if args.Range != "" && (args.Side < 0 || args.FileNum < 0) { return fmt.Errorf("--range cannot be given alone") } num := 0 for _, side := range rom.Sides { sideName := fmt.Sprintf("Side%d", side.Header.PhysicalSide) for _, file := range side.Files { fileName := filepath.Join(outdir, fmt.Sprintf("%03d_%s_%02d_%02X", args.FileNum, sideName, file.Number, file.Id)) err := os.WriteFile(fileName, file.Data, 0664) if err != nil { return err } num++ } } return nil } // $6000-$5000 func parseRange(input string) (int, int, error) { splits := strings.Split(input, "-") if len(splits) != 2 { return 0, 0, fmt.Errorf("invalid range: %q", input) } fmt.Println("splits:", splits) splits[0] = strings.Replace(splits[0], "$", "0x", 1) splits[1] = strings.Replace(splits[1], "$", "0x", 1) fmt.Println("splits:", splits) start, err := strconv.ParseInt(splits[0], 0, 64) if err != nil { return 0, 0, fmt.Errorf("invalid range: %q", input) } end, err := strconv.ParseInt(splits[1], 0, 64) if err != nil { return 0, 0, fmt.Errorf("invalid range: %q", input) } return int(start), int(end), nil }