Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Last active February 5, 2025 15:11
Show Gist options
  • Save peterhellberg/6402e95154d57ef8ac886f6b36c398d1 to your computer and use it in GitHub Desktop.
Save peterhellberg/6402e95154d57ef8ac886f6b36c398d1 to your computer and use it in GitHub Desktop.
A quick and dirty decompressor for Firefly Zero carts (Which are Zip files compressed using ZSTD) - https://docs.fireflyzero.com/internal/formats/#rom
package main
import (
"archive/zip"
"flag"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/klauspost/compress/zstd"
)
func main() {
if err := run(os.Args); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}
func run(args []string) error {
in, err := parse(args)
if err != nil {
return err
}
r, err := zip.OpenReader(in.name)
if err != nil {
return err
}
r.RegisterDecompressor(zstd.ZipMethodWinZip, zstd.ZipDecompressor())
base := strings.TrimSuffix(in.name, ".zip")
if err := os.Mkdir(base, 0o755); err != nil {
return err
}
for _, f := range r.File {
fn := filepath.Join(base, f.Name)
ff, err := r.Open(f.Name)
if err != nil {
return err
}
data, err := io.ReadAll(ff)
if err != nil {
return err
}
if err := os.WriteFile(fn, data, 0o755); err != nil {
return err
}
}
return nil
}
type input struct {
exe string
name string
}
func parse(args []string) (input, error) {
var in input
if len(args) == 0 {
return in, fmt.Errorf("no arguments")
}
in.exe = args[0]
flags := flag.NewFlagSet(in.exe, flag.ExitOnError)
if err := flags.Parse(args[1:]); err != nil {
return in, err
}
if rest := flags.Args(); len(rest) > 0 {
in.name = rest[0]
}
if in.name == "" {
return in, fmt.Errorf("no zip file specified")
}
return in, nil
}
@peterhellberg
Copy link
Author

peterhellberg commented Feb 5, 2025

Snek

$ wget https://github.com/firefly-zero/snek/releases/latest/download/lux.snek.zip
$ unzipzstd lux.snek.zip
$ file lux.snek/*
lux.snek/_badges: Windows Precompiled iNF, version 1.3, InfStyle 1, flags 0x69206d09, unicoded, volatile dir ids, at 0x72756f79 "", at 0x70612030 WinDirPath, LanguageID 0
lux.snek/_bin:    WebAssembly (wasm) binary module version 0x1 (MVP)
lux.snek/_hash:   data
lux.snek/_meta:   data
lux.snek/font:    data
$ wasm-objdump -j Export -x lux.snek/_bin

_bin:	file format wasm 0x1

Section Details:

Export[8]:
 - memory[0] -> "memory"
 - func[13] <boot> -> "boot"
 - func[16] <update> -> "update"
 - func[20] <render> -> "render"
 - func[10] <before_exit> -> "before_exit"
 - func[24] <render_line> -> "render_line"
 - func[25] <cheat> -> "cheat"
 - func[26] <_initialize> -> "_initialize"

@peterhellberg
Copy link
Author

Tip

Note that you can unpack a Firefly ROM using the firefly_cli

$ firefly_cli import lux.snek.zip 
new device name: goofy-ruff1es
⚠️  verification failed: read key from ROM
✅ installed: /home/peter/.local/share/firefly/roms/lux/snek

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment