Skip to content

Commit

Permalink
Updates to v1.1. Fixes a few bugs and refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
kamronbatman committed Feb 25, 2020
1 parent e15494d commit 2513578
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 150 deletions.
18 changes: 14 additions & 4 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
#!/usr/bin/env bash

GOOS=windows GOARCH=amd64 go build -o ./build/windows/pcd2wc4.exe
GOOS=darwin GOARCH=amd64 go build -o ./build/darwin/pcd2wc4
GOOS=linux GOARCH=amd64 go build -o ./build/linux/pcd2wc4
rm -rf ./build

GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o ./build/windows/pcd2wc4.exe
GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o ./build/darwin/pcd2wc4
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ./build/linux/pcd2wc4

upx --brute ./build/darwin/pcd2wc4
upx --brute ./build/linux/pcd2wc4
upx --brute ./build/windows/pcd2wc4.exe

cp README.md ./build/darwin
cp README.md ./build/linux
cp README.md ./build/windows
cp README.md ./build/windows

zip -j -9 ./build/pcd2wc4_v1.1_darwin.zip ./build/darwin/*
zip -j -9 ./build/pcd2wc4_v1.1_linux.zip ./build/linux/*
zip -j -9 ./build/pcd2wc4_v1.1_windows.zip ./build/windows/*
175 changes: 29 additions & 146 deletions pcd2wc4.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ package main

import (
"bufio"
"encoding/binary"
. "github.com/projectpokemon/PCD2WC4/util"
"io"
"log"
"os"
"path/filepath"
"strings"
"regexp"
"sync"
)

const version = "1.0.0"
const version = "1.1.0"

func main() {
log.Printf("PCD to WC4 by Sabresite v%s%s", version, LineBreak)
Expand All @@ -30,9 +27,33 @@ func main() {

wait.Add(1)
go func(ch chan string) {
for f := range ch {
log.Printf("Processing file %s%s", f, LineBreak)
processFile(f, ch)
for p := range ch {
log.Printf("Processing %s%s", p, LineBreak)

fi, isDir := GetFileStat(p, regexp.MustCompile("\\.pcd$"), 856)

if isDir {
go func(dir string) {
for file := range GetFiles(dir) {
ch <- file
}
}(p)
continue
}

if fi == nil { continue }

f, err := os.Open(p)
if err != nil {
log.Printf("Error: Unable to open file %s%s", p, LineBreak)
continue
}

saveData := ConvertWondercard(f)
_ = f.Close()

if saveData == nil { return }
SaveWondercard(saveData, p[0:len(p)-4] + ".wc4")
}

// Signal
Expand All @@ -50,147 +71,9 @@ func main() {
end()
}

func processFile(p string, ch chan<- string) {
info, err := os.Stat(p)
if os.IsNotExist(err) {
log.Printf("File: %s does not exist%s", p, LineBreak)
return
}

if os.IsPermission(err) {
log.Printf("File: %s cannot be accessed%s", p, LineBreak)
return
}

if !strings.HasSuffix(p, ".pcd") {
log.Printf("File: %s is not a PCD file%s", p, LineBreak)
return
}

if info.Size() != 856 {
log.Printf("File: %s is not the correct size%s", p, LineBreak)
return
}

if info.IsDir() {
getFiles(info.Name(), ch)
return
}

f, err := os.Open(info.Name())
if err != nil {
log.Printf("%v%s", err, LineBreak)
return
}

saveData := convertWondercard(f)
_ = f.Close()

if saveData != nil {
// Save the data
newPath := p[0:len(p)-4] + ".wc4"
newFile, err := os.Create(newPath)
if err != nil {
log.Printf("File: Error opening new file file %s%s", newPath, LineBreak)
return
}

writer := bufio.NewWriter(newFile)
if _, err := writer.Write(saveData); err != nil {
log.Printf("File: Error writing new file %v%s", err, LineBreak)
return
}

if err := writer.Flush(); err != nil {
log.Printf("File: Error flushing new file %v%s", err, LineBreak)
return
}

_ = newFile.Close()
log.Printf("Created %s%s", newPath, LineBreak)
}
}

func convertWondercard(f *os.File) []byte {
r := bufio.NewReader(f)

buf := make([]byte, 856)
_, err := io.ReadFull(r, buf)
if err != nil {
log.Printf("Error reading data for %s%s", f.Name(), LineBreak)
return nil
}

pkmBuf := buf[8:244]

pid := binary.LittleEndian.Uint32(pkmBuf[0:4])
seed := uint32(binary.LittleEndian.Uint16(pkmBuf[6:8]))

shiftValue := ((pid & 0x3E000) >> 0xD) % 24

decryptBuf := make([]byte, 228)

prng := NewPokemonRng(seed)

// Decrypt
for i := 0; i < 228; i += 2 {
if i == 128 { prng = NewPokemonRng(pid) }
v := binary.LittleEndian.Uint16(pkmBuf[i+8:i+10])
binary.LittleEndian.PutUint16(decryptBuf[i:i+2], v ^ prng.Next().H())
}

// Unshuffle the blocks
newBlocks := make([]byte, 228)

for block := 0; block < 4; block++ {
pos := 32 * blockPositions[block][shiftValue]
blockPos := block * 32
nextBlockPos := (block+1) * 32
copy(newBlocks[blockPos:nextBlockPos], decryptBuf[pos:32+pos])
}

// Copy party stuff
copy(newBlocks[128:228], decryptBuf[128:228])

wcBuf := make([]byte, 856)
copy(wcBuf[0:16], buf[0:16])
copy(wcBuf[16:244], newBlocks)
copy(wcBuf[244:], buf[244:])

return wcBuf
}

func getFiles(dir string, ch chan<- string) {
walk := func (path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

f := info.Name()

if strings.HasSuffix(f, ".pcd") {
ch <- f
}

return nil
}

err := filepath.Walk(dir, walk)
if err != nil {
log.Printf("%v%s", err, LineBreak)
}
}

func end() {
log.Print("Press any key to exit...")
reader := bufio.NewReader(os.Stdin)
_, _, _ = reader.ReadRune()
os.Exit(0)
}

var blockPositions = [][]int{
{0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3},
{1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2},
{2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2, 0, 0, 0, 0, 0, 0, 3, 2, 3, 2, 1, 1},
{3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0},
}
File renamed without changes.
53 changes: 53 additions & 0 deletions util/files.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package util

import (
"log"
"os"
"path/filepath"
"regexp"
)

func GetFiles(dir string) <-chan string {
ch := make(chan string, 1)

go func(d string, fch chan<- string) {
walk := func (path string, info os.FileInfo, err error) error {
if err != nil {
return err
}

fch <- path

return nil
}

_ = filepath.Walk(d, walk)
close(fch)
}(dir, ch)

return ch
}

func GetFileStat(p string, pattern *regexp.Regexp, size int64) (info os.FileInfo, isDir bool) {
info, err := os.Stat(p)
if os.IsNotExist(err) {
log.Printf("File: %s does not exist%s", p, LineBreak)
return
}

if os.IsPermission(err) {
log.Printf("File: %s cannot be accessed%s", p, LineBreak)
return
}

if !pattern.MatchString(p) {
return
}

if size > -1 && info.Size() != size {
return
}

isDir = info.IsDir()
return
}
89 changes: 89 additions & 0 deletions wc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package main

import (
"bufio"
"encoding/binary"
. "github.com/projectpokemon/PCD2WC4/util"
"io"
"log"
"os"
)

var blockPositions = [][]int{
{0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3},
{1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2},
{2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2, 0, 0, 0, 0, 0, 0, 3, 2, 3, 2, 1, 1},
{3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0},
}

func ConvertWondercard(f *os.File) []byte {
r := bufio.NewReader(f)

buf := make([]byte, 856)
_, err := io.ReadFull(r, buf)
if err != nil {
log.Printf("Error reading data for %s%s", f.Name(), LineBreak)
return nil
}

pkmBuf := buf[8:244]

pid := binary.LittleEndian.Uint32(pkmBuf[0:4])
seed := uint32(binary.LittleEndian.Uint16(pkmBuf[6:8]))

shiftValue := ((pid & 0x3E000) >> 0xD) % 24

decryptBuf := make([]byte, 228)

prng := NewPokemonRng(seed)

// Decrypt
for i := 0; i < 228; i += 2 {
if i == 128 { prng = NewPokemonRng(pid) }
v := binary.LittleEndian.Uint16(pkmBuf[i+8:i+10])
binary.LittleEndian.PutUint16(decryptBuf[i:i+2], v ^ prng.Next().H())
}

// Unshuffle the blocks
newBlocks := make([]byte, 228)

for block := 0; block < 4; block++ {
pos := 32 * blockPositions[block][shiftValue]
blockPos := block * 32
nextBlockPos := (block+1) * 32
copy(newBlocks[blockPos:nextBlockPos], decryptBuf[pos:32+pos])
}

// Copy party stuff
copy(newBlocks[128:228], decryptBuf[128:228])

wcBuf := make([]byte, 856)
copy(wcBuf[0:16], buf[0:16])
copy(wcBuf[16:244], newBlocks)
copy(wcBuf[244:], buf[244:])

return wcBuf
}

func SaveWondercard(saveData []byte, newPath string) {
// Save the data
newFile, err := os.Create(newPath)
if err != nil {
log.Printf("File: Error opening new file file %s%s", newPath, LineBreak)
return
}

writer := bufio.NewWriter(newFile)
if _, err := writer.Write(saveData); err != nil {
log.Printf("File: Error writing new file %v%s", err, LineBreak)
return
}

if err := writer.Flush(); err != nil {
log.Printf("File: Error flushing new file %v%s", err, LineBreak)
return
}

_ = newFile.Close()
log.Printf("Created %s%s", newPath, LineBreak)
}

0 comments on commit 2513578

Please sign in to comment.