204 lines
5.6 KiB
Go
204 lines
5.6 KiB
Go
package cp
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/binary"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
)
|
|
|
|
type CPReader struct {
|
|
FileHandle *os.File
|
|
streamReader *bufio.Reader
|
|
cursorOffset uint32
|
|
//h header
|
|
}
|
|
|
|
const (
|
|
CPE_FILE_IDENTIFIER string = "CPDFile"
|
|
CPE_FILE_IDENTIFIER_SIZE int = 7
|
|
CPE_FILE_VER int = 2
|
|
CPE_FILE_VER_SIZE int = 1
|
|
CPE_ENCRYPTED_FILE_VER int = 3
|
|
CPE_FILE_SUBVER int = 0
|
|
CPE_FILE_SUBVER_SIZE int = 1
|
|
CPE_FILE_HEADER_LENGTH int = 9
|
|
CPE_SECTION_NAME_SIZE int = 3
|
|
CPE_SECTION_LEN_SIZE int = 4
|
|
CPE_SECTION_COUNT int = 3
|
|
CPE_SECTION_EXT string = "EXT"
|
|
CPE_SECTION_CP string = "CPS"
|
|
CPE_SECTION_LLP string = "LLP"
|
|
CPE_SECTION_RADIOPASS string = "RPP"
|
|
CPE_SECTION_TONEFILE string = "TON"
|
|
)
|
|
|
|
func NewReader(fileName string) (_ CPReader, err error) {
|
|
return CPReader{}.NewReader(fileName)
|
|
}
|
|
func (r CPReader) NewReader(fileName string) (_ CPReader, err error) {
|
|
r.FileHandle, err = os.Open(fileName)
|
|
if err != nil {
|
|
return r, err
|
|
}
|
|
r.streamReader = bufio.NewReader(r.FileHandle)
|
|
return r, nil
|
|
}
|
|
func (r *CPReader) Close() {
|
|
r.FileHandle.Close()
|
|
}
|
|
func (r *CPReader) read32Bit() (value int, err error) {
|
|
bytes := make([]byte, 4)
|
|
_, err = io.ReadFull(r.streamReader, bytes)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
r.cursorOffset += 4
|
|
return int(binary.LittleEndian.Uint32(bytes)), nil
|
|
}
|
|
func (r *CPReader) Test() (err error) {
|
|
firstInt, _ := r.read32Bit()
|
|
fmt.Printf("first int is %d\n", firstInt)
|
|
if firstInt == 0 {
|
|
return errors.New("table empty")
|
|
}
|
|
tableIndex := 0
|
|
if tableIndex < firstInt {
|
|
recordType, _ := r.read32Bit()
|
|
fmt.Printf("recordType is %d\n", recordType)
|
|
|
|
}
|
|
return nil
|
|
}
|
|
|
|
/*
|
|
func (r *CPEReader) readFileMetadata() (GMAFileMetadata, error) {
|
|
metadata := GMAFileMetadata{}
|
|
|
|
// Read the file name
|
|
fileName, err := r.gmaStreamReader.ReadString(byte(0))
|
|
if err != nil {
|
|
return metadata, err
|
|
}
|
|
//fmt.Printf("bufio ReadString(byte(0)) = len(%d) data=%x\n", len(fileName), fileName)
|
|
|
|
fileName = fileName[:len(fileName)-1] // remove nullbyte that causes go string fuckyness
|
|
r.cursorOffset += uint32(len(fileName) + 1) // Add name length + null byte
|
|
metadata.FileName = fileName
|
|
|
|
// Read the file size
|
|
fileSizeBytes := make([]byte, 8)
|
|
_, err = io.ReadFull(r.gmaStreamReader, fileSizeBytes)
|
|
if err != nil {
|
|
return metadata, err
|
|
}
|
|
r.cursorOffset += 8
|
|
//fmt.Printf("bufio Read([]byte(4)]) fileSizeBytes = bytesRead(%d) data=%x\n", bytesRead, fileSizeBytes)
|
|
metadata.FileSize = int64(binary.LittleEndian.Uint64(fileSizeBytes))
|
|
|
|
// Read the file crc
|
|
crcBytes := make([]byte, 4)
|
|
_, err = io.ReadFull(r.gmaStreamReader, crcBytes)
|
|
if err != nil {
|
|
return metadata, err
|
|
}
|
|
r.cursorOffset += 4
|
|
//fmt.Printf("bufio Read([]byte(4)]) crcBytes = bytesRead(%d) data=%x\n", bytesRead, crcBytes)
|
|
metadata.CRC = binary.LittleEndian.Uint32(crcBytes)
|
|
|
|
// Read the next type
|
|
nextTypeBytes := make([]byte, 4)
|
|
_, err = io.ReadFull(r.gmaStreamReader, nextTypeBytes)
|
|
if err != nil {
|
|
return metadata, err
|
|
}
|
|
r.cursorOffset += 4
|
|
metadata.NextType = binary.LittleEndian.Uint32(nextTypeBytes)
|
|
//fmt.Printf("bufio Read([]byte(4)]) nextTypeBytes = bytesRead(%d) data=%x\n", bytesRead, nextTypeBytes)
|
|
|
|
return metadata, nil
|
|
}
|
|
func (r *CPEReader) ReadAddonCRC(lastOffset int64) (crc uint32, err error) {
|
|
|
|
limitReader := io.NewSectionReader(r.FileHandle, int64(r.cursorOffset)+lastOffset, int64(4))
|
|
|
|
crcBytes := make([]byte, 4)
|
|
_, err = limitReader.Read(crcBytes)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
r.cursorOffset += 4
|
|
CRC := binary.LittleEndian.Uint32(crcBytes)
|
|
return CRC, nil
|
|
}
|
|
|
|
func (r *CPEReader) ReadFiles() (firstType int32, files []GMAFileMetadata, err error) {
|
|
// read nType 4byte
|
|
firstTypeBytes := make([]byte, 4)
|
|
_, err = r.gmaStreamReader.Read(firstTypeBytes)
|
|
if err != nil {
|
|
return 0, files, err
|
|
}
|
|
r.cursorOffset += 4
|
|
firstType = int32(binary.LittleEndian.Uint32(firstTypeBytes))
|
|
|
|
if firstType == 0 {
|
|
return 0, files, nil
|
|
}
|
|
fileOffset := int64(0)
|
|
fileNumber := int32(1)
|
|
for {
|
|
fileMeta, err := r.readFileMetadata()
|
|
if err != nil {
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
return firstType, files, err
|
|
}
|
|
fileMeta.FileNumber = fileNumber
|
|
fileMeta.Offset = fileOffset
|
|
//fmt.Printf("%s CRC: %d Offset: %d Size: %d\n", fileMeta.FileName, fileMeta.CRC, fileMeta.Offset, fileMeta.FileSize)
|
|
//fmt.Printf("[% x]\n", fileMeta.FileName)
|
|
files = append(files, fileMeta)
|
|
fileOffset += fileMeta.FileSize
|
|
fileNumber++
|
|
if fileMeta.NextType == 0 {
|
|
break
|
|
}
|
|
}
|
|
|
|
return firstType, files, nil
|
|
}
|
|
func (r *CPEReader) GetOffset() (offset uint32) {
|
|
return r.cursorOffset
|
|
}
|
|
func (r *CPEReader) ExtractFileTo(fileMeta GMAFileMetadata, writer io.Writer) (extractMeta GMAExtractionMeta, err error) {
|
|
extractMeta.OriginalMeta = fileMeta
|
|
// Seek to the specified offset in the reader
|
|
limitReader := io.NewSectionReader(r.FileHandle, int64(r.cursorOffset)+fileMeta.Offset, int64(fileMeta.FileSize))
|
|
// Copy the specified length of data from the reader to the output file
|
|
buf := bytes.NewBuffer(nil)
|
|
_, err = io.CopyN(buf, limitReader, int64(fileMeta.FileSize))
|
|
if err != nil {
|
|
return extractMeta, err
|
|
}
|
|
shaHasher := sha256.New()
|
|
|
|
extractMeta.ExtractedCRC = crc32.Checksum(buf.Bytes(), crc32.MakeTable(crc32.IEEE))
|
|
shaHasher.Write(buf.Bytes())
|
|
extractMeta.ExtractedSHA256 = fmt.Sprintf("%x", shaHasher.Sum(nil))
|
|
buf.WriteTo(writer)
|
|
|
|
return extractMeta, nil
|
|
}
|
|
func (r *CPEReader) GetSHA256() (hash string, err error) {
|
|
shaHasher := sha256.New()
|
|
if _, err := io.Copy(shaHasher, r.FileHandle); err != nil {
|
|
return "", err
|
|
}
|
|
return fmt.Sprintf("%x", shaHasher.Sum(nil)), nil
|
|
}
|
|
|
|
*/
|