all repos — nds-converter @ 5b2bb6a5c8061db447746fa0fe7d300d0dd6c019

A lightweight save converter for NDS and DeSmuME.

nds-converter.go (view raw)

  1package main
  2
  3import (
  4	"encoding/hex"
  5	"io"
  6	"net/http"
  7	"os"
  8	"path/filepath"
  9	"strconv"
 10
 11	"github.com/joho/godotenv"
 12)
 13
 14type ConverterFunction func([]byte) []byte
 15
 16const (
 17	MB                 = 1 << 20
 18	DefaultMaxFileSize = 2
 19	DefaultPort        = "1111"
 20	TrimBytes          = 122
 21	AdditionalBytesHex = "7C3C2D2D536E69702061626F7665206865726520746F2063726561746520612072617720736176206279206578636C7564696E672074686973204465536D754D4520736176656461746120666F6F7465723A0000010000000100030000000200000000000100000000007C2D4445534D554D4520534156452D7C"
 22)
 23
 24var (
 25	MaxFileSize        int64
 26	AdditionalBytes    []byte
 27	ConverterFunctions = map[string]ConverterFunction{
 28		".dsv": DsvToSav,
 29		".sav": SavToDsv,
 30	}
 31)
 32
 33func main() {
 34	// Load the .env file
 35	err := godotenv.Load()
 36	if err != nil {
 37		println("Could not load .env file")
 38	}
 39
 40	port := os.Getenv("PORT")
 41	if port == "" {
 42		port = DefaultPort
 43	}
 44
 45	fileSizeString := os.Getenv("MAX_SIZE_MB")
 46	MaxFileSize, err = strconv.ParseInt(fileSizeString, 10, 64)
 47	if err != nil {
 48		MaxFileSize = DefaultMaxFileSize
 49	}
 50	MaxFileSize *= MB
 51
 52	AdditionalBytes, _ = hex.DecodeString(AdditionalBytesHex)
 53
 54	http.HandleFunc("/", uploadHandler)
 55	println("Listening on port " + port)
 56	http.ListenAndServe(":"+port, nil)
 57}
 58
 59func DsvToSav(input []byte) []byte {
 60	return input[:len(input)-TrimBytes]
 61}
 62
 63func SavToDsv(input []byte) []byte {
 64	return append(input, AdditionalBytes...)
 65}
 66
 67func uploadHandler(w http.ResponseWriter, r *http.Request) {
 68	// Parse the multipart form data
 69	err := r.ParseMultipartForm(MaxFileSize)
 70	if err != nil {
 71		http.Error(w, "Error parsing form", http.StatusBadRequest)
 72		return
 73	}
 74
 75	r.Body = http.MaxBytesReader(w, r.Body, MaxFileSize)
 76
 77	// Get the file from the request
 78	file, h, err := r.FormFile("file")
 79	if err != nil {
 80		http.Error(w, "Error retrieving file from form data", http.StatusBadRequest)
 81		return
 82	}
 83	defer file.Close()
 84
 85	// Check file size
 86	if h.Size > MaxFileSize {
 87		http.Error(w, "File size exceeds 1MB", http.StatusBadRequest)
 88		return
 89	}
 90
 91	var outputContent []byte
 92
 93	// Check file extension
 94	fileExt := filepath.Ext(h.Filename)
 95	converterFunction, exists := ConverterFunctions[fileExt]
 96	if !exists {
 97		http.Error(w, "Invalid file format, only .dsv and .sav files are allowed", http.StatusBadRequest)
 98		return
 99	}
100
101	content, err := io.ReadAll(file)
102	if err != nil {
103		http.Error(w, "Error reading file content", http.StatusInternalServerError)
104		return
105	}
106	outputContent = converterFunction(content)
107
108	w.Header().Set("Content-Length", strconv.Itoa(len(outputContent)))
109	w.Header().Set("Content-Type", "application/octet-stream")
110	w.WriteHeader(http.StatusOK)
111	w.Write(outputContent)
112}