Initial commit
This commit is contained in:
commit
5fae89a394
|
@ -0,0 +1,61 @@
|
||||||
|
name: Build
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
env:
|
||||||
|
GOVER: ^1.18
|
||||||
|
NAME: stargazer
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
GOOS: [ windows, linux, darwin ]
|
||||||
|
GOARCH: [ amd64, 386, arm, arm64 ]
|
||||||
|
exclude:
|
||||||
|
- GOOS: windows
|
||||||
|
GOARCH: arm
|
||||||
|
- GOOS: darwin
|
||||||
|
GOARCH: 386
|
||||||
|
- GOOS: darwin
|
||||||
|
GOARCH: arm
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.cache/go-build
|
||||||
|
~/go/pkg/mod
|
||||||
|
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-go-
|
||||||
|
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: ${{ env.GOVER }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
env:
|
||||||
|
GOOS: ${{ matrix.GOOS }}
|
||||||
|
GOARCH: ${{ matrix.GOARCH }}
|
||||||
|
run: go build -ldflags="-s -w" -o dist/$NAME-$GOOS-$GOARCH
|
||||||
|
|
||||||
|
- name: Rename binaries (Windows)
|
||||||
|
if: matrix.GOOS == 'windows'
|
||||||
|
run: for x in dist/$NAME-windows-*; do mv $x $x.exe; done
|
||||||
|
|
||||||
|
- name: Upload binary
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: ${{env.NAME}}-${{ matrix.GOOS }}-${{ matrix.GOARCH }}-${{github.sha}}
|
||||||
|
path: dist/*
|
||||||
|
retention-days: 90
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
*.iml
|
||||||
|
.idea/
|
|
@ -0,0 +1,24 @@
|
||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <https://unlicense.org>
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Stargazer
|
||||||
|
|
||||||
|
Tool to extract STAR files from the PSX used by its package manager "PackmanJr".
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./stargazer stargazer <file> [output dir (optional)]
|
||||||
|
```
|
||||||
|
|
||||||
|
If not output directory is given, the file is extracted to the file name minus the extension plus "`_extracted`" (e.g. `xPackmanJr_0.105.star` -> `xPackmanJr_0.105_extracted`).
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
Thanks to @martravi for helping with reverse-engineering!
|
|
@ -0,0 +1,149 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/binary"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const VERSION = "1.0"
|
||||||
|
|
||||||
|
type (
|
||||||
|
Header struct {
|
||||||
|
Unknown1stByte int8
|
||||||
|
Unknown2ndByte int8
|
||||||
|
Filesize uint32
|
||||||
|
FilenameSize int8
|
||||||
|
MaybePadding int8
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry struct {
|
||||||
|
Header
|
||||||
|
FileName []byte
|
||||||
|
Content []byte
|
||||||
|
Sha1 [20]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
Star struct {
|
||||||
|
Entries []Entry
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Entry) GetFileName() string {
|
||||||
|
return string(e.FileName[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) CalculateSha1() []byte {
|
||||||
|
h := sha1.New()
|
||||||
|
h.Write(e.Content)
|
||||||
|
return h.Sum(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) GetSha1() string {
|
||||||
|
return fmt.Sprintf("%x", e.Sha1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Entry) Extract(outputDir string) error {
|
||||||
|
fp := filepath.Join(outputDir, e.GetFileName())
|
||||||
|
err := os.MkdirAll(filepath.Dir(fp), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.Create(fp)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.Write(e.Content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseEntry(file io.Reader) (*Entry, error) {
|
||||||
|
entry := Entry{}
|
||||||
|
err := binary.Read(file, binary.LittleEndian, &entry.Header.Unknown1stByte)
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
binary.Read(file, binary.LittleEndian, &entry.Header.Unknown2ndByte)
|
||||||
|
|
||||||
|
binary.Read(file, binary.LittleEndian, &entry.Header.Filesize)
|
||||||
|
|
||||||
|
binary.Read(file, binary.LittleEndian, &entry.Header.FilenameSize)
|
||||||
|
binary.Read(file, binary.LittleEndian, &entry.Header.MaybePadding)
|
||||||
|
|
||||||
|
filename := make([]byte, entry.Header.FilenameSize)
|
||||||
|
binary.Read(file, binary.LittleEndian, &filename)
|
||||||
|
entry.FileName = filename
|
||||||
|
|
||||||
|
entry.Content = make([]byte, entry.Header.Filesize)
|
||||||
|
binary.Read(file, binary.LittleEndian, &entry.Content)
|
||||||
|
|
||||||
|
binary.Read(file, binary.LittleEndian, &entry.Sha1)
|
||||||
|
|
||||||
|
calculatedHash := entry.CalculateSha1()
|
||||||
|
|
||||||
|
if !bytes.Equal(calculatedHash, entry.Sha1[:]) {
|
||||||
|
log.Fatalln("Hash mismatch")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &entry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Printf("Stargazer v%s\n", VERSION)
|
||||||
|
flag.Parse()
|
||||||
|
if flag.NArg() < 1 || flag.NArg() > 2 {
|
||||||
|
fmt.Println("Usage: stargazer <file> [output dir (optional)]")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
inputFile := flag.Arg(0)
|
||||||
|
outputDir := flag.Arg(1)
|
||||||
|
if outputDir == "" {
|
||||||
|
outputDir = fmt.Sprintf("%s_extracted", filepath.Base(strings.TrimSuffix(inputFile, filepath.Ext(inputFile))))
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(inputFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var star Star
|
||||||
|
|
||||||
|
log.Printf("Parsing '%s'...\n", inputFile)
|
||||||
|
for {
|
||||||
|
entry, err := ParseEntry(file)
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
star.Entries = append(star.Entries, *entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("Extracting to '%s'...\n", outputDir)
|
||||||
|
for _, entry := range star.Entries {
|
||||||
|
log.Printf("Extracting %s...\n", entry.GetFileName())
|
||||||
|
err := entry.Extract(outputDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Extraction complete!")
|
||||||
|
}
|
Loading…
Reference in New Issue