...
1 package storage
2
3 import (
4 "encoding/json"
5 "errors"
6 "io"
7 "path/filepath"
8 "unicode/utf8"
9 )
10
11
12
13 var ErrDuplicatePath = errors.New("duplicates of file paths not supported")
14
15
16 type Packer interface {
17
18 AddEntry(e Entry) (int, error)
19 }
20
21
22 type Unpacker interface {
23
24 Next() (*Entry, error)
25 }
26
27 type jsonUnpacker struct {
28 seen seenNames
29 dec *json.Decoder
30 }
31
32 func (jup *jsonUnpacker) Next() (*Entry, error) {
33 var e Entry
34 err := jup.dec.Decode(&e)
35 if err != nil {
36 return nil, err
37 }
38
39
40 if e.Type == FileType {
41 cName := filepath.Clean(e.GetName())
42 if _, ok := jup.seen[cName]; ok {
43 return nil, ErrDuplicatePath
44 }
45 jup.seen[cName] = struct{}{}
46 }
47
48 return &e, err
49 }
50
51
52
53
54
55 func NewJSONUnpacker(r io.Reader) Unpacker {
56 return &jsonUnpacker{
57 dec: json.NewDecoder(r),
58 seen: seenNames{},
59 }
60 }
61
62 type jsonPacker struct {
63 w io.Writer
64 e *json.Encoder
65 pos int
66 seen seenNames
67 }
68
69 type seenNames map[string]struct{}
70
71 func (jp *jsonPacker) AddEntry(e Entry) (int, error) {
72
73 if e.Name != "" {
74 if !utf8.ValidString(e.Name) {
75 e.NameRaw = []byte(e.Name)
76 e.Name = ""
77 }
78 }
79
80
81 if e.Type == FileType {
82 cName := filepath.Clean(e.GetName())
83 if _, ok := jp.seen[cName]; ok {
84 return -1, ErrDuplicatePath
85 }
86 jp.seen[cName] = struct{}{}
87 }
88
89 e.Position = jp.pos
90 err := jp.e.Encode(e)
91 if err != nil {
92 return -1, err
93 }
94
95
96 jp.pos++
97 return e.Position, nil
98 }
99
100
101
102
103
104 func NewJSONPacker(w io.Writer) Packer {
105 return &jsonPacker{
106 w: w,
107 e: json.NewEncoder(w),
108 seen: seenNames{},
109 }
110 }
111
View as plain text