diff --git a/.gitignore b/.gitignore index 892f00f..39e31f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +opt/ # If you prefer the allow list template instead of the deny list, see community template: # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore # diff --git a/converter/converter.go b/converter/converter.go index af2b5b0..f0947ab 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -113,19 +113,43 @@ func IntelHexToBin(inputFile string, outputFile string) error { return fmt.Errorf("no data segments found in Intel HEX file") } + // Find the lowest and highest addresses + minAddr := segments[0].Address + maxAddr := segments[0].Address + uint32(len(segments[0].Data)) + for _, segment := range segments { + if segment.Address < minAddr { + minAddr = segment.Address + } + endAddr := segment.Address + uint32(len(segment.Data)) + if endAddr > maxAddr { + maxAddr = endAddr + } + } + + // Create a buffer filled with 0xFF + totalLen := maxAddr - minAddr + binData := make([]byte, totalLen) + for i := range binData { + binData[i] = 0xFF + } + + // Copy each segment's data into the buffer + for _, segment := range segments { + start := segment.Address - minAddr + copy(binData[start:start+uint32(len(segment.Data))], segment.Data) + } + // Create output file - ofw, err := os.Create(outputFile) + of, err := os.Create(outputFile) if err != nil { return fmt.Errorf("error creating output file: %w", err) } - defer ofw.Close() + defer of.Close() - // Write binary data in order of addresses - for _, segment := range segments { - _, err = ofw.Write(segment.Data) - if err != nil { - return fmt.Errorf("error writing binary data: %v", err) - } + // Write the buffer to the file + _, err = of.Write(binData) + if err != nil { + return fmt.Errorf("error writing binary data: %v", err) } return nil diff --git a/hex2bin b/hex2bin new file mode 100755 index 0000000..bea23c8 Binary files /dev/null and b/hex2bin differ diff --git a/main.go b/main.go index 65fc00d..4c14310 100644 --- a/main.go +++ b/main.go @@ -14,8 +14,8 @@ var ( buildTime = "unknown" ) -// getOutputFileName determines the output file name based on input file and mode -func getOutputFileName(inputFile, mode string) (string, error) { +// GetOutputFileName determines the output file name based on input file and mode +func GetOutputFileName(inputFile, mode string) (string, error) { ext := "" switch mode { case "bin2hex": @@ -26,7 +26,22 @@ func getOutputFileName(inputFile, mode string) (string, error) { return "", fmt.Errorf("cannot determine output file extension for mode '%s' (should be 'bin2hex' or 'hex2bin')", mode) } base := strings.TrimSuffix(inputFile, filepath.Ext(inputFile)) - return base + ext, nil + output := base + ext + + // Add suffix if file exists + if _, err := os.Stat(output); err == nil { + suffix := 1 + for { + candidate := fmt.Sprintf("%s_%d%s", base, suffix, ext) + if _, err := os.Stat(candidate); os.IsNotExist(err) { + output = candidate + break + } + suffix++ + } + } + + return output, nil } // getModeFromInputExt tries to determine the mode from the input file extension @@ -64,7 +79,7 @@ func main() { if arg == "bin2hex" || arg == "hex2bin" { mode = arg var err error - outputFile, err = getOutputFileName(inputFile, mode) + outputFile, err = GetOutputFileName(inputFile, mode) if err != nil { fmt.Printf("Error: %v\n", err) os.Exit(1) @@ -86,7 +101,7 @@ func main() { fmt.Printf("Error: %v\n", err) os.Exit(1) } - outputFile, err = getOutputFileName(inputFile, mode) + outputFile, err = GetOutputFileName(inputFile, mode) if err != nil { fmt.Printf("Error: %v\n", err) os.Exit(1) diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..7436152 --- /dev/null +++ b/main_test.go @@ -0,0 +1,50 @@ +package main + +import ( + "os" + "path/filepath" + "testing" +) + +func TestGetOutputFileName_NoConflict(t *testing.T) { + dir := t.TempDir() + input := filepath.Join(dir, "file.hex") + os.WriteFile(input, []byte("dummy"), 0644) + name, err := GetOutputFileName(input, "hex2bin") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if filepath.Base(name) != "file.bin" { + t.Errorf("expected file.bin, got %s", filepath.Base(name)) + } +} + +func TestGetOutputFileName_OneConflict(t *testing.T) { + dir := t.TempDir() + input := filepath.Join(dir, "file.hex") + os.WriteFile(input, []byte("dummy"), 0644) + os.WriteFile(filepath.Join(dir, "file.bin"), []byte("bin"), 0644) + name, err := GetOutputFileName(input, "hex2bin") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if filepath.Base(name) != "file_1.bin" { + t.Errorf("expected file_1.bin, got %s", filepath.Base(name)) + } +} + +func TestGetOutputFileName_MultipleConflicts(t *testing.T) { + dir := t.TempDir() + input := filepath.Join(dir, "file.hex") + os.WriteFile(input, []byte("dummy"), 0644) + os.WriteFile(filepath.Join(dir, "file.bin"), []byte("bin"), 0644) + os.WriteFile(filepath.Join(dir, "file_1.bin"), []byte("bin1"), 0644) + os.WriteFile(filepath.Join(dir, "file_2.bin"), []byte("bin2"), 0644) + name, err := GetOutputFileName(input, "hex2bin") + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if filepath.Base(name) != "file_3.bin" { + t.Errorf("expected file_3.bin, got %s", filepath.Base(name)) + } +}