package gma import ( "bufio" "crypto/sha256" "encoding/binary" "fmt" "io" "os" ) type GMAWriter struct { FileHandle *os.File gmaStreamWriter *bufio.Writer } func NewWriter(fileName string) (_ GMAWriter, err error) { return GMAWriter{}.NewWriter(fileName) } func (w GMAWriter) NewWriter(fileName string) (_ GMAWriter, err error) { w.FileHandle, err = os.Create(fileName) if err != nil { return w, err } w.gmaStreamWriter = bufio.NewWriter(w.FileHandle) return w, nil } func (w *GMAWriter) WriteHeader(header GMAHeader) (err error) { w.gmaStreamWriter.WriteByte('G') w.gmaStreamWriter.WriteByte('M') w.gmaStreamWriter.WriteByte('A') w.gmaStreamWriter.WriteByte('D') w.gmaStreamWriter.WriteByte(header.FormatVersion) steamIDBytes := make([]byte, 8) binary.LittleEndian.PutUint64(steamIDBytes, header.SteamID) w.gmaStreamWriter.Write(steamIDBytes) timestampBytes := make([]byte, 8) binary.LittleEndian.PutUint64(timestampBytes, header.Timestamp) w.gmaStreamWriter.Write(timestampBytes) if header.FormatVersion > 1 { w.gmaStreamWriter.WriteByte(header.FormatVersionDiscardByte) } w.gmaStreamWriter.WriteString(header.Title) w.gmaStreamWriter.WriteByte(0) w.gmaStreamWriter.WriteString(header.Description) w.gmaStreamWriter.WriteByte(0) w.gmaStreamWriter.WriteString(header.Author) w.gmaStreamWriter.WriteByte(0) addonVersionBytes := make([]byte, 4) binary.LittleEndian.PutUint32(addonVersionBytes, uint32(header.AddonVersion)) w.gmaStreamWriter.Write(addonVersionBytes) w.gmaStreamWriter.Flush() return nil } func (w *GMAWriter) Close() (err error) { return w.FileHandle.Close() } func (w *GMAWriter) WriteFooterCRC(footerCRC uint32) (err error) { crcBytes := make([]byte, 4) binary.LittleEndian.PutUint32(crcBytes, footerCRC) w.gmaStreamWriter.Write(crcBytes) w.gmaStreamWriter.Flush() return nil } func (w *GMAWriter) WriteFirstType(firstType int32) (err error) { firstTypeBytes := make([]byte, 4) binary.LittleEndian.PutUint32(firstTypeBytes, uint32(firstType)) w.gmaStreamWriter.Write(firstTypeBytes) w.gmaStreamWriter.Flush() return nil } func (w *GMAWriter) WriteFileIndex(fileName string, fileSize int64, fileCRC uint32, nextType uint32) (err error) { w.gmaStreamWriter.WriteString(fileName) w.gmaStreamWriter.WriteByte(0) fileSizeBytes := make([]byte, 8) binary.LittleEndian.PutUint64(fileSizeBytes, uint64(fileSize)) w.gmaStreamWriter.Write(fileSizeBytes) crcBytes := make([]byte, 4) binary.LittleEndian.PutUint32(crcBytes, fileCRC) w.gmaStreamWriter.Write(crcBytes) nextTypeBytes := make([]byte, 4) binary.LittleEndian.PutUint32(nextTypeBytes, nextType) w.gmaStreamWriter.Write(nextTypeBytes) w.gmaStreamWriter.Flush() return nil } func (w *GMAWriter) WriteFile(reader io.ReadCloser) (err error) { //body := new(bytes.Buffer) if _, err = io.Copy(w.gmaStreamWriter, reader); err != nil { return err } /* byteCount, err := w.gmaStreamWriter.Write(body.Bytes()) if err != nil { return err } if byteCount != body.Len() { return fmt.Errorf("Only wrote %d bytes from %d", byteCount, body.Len()) } */ err = w.gmaStreamWriter.Flush() if err != nil { return err } return nil } func (w GMAWriter) GetSHA256() (hash string, err error) { shaHasher := sha256.New() if _, err := io.Copy(shaHasher, w.FileHandle); err != nil { return "", err } return fmt.Sprintf("%x", shaHasher.Sum(nil)), nil }