Kistaro

Unsuccessful attempt to guess Analogue Pocket GB Palette file format

Dec 9th, 2023
1,452
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 4.55 KB | Gaming | 0 0
  1. package main
  2.  
  3. // Binary apgbpal creates a 56-byte file named "test.pal" in the current working
  4. // directory. I hope it might be an Analogue Pocket GB Palette file, but I don't
  5. // know that for sure yet.
  6.  
  7. // apgbpal is licensed under 0BSD.
  8. //
  9. // Zero-Clause BSD
  10. // =============
  11. //
  12. // Permission to use, copy, modify, and/or distribute this software for
  13. // any purpose with or without fee is hereby granted.
  14. //
  15. // THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL
  16. // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
  17. // OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18. // FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
  19. // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  20. // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. // OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  
  23.  
  24. import (
  25.     "fmt"
  26.     "log"
  27.     "os"
  28.     "strconv"
  29.     "strings"
  30. )
  31.  
  32. type RGBA struct {
  33.     R byte
  34.     G byte
  35.     B byte
  36.     A byte
  37. }
  38.  
  39. func (c RGBA) Bytes() [4]byte {
  40.     return [4]byte{c.R, c.G, c.B, c.A}
  41. }
  42.  
  43. func HexByteAt(str string, index int) (byte, error) {
  44.     if len(str) < index+2 {
  45.         return 0, fmt.Errorf("no hex byte at %d in too short string %q", index, str)
  46.     }
  47.     big, err := strconv.ParseUint(str[index:index+1], 16, 8)
  48.     if err != nil {
  49.         return 0, fmt.Errorf("can't parse hex byte at %d in string %q: %w", index, str, err)
  50.     }
  51.     return byte(big), nil
  52. }
  53.  
  54. func ParseRGBA(str string) (RGBA, error) {
  55.     s := strings.TrimSpace(str)
  56.     s = strings.ToLower(s)
  57.     s, _ = strings.CutPrefix(s, "#")
  58.     var ret RGBA
  59.     switch len(s) {
  60.     case 6:
  61.         ret.A = 0xFF
  62.     case 8:
  63.         var err error
  64.         ret.A, err = HexByteAt(s, 6)
  65.         if err != nil {
  66.             return RGBA{}, fmt.Errorf("can't parse alpha channel: %v", err)
  67.         }
  68.     default:
  69.         return RGBA{}, fmt.Errorf("%q is not an RGBA value: wrong length after trimming", str)
  70.     }
  71.     var err error
  72.     if ret.R, err = HexByteAt(s, 0); err != nil {
  73.         return RGBA{}, fmt.Errorf("can't parse red channel: %v", err)
  74.     }
  75.     if ret.G, err = HexByteAt(s, 2); err != nil {
  76.         return RGBA{}, fmt.Errorf("can't parse green channel: %v", err)
  77.     }
  78.     if ret.B, err = HexByteAt(s, 4); err != nil {
  79.         return RGBA{}, fmt.Errorf("can't parse blue channel: %v", err)
  80.     }
  81.     return ret, nil
  82. }
  83.  
  84. type BGPal [4]RGBA
  85.  
  86. func (b BGPal) Bytes() [20]byte {
  87.     var ret [20]byte
  88.     ret[0] = 'b'
  89.     ret[1] = 'g'
  90.     ret[2] = ':'
  91.     for c := 0; c < 4; c++ {
  92.         bb := b[c].Bytes()
  93.         for i := 0; i < 4; i++ {
  94.             ret[3+i+4*c] = bb[i]
  95.         }
  96.     }
  97.     ret[19] = '\n'
  98.     return ret
  99. }
  100.  
  101. func MustParseBGPal(strs []string) BGPal {
  102.     if len(strs) != 4 {
  103.         log.Fatalf("MustParseBGPal requires length 4, got %d", len(strs))
  104.     }
  105.     var ret BGPal
  106.     for i := 0; i < 4; i++ {
  107.         var err error
  108.         ret[i], err = ParseRGBA(strs[i])
  109.         if err != nil {
  110.             log.Fatalf("MustParseBGPal can't parse at %d: %v", i, err)
  111.         }
  112.     }
  113.     return ret
  114. }
  115.  
  116. type OBJPal [3]RGBA
  117.  
  118. func (o OBJPal) Bytes(indexchar byte) [18]byte {
  119.     var ret [18]byte
  120.     ret[0] = 'o'
  121.     ret[1] = 'b'
  122.     ret[2] = 'j'
  123.     ret[3] = indexchar
  124.     ret[4] = ':'
  125.     for c := 0; c < 3; c++ {
  126.         oo := o[c].Bytes()
  127.         for i := 0; i < 4; i++ {
  128.             ret[5+i+4*c] = oo[i]
  129.         }
  130.     }
  131.     ret[17] = '\n'
  132.     return ret
  133. }
  134.  
  135. func MustParseOBJPal(strs []string) OBJPal {
  136.     if len(strs) == 4 {
  137.         log.Println("Discarding index 0 of OBJ pal")
  138.         strs = strs[1:]
  139.     }
  140.     if len(strs) != 3 {
  141.         log.Fatalf("MustParseObjPal requires length 3, got %d", len(strs))
  142.     }
  143.     var ret OBJPal
  144.     for i := 0; i < 3; i++ {
  145.         var err error
  146.         ret[i], err = ParseRGBA(strs[i])
  147.         if err != nil {
  148.             log.Fatalf("MustParseOBJPal can't parse at %d: %v", i, err)
  149.         }
  150.     }
  151.     return ret
  152. }
  153.  
  154. type APGBPal struct {
  155.     BG   BGPal
  156.     OBJ0 OBJPal
  157.     OBJ1 OBJPal
  158. }
  159.  
  160. func (a APGBPal) Bytes() [56]byte {
  161.     var ret [56]byte
  162.     for i, b := range a.BG.Bytes() {
  163.         ret[i] = b
  164.     }
  165.     for i, b := range a.OBJ0.Bytes('0') {
  166.         ret[i+20] = b
  167.     }
  168.     for i, b := range a.OBJ1.Bytes('1') {
  169.         ret[i+38] = b
  170.     }
  171.     return ret
  172. }
  173.  
  174. func main() {
  175.     f, err := os.OpenFile(
  176.         "test.pal",
  177.         os.O_WRONLY|os.O_CREATE|os.O_EXCL,
  178.         0644)
  179.     if err != nil {
  180.         log.Fatalf("can't create test.pal: %v", err)
  181.     }
  182.     aUpPal := APGBPal{
  183.         BG:   MustParseBGPal([]string{"ffffff", "ff8484", "943a3a", "000000"}),
  184.         OBJ0: MustParseOBJPal([]string{"7bff31", "008400", "000000"}),
  185.         OBJ1: MustParseOBJPal([]string{"63a5ff", "0000ff", "000000"}),
  186.     }
  187.     palb := aUpPal.Bytes()
  188.     n, err := f.Write(palb[:])
  189.     if err != nil {
  190.         log.Fatalf("can't save test.pal: %v", err)
  191.     }
  192.     if n != 56 {
  193.         log.Fatalf("unexpected write length: %d", n)
  194.     }
  195.     f.Close()
  196.     os.Exit(0)
  197. }
  198.  
Advertisement