diff --git a/Makefile b/Makefile index d99053a..f074beb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ CMDS= \ - bin/fdslist + bin/fdslist \ + bin/fdsextract all: bin $(CMDS) diff --git a/cmd/fdsextract.go b/cmd/fdsextract.go new file mode 100644 index 0000000..fdc32b8 --- /dev/null +++ b/cmd/fdsextract.go @@ -0,0 +1,155 @@ +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 +}