65 lines
2.0 KiB
Go
65 lines
2.0 KiB
Go
package lgres
|
|
|
|
import (
|
|
"io"
|
|
|
|
"github.com/inkyblackness/hacked/ss1/resource/lgres/internal/compression"
|
|
"github.com/inkyblackness/hacked/ss1/serial"
|
|
)
|
|
|
|
// CompoundResourceWriter writes a resource with zero, one, or more blocks.
|
|
// Multiple blocks can be created and then written concurrently. Only when the
|
|
// resource is finished, the blocks are finalized.
|
|
type CompoundResourceWriter struct {
|
|
target *serial.PositioningEncoder
|
|
|
|
compressed bool
|
|
dataPaddingSize int
|
|
blockStores []*serial.ByteStore
|
|
blockWriter []*BlockWriter
|
|
}
|
|
|
|
// CreateBlock provides a new, dedicated writer for a new block.
|
|
func (writer *CompoundResourceWriter) CreateBlock() *BlockWriter {
|
|
store := serial.NewByteStore()
|
|
blockWriter := &BlockWriter{target: serial.NewEncoder(store), finisher: func() {}}
|
|
writer.blockStores = append(writer.blockStores, store)
|
|
writer.blockWriter = append(writer.blockWriter, blockWriter)
|
|
return blockWriter
|
|
}
|
|
|
|
func (writer *CompoundResourceWriter) finish() (length uint32) {
|
|
var unpackedSize uint32
|
|
blockCount := len(writer.blockStores)
|
|
writer.target.Code(uint16(blockCount))
|
|
offset := 2 + (blockCount+1)*4 + writer.dataPaddingSize
|
|
for index, store := range writer.blockStores {
|
|
unpackedSize += writer.blockWriter[index].finish()
|
|
writer.target.Code(uint32(offset))
|
|
offset += len(store.Data())
|
|
}
|
|
writer.target.Code(uint32(offset))
|
|
unpackedSize += writer.target.CurPos() + uint32(writer.dataPaddingSize)
|
|
|
|
writer.writeBlocks()
|
|
|
|
return unpackedSize
|
|
}
|
|
|
|
func (writer *CompoundResourceWriter) writeBlocks() {
|
|
var targetWriter io.Writer = writer.target
|
|
targetFinisher := func() {}
|
|
if writer.compressed {
|
|
compressor := compression.NewCompressor(targetWriter)
|
|
targetWriter = compressor
|
|
targetFinisher = func() { compressor.Close() } // nolint: errcheck
|
|
}
|
|
for i := 0; i < writer.dataPaddingSize; i++ {
|
|
targetWriter.Write([]byte{0x00}) // nolint: errcheck
|
|
}
|
|
for _, store := range writer.blockStores {
|
|
targetWriter.Write(store.Data()) // nolint: errcheck
|
|
}
|
|
targetFinisher()
|
|
}
|