WiiUDownloader/tmd.go
2024-04-20 17:44:14 +02:00

147 lines
3.8 KiB
Go

package wiiudownloader
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
const (
TMD_VERSION_WII = 0x00
TMD_VERSION_WIIU = 0x01
)
type TMD struct {
TitleID uint64
Version byte
TitleVersion uint16
ContentCount uint16
Contents []Content
Certificate1 []byte
Certificate2 []byte
}
func ParseTMD(data []byte) (*TMD, error) {
tmd := &TMD{}
reader := bytes.NewReader(data)
reader.Seek(0x180, io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.Version); err != nil {
return nil, err
}
switch tmd.Version {
case TMD_VERSION_WII:
reader.Seek(0x18C, io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.TitleID); err != nil {
return nil, err
}
reader.Seek(0x1DC, io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.TitleVersion); err != nil {
return nil, err
}
if err := binary.Read(reader, binary.BigEndian, &tmd.ContentCount); err != nil {
return nil, err
}
tmd.Contents = make([]Content, tmd.ContentCount)
for i := 0; i < int(tmd.ContentCount); i++ {
offset := 0x1E4 + (0x24 * i)
reader.Seek(int64(offset), io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[i].ID); err != nil {
return nil, err
}
reader.Seek(0x1E8+(0x24*int64(i)), io.SeekStart)
tmd.Contents[i].Index = make([]byte, 2)
if _, err := io.ReadFull(reader, tmd.Contents[i].Index); err != nil {
return nil, err
}
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[i].Type); err != nil {
return nil, err
}
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[i].Size); err != nil {
return nil, err
}
tmd.Contents[i].Hash = make([]byte, 0x20)
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[i].Hash); err != nil {
return nil, err
}
}
tmd.Certificate1 = make([]byte, 0x400)
if _, err := io.ReadFull(reader, tmd.Certificate1); err != nil {
return nil, err
}
tmd.Certificate2 = make([]byte, 0x300)
if _, err := io.ReadFull(reader, tmd.Certificate2); err != nil {
return nil, err
}
case TMD_VERSION_WIIU:
reader.Seek(0x18C, io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.TitleID); err != nil {
return nil, err
}
reader.Seek(0x1DC, io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.TitleVersion); err != nil {
return nil, err
}
if err := binary.Read(reader, binary.BigEndian, &tmd.ContentCount); err != nil {
return nil, err
}
tmd.Contents = make([]Content, tmd.ContentCount)
for c := uint16(0); c < tmd.ContentCount; c++ {
offset := 2820 + (48 * c)
reader.Seek(int64(offset), io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[c].ID); err != nil {
return nil, err
}
reader.Seek(0xB08+(0x30*int64(c)), io.SeekStart)
tmd.Contents[c].Index = make([]byte, 2)
if _, err := io.ReadFull(reader, tmd.Contents[c].Index); err != nil {
return nil, err
}
reader.Seek(0xB0A+(0x30*int64(c)), io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[c].Type); err != nil {
return nil, err
}
reader.Seek(0xB0C+(0x30*int64(c)), io.SeekStart)
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[c].Size); err != nil {
return nil, err
}
reader.Seek(0xB14+(0x30*int64(c)), io.SeekStart)
tmd.Contents[c].Hash = make([]byte, 0x20)
if err := binary.Read(reader, binary.BigEndian, &tmd.Contents[c].Hash); err != nil {
return nil, err
}
}
tmd.Certificate1 = make([]byte, 0x400)
if err := binary.Read(reader, binary.BigEndian, &tmd.Certificate1); err != nil {
return nil, err
}
tmd.Certificate2 = make([]byte, 0x300)
if err := binary.Read(reader, binary.BigEndian, &tmd.Certificate2); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unknown TMD version: %d", tmd.Version)
}
return tmd, nil
}