diff --git a/cmd/convert.go b/cmd/convert.go new file mode 100644 index 0000000..cc0f744 --- /dev/null +++ b/cmd/convert.go @@ -0,0 +1,51 @@ +package cmd + +import ( + "errors" + "fmt" + "os" + "path" + "strings" + + "github.com/mroach/n64-go/rom" + "github.com/spf13/cobra" +) + +func init() { + var overwrite bool + var convertCmd = &cobra.Command{ + Use: "convert", + Short: "Converts a ROM to native Big-Endian Z64 format", + Args: cobra.MinimumNArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + inpath := args[0] + dirname, filename := path.Split(inpath) + baseFilename := basename(filename) + outFilename := baseFilename + ".z64" + outpath := path.Join(dirname, outFilename) + + if !overwrite { + if _, err := os.Stat(outpath); err == nil { + return errors.New(outpath + " already exists") + } + } + + if err := rom.ConvertRomFormat(inpath, outpath); err != nil { + return err + } + + fmt.Println(inpath, "=>", outpath) + return nil + }, + } + + convertCmd.Flags().BoolVarP(&overwrite, "force", "f", false, "Overwrite destination file if it exists") + rootCmd.AddCommand(convertCmd) +} + +func basename(filename string) string { + if pos := strings.LastIndexByte(filename, '.'); pos != -1 { + return filename[:pos] + } + return filename +} diff --git a/rom/convert.go b/rom/convert.go new file mode 100644 index 0000000..47e998b --- /dev/null +++ b/rom/convert.go @@ -0,0 +1,77 @@ +package rom + +import ( + "errors" + "io" + "os" +) + +func ConvertRomFormat(inpath string, outpath string) error { + const bufferSize = 2048 + + info, err := FromPath(inpath) + if err != nil { + return err + } + + if info.File.Format == "z64" { + return errors.New("File is already in the native Z64 format") + } + + source, err := os.Open(inpath) + if err != nil { + return err + } + + dest, err := os.Create(outpath) + if err != nil { + return err + } + + for { + buf := make([]byte, bufferSize) + n, err := source.Read(buf) + if err != nil && err != io.EOF { + return err + } + if n == 0 { + break + } + + buf = maybeReverseBytes(buf, info.File.Format) + if _, err := dest.Write(buf[:n]); err != nil { + return err + } + } + + return nil +} + +func maybeReverseBytes(bytes []byte, romFormat string) []byte { + if romFormat == "v64" { + return reverseBytes(bytes, 2) + } + + if romFormat == "n64" { + return reverseBytes(bytes, 4) + } + + return bytes +} + +func reverseBytes(bytes []byte, size int) (reversed []byte) { + for _, chunk := range chunk(bytes, size) { + for i := len(chunk) - 1; i >= 0; i = i - 1 { + reversed = append(reversed, chunk[i]) + } + } + + return reversed +} + +func chunk(bytes []byte, chunkSize int) (chunks [][]byte) { + for chunkSize < len(bytes) { + bytes, chunks = bytes[chunkSize:], append(chunks, bytes[0:chunkSize:chunkSize]) + } + return append(chunks, bytes) +} diff --git a/rom/rom.go b/rom/rom.go index 1745e87..730f9d0 100644 --- a/rom/rom.go +++ b/rom/rom.go @@ -224,35 +224,6 @@ func detectRomFormat(signature []byte) (string, error) { return "", errors.New("Unknown ROM format. Invalid file?") } -func maybeReverseBytes(bytes []byte, romFormat string) []byte { - if romFormat == "v64" { - return reverseBytes(bytes, 2) - } - - if romFormat == "n64" { - return reverseBytes(bytes, 4) - } - - return bytes -} - -func reverseBytes(bytes []byte, size int) (reversed []byte) { - for _, chunk := range chunk(bytes, size) { - for i := len(chunk) - 1; i >= 0; i = i - 1 { - reversed = append(reversed, chunk[i]) - } - } - - return reversed -} - -func chunk(bytes []byte, chunkSize int) (chunks [][]byte) { - for chunkSize < len(bytes) { - bytes, chunks = bytes[chunkSize:], append(chunks, bytes[0:chunkSize:chunkSize]) - } - return append(chunks, bytes) -} - func bytesToString(bytes []byte) string { chars := []rune{}