Skip to content

Commit 90db537

Browse files
Add makefile + better units in output
1 parent f8513fe commit 90db537

6 files changed

Lines changed: 92 additions & 5 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ test/
33

44
# Binary
55
steg-go
6+
dist/
67

78
# IDE
89
.vscode/

Makefile

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
BINARY_NAME := steg-go
2+
DIST_DIR := dist
3+
VERSION ?= dev
4+
5+
GO := go
6+
GOFLAGS := -trimpath
7+
LDFLAGS := -s -w
8+
9+
.PHONY: all build build-linux build-macos build-windows build-wasm build-all clean
10+
11+
all: build-all
12+
13+
build: ## Build for the current platform
14+
$(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(BINARY_NAME) .
15+
16+
build-linux: ## Build static Linux binary (amd64)
17+
mkdir -p $(DIST_DIR)
18+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(DIST_DIR)/$(BINARY_NAME)-linux-amd64 .
19+
20+
build-macos: ## Build macOS binary (amd64 + arm64)
21+
mkdir -p $(DIST_DIR)
22+
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(DIST_DIR)/$(BINARY_NAME)-darwin-amd64 .
23+
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(DIST_DIR)/$(BINARY_NAME)-darwin-arm64 .
24+
25+
build-windows: ## Build Windows binary (amd64)
26+
mkdir -p $(DIST_DIR)
27+
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(DIST_DIR)/$(BINARY_NAME)-windows-amd64.exe .
28+
29+
build-wasm: ## Build WebAssembly binary (js/wasm)
30+
mkdir -p $(DIST_DIR)
31+
GOOS=js GOARCH=wasm $(GO) build $(GOFLAGS) -ldflags "$(LDFLAGS)" -o $(DIST_DIR)/$(BINARY_NAME)-js-wasm.wasm .
32+
33+
build-all: build-linux build-macos build-windows build-wasm ## Build all target platforms
34+
35+
clean: ## Remove build artifacts
36+
rm -rf $(DIST_DIR)
37+
rm -f $(BINARY_NAME)

main.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ func main() {
6161
os.Exit(0)
6262
}
6363

64+
fmt.Printf("Decoded hidden payload: %s\n", stego.FormatBytes(uint64(len(data))))
65+
6466
err = stego.ExtractTarGz(data, output)
6567
if err != nil {
6668
fmt.Fprintf(os.Stderr, "Error extracting archive: %v\n", err)
@@ -82,7 +84,7 @@ func main() {
8284
fmt.Fprintf(os.Stderr, "Error creating archive: %v\n", err)
8385
os.Exit(1)
8486
}
85-
fmt.Printf("Created archive with preserved directory structure\n")
87+
fmt.Printf("Created archive with preserved directory structure: %s\n", stego.FormatBytes(uint64(len(archiveData))))
8688
}
8789

8890
// Encode data into image using LSB steganography

stego/archive.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ import (
1313
// CreateTarGzWithStructure creates a tar.gz archive preserving directory structure
1414
func CreateTarGzWithStructure(paths []string) ([]byte, error) {
1515
var buf bytes.Buffer
16-
gzWriter := gzip.NewWriter(&buf)
16+
gzWriter, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
17+
if err != nil {
18+
return nil, fmt.Errorf("failed to create gzip writer: %v", err)
19+
}
1720
tarWriter := tar.NewWriter(gzWriter)
1821

1922
for _, path := range paths {
@@ -34,9 +37,20 @@ func CreateTarGzWithStructure(paths []string) ([]byte, error) {
3437
if err != nil {
3538
relPath = filePath
3639
}
40+
relPath = filepath.ToSlash(relPath)
3741

3842
if info.IsDir() {
39-
// Add directory entry
43+
// Add directory headers only for empty directories.
44+
// Non-empty directories are implicitly created during extraction
45+
// from file paths and omitting them keeps the archive smaller.
46+
isEmpty, err := isDirEmpty(filePath)
47+
if err != nil {
48+
return err
49+
}
50+
if !isEmpty {
51+
return nil
52+
}
53+
4054
header := &tar.Header{
4155
Name: relPath + "/",
4256
Mode: int64(info.Mode()),
@@ -97,6 +111,8 @@ func addFileToTarWithName(tarWriter *tar.Writer, filePath, tarName string) error
97111
}
98112
defer file.Close()
99113

114+
tarName = filepath.ToSlash(tarName)
115+
100116
stat, err := file.Stat()
101117
if err != nil {
102118
return err
@@ -117,6 +133,14 @@ func addFileToTarWithName(tarWriter *tar.Writer, filePath, tarName string) error
117133
return err
118134
}
119135

136+
func isDirEmpty(path string) (bool, error) {
137+
entries, err := os.ReadDir(path)
138+
if err != nil {
139+
return false, err
140+
}
141+
return len(entries) == 0, nil
142+
}
143+
120144
// ExtractTarGz extracts a tar.gz archive to a directory
121145
func ExtractTarGz(data []byte, destDir string) error {
122146
gzReader, err := gzip.NewReader(bytes.NewReader(data))

stego/size.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package stego
2+
3+
import "fmt"
4+
5+
var sizeUnits = []string{"B", "KB", "MB", "GB", "TB", "PB"}
6+
7+
// FormatBytes returns a human-readable byte size using base-1024 units.
8+
func FormatBytes(n uint64) string {
9+
if n < 1024 {
10+
return fmt.Sprintf("%d B", n)
11+
}
12+
13+
value := float64(n)
14+
unitIndex := 0
15+
for value >= 1024 && unitIndex < len(sizeUnits)-1 {
16+
value /= 1024
17+
unitIndex++
18+
}
19+
20+
return fmt.Sprintf("%.2f %s", value, sizeUnits[unitIndex])
21+
}

stego/stego.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ func EncodeData(img image.Image, data []byte) (image.Image, error) {
1616
// We need 4 bytes for length + actual data
1717
availableBits := width * height * 3
1818
requiredBits := (len(data) + 4) * 8 // 4 bytes for length prefix
19+
availableBytes := availableBits / 8
20+
requiredBytes := len(data) + 4
1921

2022
if requiredBits > availableBits {
21-
return nil, fmt.Errorf("image too small: need %d bits, have %d bits", requiredBits, availableBits)
23+
return nil, fmt.Errorf("image too small: need %s, have %s capacity", FormatBytes(uint64(requiredBytes)), FormatBytes(uint64(availableBytes)))
2224
}
2325

2426
// Create a new RGBA image
@@ -140,7 +142,7 @@ func DecodeData(img image.Image) ([]byte, error) {
140142

141143
// Sanity check
142144
if dataLength == 0 || dataLength > 100*1024*1024 { // Max 100MB
143-
return nil, fmt.Errorf("invalid data length: %d", dataLength)
145+
return nil, fmt.Errorf("invalid data length: %s", FormatBytes(uint64(dataLength)))
144146
}
145147

146148
// Extract the actual data

0 commit comments

Comments
 (0)