-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubfile.go
163 lines (141 loc) · 4.06 KB
/
subfile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package tgxlib
import (
"encoding/binary"
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
)
type subfile struct {
FilePath string
fileLen uint32
fileIdentifier uint32
fileIndex uint32
headerOffset uint32
headerLen uint32
startOffset uint32
endOffset uint32
fileData []byte
readoffset int
}
// Implement fs.File interface
func (file subfile) Stat() (fs.FileInfo, error) {
return nil, nil
}
func (file *subfile) Read(buf []byte) (int, error) {
bytes := copy(buf, file.fileData[file.readoffset:])
file.readoffset += bytes
return bytes, nil
}
func (file subfile) Close() error {
return nil
}
// end of fs.File implementation
// Implement sort interface
type subfileList []subfile
func (files subfileList) Len() int {
return len(files)
}
func (files subfileList) Swap(i, j int) {
files[i], files[j] = files[j], files[i]
}
func (files subfileList) Less(i, j int) bool {
return files[i].fileIdentifier < files[j].fileIdentifier
}
// End of sort implementation
func (file *subfile) setIdentifier() {
file.fileIdentifier = genIdentifier(strings.ReplaceAll(file.FilePath, "/", "\\"))
}
func (file subfile) getHeaderLength() uint32 {
switch strings.ToUpper(filepath.Ext(file.FilePath)) {
case ".WAV":
return 0x0
//return 0x24
default:
return 0x0
}
}
func fromFileSpec(file_spec_buf []byte) subfile {
var result subfile
result.readFileSpec(file_spec_buf)
return result
}
func ImportSubfile(file_path string) (subfile, error) {
var result subfile
result.FilePath = file_path
result.setIdentifier()
//fmt.Fprintf(os.Stderr, "%s => 0x%08x\n", result.FilePath, result.fileIdentifier)
fileinfo, err := os.Stat(file_path)
if err != nil {
return subfile{}, err
}
result.fileLen = uint32(fileinfo.Size())
result.headerLen = result.getHeaderLength()
result.fileData, err = os.ReadFile(file_path)
if err != nil {
return subfile{}, err
}
return result, nil
}
func (file *subfile) readFileSpec(file_spec_buf []byte) {
path_len := cStrLen(file_spec_buf)
file.FilePath = InternalToOsPath(string(file_spec_buf[:path_len]))
file.fileIdentifier = binary.LittleEndian.Uint32(file_spec_buf[0x50:])
file.fileLen = binary.LittleEndian.Uint32(file_spec_buf[0x54:])
file.fileIndex = binary.LittleEndian.Uint32(file_spec_buf[0x5c:])
file.headerOffset = binary.LittleEndian.Uint32(file_spec_buf[0x60:])
file.headerLen = binary.LittleEndian.Uint32(file_spec_buf[0x64:])
}
func (file *subfile) readFilePos(file_pos_buf []byte) {
file.startOffset = binary.LittleEndian.Uint32(file_pos_buf)
file.endOffset = binary.LittleEndian.Uint32(file_pos_buf[0x4:])
file.fileData = make([]byte, file.fileLen)
}
func (file subfile) writeFileSpec(buf []byte) error {
if len(file.FilePath) >= 80 {
return fmt.Errorf("File path %s is too long", file.FilePath)
}
copy(buf, []byte(OsToInternalPath(file.FilePath)))
buf[len(file.FilePath)] = 0
binary.LittleEndian.PutUint32(buf[80:], file.fileIdentifier)
binary.LittleEndian.PutUint32(buf[84:], file.fileLen)
binary.LittleEndian.PutUint32(buf[88:], 1)
binary.LittleEndian.PutUint32(buf[92:], file.fileIndex)
binary.LittleEndian.PutUint32(buf[96:], file.headerOffset)
binary.LittleEndian.PutUint32(buf[100:], file.headerLen)
return nil
}
func (file subfile) writeLenSpec(buf []byte) {
binary.LittleEndian.PutUint32(buf[0x8:], file.fileLen)
binary.LittleEndian.PutUint32(buf[0xc:], 1)
binary.LittleEndian.PutUint32(buf[0x10:], file.fileIndex)
}
func (file subfile) writePosSpec(buf []byte) {
binary.LittleEndian.PutUint32(buf[0x0:], file.startOffset)
binary.LittleEndian.PutUint32(buf[0x4:], file.endOffset)
}
func (file subfile) Dump(rootdir string) error {
rootdir = filepath.Clean(rootdir)
outfilename, err := FindExistingPath(filepath.Join(rootdir, file.FilePath))
if err != nil {
return err
}
subdir := filepath.Dir(outfilename)
if _, err := os.Stat(subdir); os.IsNotExist(err) {
err := os.MkdirAll(subdir, 0700)
if err != nil {
return err
}
}
outfilehandle, err := os.Create(outfilename)
if err != nil {
return err
}
defer outfilehandle.Close()
_, err = outfilehandle.Write(file.fileData)
if err != nil {
return err
}
return nil
}