]>
Commit | Line | Data |
---|---|---|
1 | package hotline | |
2 | ||
3 | import ( | |
4 | "bytes" | |
5 | "encoding/binary" | |
6 | "errors" | |
7 | "io" | |
8 | "path" | |
9 | "strings" | |
10 | ) | |
11 | ||
12 | const pathSeparator = "/" // File path separator TODO: make configurable to support Windows | |
13 | ||
14 | // FilePathItem represents the file or directory portion of a delimited file path (e.g. foo and bar in "/foo/bar") | |
15 | // 00 00 | |
16 | // 09 | |
17 | // 73 75 62 66 6f 6c 64 65 72 // "subfolder" | |
18 | type FilePathItem struct { | |
19 | Len byte | |
20 | Name []byte | |
21 | } | |
22 | ||
23 | type FilePath struct { | |
24 | ItemCount [2]byte | |
25 | Items []FilePathItem | |
26 | } | |
27 | ||
28 | func (fp *FilePath) UnmarshalBinary(b []byte) error { | |
29 | reader := bytes.NewReader(b) | |
30 | err := binary.Read(reader, binary.BigEndian, &fp.ItemCount) | |
31 | if err != nil && !errors.Is(err, io.EOF) { | |
32 | return err | |
33 | } | |
34 | if errors.Is(err, io.EOF) { | |
35 | return nil | |
36 | } | |
37 | ||
38 | for i := uint16(0); i < fp.Len(); i++ { | |
39 | // skip two bytes for the file path delimiter | |
40 | _, _ = reader.Seek(2, io.SeekCurrent) | |
41 | ||
42 | // read the length of the next pathItem | |
43 | segLen, err := reader.ReadByte() | |
44 | if err != nil { | |
45 | return err | |
46 | } | |
47 | ||
48 | pBytes := make([]byte, segLen) | |
49 | ||
50 | _, err = reader.Read(pBytes) | |
51 | if err != nil && !errors.Is(err, io.EOF) { | |
52 | return err | |
53 | } | |
54 | ||
55 | fp.Items = append(fp.Items, FilePathItem{Len: segLen, Name: pBytes}) | |
56 | } | |
57 | ||
58 | return nil | |
59 | } | |
60 | ||
61 | func (fp *FilePath) IsDropbox() bool { | |
62 | if fp.Len() == 0 { | |
63 | return false | |
64 | } | |
65 | ||
66 | return strings.Contains(strings.ToLower(string(fp.Items[fp.Len()-1].Name)), "drop box") | |
67 | } | |
68 | ||
69 | func (fp *FilePath) IsUploadDir() bool { | |
70 | if fp.Len() == 0 { | |
71 | return false | |
72 | } | |
73 | ||
74 | return strings.Contains(strings.ToLower(string(fp.Items[fp.Len()-1].Name)), "upload") | |
75 | } | |
76 | ||
77 | func (fp *FilePath) Len() uint16 { | |
78 | return binary.BigEndian.Uint16(fp.ItemCount[:]) | |
79 | } | |
80 | ||
81 | func (fp *FilePath) String() string { | |
82 | out := []string{"/"} | |
83 | for _, i := range fp.Items { | |
84 | out = append(out, string(i.Name)) | |
85 | } | |
86 | ||
87 | return path.Join(out...) | |
88 | } | |
89 | ||
90 | func ReadFilePath(filePathFieldData []byte) string { | |
91 | var fp FilePath | |
92 | err := fp.UnmarshalBinary(filePathFieldData) | |
93 | if err != nil { | |
94 | // TODO | |
95 | } | |
96 | return fp.String() | |
97 | } | |
98 | ||
99 | func readPath(fileRoot string, filePath, fileName []byte) (fullPath string, err error) { | |
100 | var fp FilePath | |
101 | if filePath != nil { | |
102 | if err = fp.UnmarshalBinary(filePath); err != nil { | |
103 | return "", err | |
104 | } | |
105 | } | |
106 | ||
107 | fullPath = path.Join( | |
108 | "/", | |
109 | fileRoot, | |
110 | fp.String(), | |
111 | path.Join("/", string(fileName)), | |
112 | ) | |
113 | ||
114 | return fullPath, nil | |
115 | } |