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 } */