diff options
Diffstat (limited to 'vendor/layeh.com/asar/encoder.go')
| -rw-r--r-- | vendor/layeh.com/asar/encoder.go | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/vendor/layeh.com/asar/encoder.go b/vendor/layeh.com/asar/encoder.go new file mode 100644 index 0000000..70024a9 --- /dev/null +++ b/vendor/layeh.com/asar/encoder.go @@ -0,0 +1,122 @@ +package asar // import "layeh.com/asar" + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "io" + "strconv" +) + +type entryEncoder struct { + Contents []io.Reader + CurrentOffset int64 + Header bytes.Buffer + Encoder *json.Encoder +} + +func (enc *entryEncoder) Write(v interface{}) { + enc.Encoder.Encode(v) + enc.Header.Truncate(enc.Header.Len() - 1) // cut off trailing new line +} + +func (enc *entryEncoder) WriteField(key string, v interface{}) { + enc.Write(key) + enc.Header.WriteByte(':') + enc.Write(v) +} + +func (enc *entryEncoder) Encode(e *Entry) error { + enc.Header.WriteByte('{') + if e.Flags&FlagDir != 0 { + enc.Write("files") + enc.Header.WriteString(":{") + for i, child := range e.Children { + if i > 0 { + enc.Header.WriteByte(',') + } + if !validFilename(child.Name) { + panic(errHeader) + } + enc.Write(child.Name) + enc.Header.WriteByte(':') + if err := enc.Encode(child); err != nil { + return err + } + } + enc.Header.WriteByte('}') + } else { + enc.Write("size") + enc.Header.WriteByte(':') + enc.Write(e.Size) + + if e.Flags&FlagExecutable != 0 { + enc.Header.WriteByte(',') + enc.WriteField("executable", true) + } + + enc.Header.WriteByte(',') + if e.Flags&FlagUnpacked == 0 { + enc.WriteField("offset", strconv.FormatInt(enc.CurrentOffset, 10)) + enc.CurrentOffset += e.Size + enc.Contents = append(enc.Contents, io.NewSectionReader(e.r, e.baseOffset, e.Size)) + } else { + enc.WriteField("unpacked", true) + } + } + enc.Header.WriteByte('}') + return nil +} + +// EncodeTo writes an ASAR archive containing Entry's descendants. This function +// is usally called on the root entry. +func (e *Entry) EncodeTo(w io.Writer) (n int64, err error) { + + defer func() { + if r := recover(); r != nil { + if e := r.(error); e != nil { + err = e + } else { + panic(r) + } + } + + }() + + encoder := entryEncoder{} + { + var reserve [16]byte + encoder.Header.Write(reserve[:]) + } + encoder.Encoder = json.NewEncoder(&encoder.Header) + if err = encoder.Encode(e); err != nil { + return + } + + { + var padding [3]byte + encoder.Header.Write(padding[:encoder.Header.Len()%4]) + } + + header := encoder.Header.Bytes() + binary.LittleEndian.PutUint32(header[:4], 4) + binary.LittleEndian.PutUint32(header[4:8], 8+uint32(encoder.Header.Len())) + binary.LittleEndian.PutUint32(header[8:12], 4+uint32(encoder.Header.Len())) + binary.LittleEndian.PutUint32(header[12:16], uint32(encoder.Header.Len())) + + n, err = encoder.Header.WriteTo(w) + if err != nil { + return + } + + for _, chunk := range encoder.Contents { + var written int64 + written, err = io.Copy(w, chunk) + n += written + if err != nil { + return + } + } + + return +} |
