go-fds/blocks.go

214 lines
4.1 KiB
Go

package fds
import (
"fmt"
"strings"
)
type BlockType byte
const (
BtInfo BlockType = 0x01
BtFileAmount BlockType = 0x02
BtFileHeader BlockType = 0x03
BtFileData BlockType = 0x04
BtTest BlockType = 0x05
)
func (bt BlockType) String() string {
switch bt {
case BtInfo:
return "BlockInfo"
case BtFileAmount:
return "BlockAmount"
case BtFileHeader:
return "BlockFileHeader"
case BtFileData:
return "BlockFileData"
}
return "Unknown block"
}
type DiskBlock interface {
Type() BlockType
String() string
}
// Block 1
type BlockInfo struct {
// always 0x01
BlockCode byte
// literal ASCII: "*NINTENDO-HVC*"
DiskVerification [14]byte
Licensee uint8
// 3 byte ASCII code
GameName [3]byte
// 0x20: " " normal disk
// 0x45: "E" Event
// 0x4A: "J" Unknown
// 0x52: "R" Reduction in price via advert (lmao what?)
GameType uint8
GameVersion uint8
SideNumber uint8
DiskNumber uint8
// 0x01 for FMC blue-disk
// 0x00 otherwise
DiskType uint8
Unknown_18 uint8 // unknown; 0x00 in all known games
BootReadFileCode uint8
Unknown_1A [5]byte // unknown; 0xFF x5
// BCD YMD, but 1-indexed from Japanese calendar era (fuck you, lmao).
ManufacturingDate [3]byte
CountryCode uint8 // 0x49 = japan
Unknown_23 uint8 // region code?
Unknown_24 uint8 // location/site?
Unknown_25 [2]byte // raw: 0x00 0x22
Unknown_27 [5]byte // game info representation?
// BCD YMD (same as above). Disk Writer kiosk write date?
RewrittenDate [3]byte
Unknown_2F uint8
Unknown_30 uint8 // raw: 0x80
DiskWriterSerial uint16
Unknown_33 uint8 // raw: 0x07
// BCD format. 0x00 == original
RewriteCount byte
// 0x00 = SideA; 0x01 = SideB
ActualDiskSide uint8
// 0x00 yellow
// 0xFF blue
// 0xFE prototype/internal (white or pink)
DiskTypeOther uint8
DiskVersion uint8
// CRC-16/KERMIT. apparently this will work: github.com/sigurn/crc16
CRC uint16 // omitted from FDS files (fucking whyyyyyyy)
}
func (b *BlockInfo) Type() BlockType {
return BtInfo
}
func (b *BlockInfo) String() string {
return fmt.Sprintf("FdsBlockInfo Licensee:%02X GameName:%q GameType:%c",
b.Licensee,
b.GameName,
b.GameType,
)
}
const Template_FdsBlockInfo string = `Licensee: {{.Licensee}}
{{.LicEn}}
{{.LicJp}}
Name: {{.GameName}} Version: {{.GameVersion}} Type: {{.GameType}}`
func (b *BlockInfo) Info() string {
return "yup"
}
//func (b *BlockInfo) Info() string {
// return fmt.Sprintf("Licensee:%02X\n %s\n %s\nGameName: %s",
// b.Licensee,
// LicenseeEnName(b.Licensee),
// LicenseeJpName(b.Licensee),
// )
//}
type BlockFileAmount struct {
BlockCode byte // raw: 0x02
FileAmount uint8
CRC uint16 // omitted from FDS files (fucking whyyyyyyy)
}
func (b *BlockFileAmount) Type() BlockType {
return BtFileAmount
}
func (b *BlockFileAmount) String() string {
return fmt.Sprintf("BlockFileAmount FileAmount:%d", b.FileAmount)
}
type BlockFileHeader struct {
BlockCode byte // raw: 0x03
FileNumber uint8
FileId uint8
FileName [8]byte
FileAddress uint16 // destination when loading
FileSize uint16
// 0x00: Program (PRAM)
// 0x01: Character (CRAM)
// 0x02: Nametable (VRAM)
FileType uint8
CRC uint16 // omitted from FDS files (fucking whyyyyyyy)
}
func (b *BlockFileHeader) Type() BlockType {
return BtFileHeader
}
func (b *BlockFileHeader) String() string {
return fmt.Sprintf("BlockFileHeader FileNumber:%d FileId:%d FileName:%q FileAddress:$%04X FileSize:%d FileType:%d",
b.FileNumber,
b.FileId,
string(b.FileName[:]),
b.FileAddress,
b.FileSize,
b.FileType,
)
}
type BlockFileData struct {
BlockCode byte // raw: 0x04
// Disk data (FdsFileHeader.FileSize length)
Data []byte
CRC uint16 // omitted from FDS files (fucking whyyyyyyy)
}
func (b *BlockFileData) Type() BlockType {
return BtFileData
}
func (b *BlockFileData) String() string {
return "BlockFileData"
}
type BlockTest struct {
Raw []byte
}
func (b *BlockTest) Type() BlockType {
return BtTest
}
func (b *BlockTest) String() string {
bytes := []string{}
for _, byt := range b.Raw {
bytes = append(bytes, fmt.Sprintf("$%02X", byt))
}
return fmt.Sprintf("BlockTest Raw:[%s]", strings.Join(bytes, " "))
}