├── README.md ├── .gitignore ├── unpack_CN_test.go ├── unpack.go └── unpack_CN.go /README.md: -------------------------------------------------------------------------------- 1 | # pvf-unpack 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | -------------------------------------------------------------------------------- /unpack_CN_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | import "encoding/hex" 5 | import "log" 6 | import "bytes" 7 | 8 | func Test_pvfDecrypt(t *testing.T) { 9 | tests := []struct { 10 | name string 11 | h string 12 | key string 13 | want string 14 | }{ 15 | // TODO: Add test cases. 16 | {"", 17 | "2225E83379981F9B79B334E4B93A523FAB92A1CC1C35281670CAD51C56DACE5C9848919C4309E5E94F6C5369EC69B4BE", 18 | "hEAd", 19 | "6E6B7069559947593EAA477E136A52A63B35410EECD694E4F2B40C00882A47023B7DDF028A1B0000C8AB810090AB9300", 20 | }, 21 | } 22 | for _, tt := range tests { 23 | t.Run(tt.name, func(t *testing.T) { 24 | b, _ := hex.DecodeString(tt.h) 25 | bw, _ := hex.DecodeString(tt.want) 26 | pvfDecrypt(b, tt.key) 27 | log.Println(hex.Dump(b)) 28 | if !bytes.Equal(b, bw) { 29 | t.Errorf("bad\n") 30 | } 31 | }) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /unpack.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "encoding/hex" 7 | "fmt" 8 | "hash/crc32" 9 | "os" 10 | "strings" 11 | ) 12 | 13 | //PvfDirectory .. 14 | // type PvfDirectory struct { 15 | // //Tag Size 16 | // Tag []byte 17 | // Revision uint32 18 | // //aligned_index_header_size 19 | // //index_header_crc 20 | // //index_size 21 | // data []byte 22 | // } 23 | 24 | // 25 | //namesize 26 | //name 27 | //size 28 | //crc 29 | //offset 30 | // 31 | 32 | //PackEntity -- 33 | type PackEntity struct { 34 | key uint32 35 | name string 36 | crc uint32 37 | offset uint32 38 | size uint32 39 | alignSize uint32 40 | content []byte 41 | } 42 | 43 | var ( 44 | gStringtable []string 45 | gEntities []PackEntity 46 | ) 47 | 48 | func decryptNcrc32(key uint32, b []byte) []byte { 49 | if len(b)%4 > 0 { 50 | return []byte{} 51 | } 52 | var result []byte 53 | result = make([]byte, len(b), len(b)) 54 | e := binary.LittleEndian 55 | key ^= 0 56 | for i := 0; i+4 <= len(b); i += 4 { 57 | var x uint32 58 | x = e.Uint32(b[i:]) 59 | x ^= 0x81A79011 60 | x ^= key 61 | x = (x >> 6) | (x << (32 - 6)) 62 | e.PutUint32(result[i:], x) 63 | } 64 | return result 65 | } 66 | 67 | func getEntityContent(name string) []byte { 68 | for i := 0; i < len(gEntities); i++ { 69 | if name == gEntities[i].name { 70 | return gEntities[i].content 71 | } 72 | } 73 | return nil 74 | } 75 | func initStringtable(b []byte) { 76 | e := binary.LittleEndian 77 | count := e.Uint32(b) 78 | offsets := make([]uint32, count+1, count+1) 79 | gStringtable = make([]string, count, count) 80 | for i := 0; i < int(count+1); i++ { 81 | offsets[i] = e.Uint32(b[4+i*4:]) + 4 82 | } 83 | for i := 0; i < int(count); i++ { 84 | test := b[offsets[i]:offsets[i+1]] 85 | gStringtable[i] = string(test) 86 | } 87 | } 88 | func parserPvf(path string) []PackEntity { 89 | file, err := os.Open(path) 90 | if err != nil { 91 | return nil 92 | } 93 | defer file.Close() 94 | var lenstr uint32 95 | err = binary.Read(file, binary.LittleEndian, &lenstr) 96 | if err != nil { 97 | return nil 98 | } 99 | var tag []byte 100 | tag = make([]byte, lenstr) 101 | _, err = file.Read(tag) 102 | if err != nil { 103 | return nil 104 | } 105 | fmt.Println("tag:", string(tag)) 106 | var revision uint32 107 | var alignedIndexHeaderSize uint32 108 | var indexHeaderCrc uint32 109 | var indexSize uint32 110 | err = binary.Read(file, binary.LittleEndian, &revision) 111 | if err != nil { 112 | return nil 113 | } 114 | fmt.Printf("revision:0x%08X\n", revision) 115 | err = binary.Read(file, binary.LittleEndian, &alignedIndexHeaderSize) 116 | if err != nil { 117 | return nil 118 | } 119 | fmt.Printf("alignedIndexHeaderSize:0x%08X\n", alignedIndexHeaderSize) 120 | err = binary.Read(file, binary.LittleEndian, &indexHeaderCrc) 121 | if err != nil { 122 | return nil 123 | } 124 | fmt.Printf("indexHeaderCrc:0x%08X\n", indexHeaderCrc) 125 | err = binary.Read(file, binary.LittleEndian, &indexSize) 126 | if err != nil { 127 | return nil 128 | } 129 | fmt.Printf("indexSize:0x%08X\n", indexSize) 130 | indexHeaderData := make([]byte, alignedIndexHeaderSize) 131 | 132 | _, err = file.Read(indexHeaderData) 133 | if err != nil { 134 | return nil 135 | } 136 | headerSize, _ := file.Seek(0, 1) 137 | fmt.Printf("0x%08X 0x%08X\n", headerSize, alignedIndexHeaderSize) 138 | indexHeaderData = decryptNcrc32(indexHeaderCrc, indexHeaderData) 139 | fmt.Println(hex.Dump(indexHeaderData[:0x100])) 140 | if crc32.Update(indexSize, crc32.IEEETable, indexHeaderData) != indexHeaderCrc { 141 | fmt.Println("CRC FAILD") 142 | return nil 143 | } 144 | reader := bytes.NewReader(indexHeaderData) 145 | 146 | entities := make([]PackEntity, indexSize) 147 | 148 | for i := 0; i < int(indexSize); i++ { 149 | var key uint32 150 | var namesize uint32 151 | var name string 152 | var size uint32 153 | var crc uint32 154 | var offset uint32 155 | var alignSize uint32 156 | 157 | err = binary.Read(reader, binary.LittleEndian, &key) 158 | if err != nil { 159 | return nil 160 | } 161 | err = binary.Read(reader, binary.LittleEndian, &namesize) 162 | if err != nil { 163 | return nil 164 | } 165 | bname := make([]byte, namesize) 166 | err = binary.Read(reader, binary.LittleEndian, &bname) 167 | if err != nil { 168 | return nil 169 | } 170 | name = string(bname) 171 | err = binary.Read(reader, binary.LittleEndian, &size) 172 | if err != nil { 173 | return nil 174 | } 175 | err = binary.Read(reader, binary.LittleEndian, &crc) 176 | if err != nil { 177 | return nil 178 | } 179 | err = binary.Read(reader, binary.LittleEndian, &offset) 180 | if err != nil { 181 | return nil 182 | } 183 | alignSize = (size + 3) & 0xFFFFFFFC 184 | entities[i].key = key 185 | entities[i].name = name 186 | entities[i].crc = crc 187 | entities[i].offset = offset 188 | entities[i].size = size 189 | entities[i].alignSize = alignSize 190 | 191 | var content []byte 192 | content = make([]byte, alignSize) 193 | file.Seek(int64(offset)+int64(headerSize), 0) 194 | file.Read(content) 195 | entities[i].content = decryptNcrc32(crc, content) 196 | if len(entities[i].content) > int(size) { 197 | entities[i].content = entities[i].content[:size] 198 | } 199 | content = []byte{} 200 | } 201 | 202 | return entities 203 | } 204 | 205 | func bar() { 206 | for i := 0; i < len(gEntities); i++ { 207 | fmt.Println(gEntities[i].name) 208 | buf := bytes.NewBuffer(gEntities[i].content) 209 | var mark uint16 210 | mark = 0 211 | if buf.Len() > 2 { 212 | err := binary.Read(buf, binary.LittleEndian, &mark) 213 | if err != nil { 214 | return 215 | } 216 | } 217 | // if strings.HasSuffix(gEntities[i].name, ".str") { 218 | // fmt.Println(string(gEntities[i].content)) 219 | // file, err := os.Create("str.test") 220 | // if err != nil { 221 | // return 222 | // } 223 | // file.Write(gEntities[i].content) 224 | // file.Close() 225 | // } else { 226 | // continue 227 | // } 228 | if mark != 0xD0B0 { 229 | if !strings.HasSuffix(gEntities[i].name, ".ani") { 230 | fmt.Println(gEntities[i].name) 231 | } 232 | } else { 233 | 234 | for buf.Len() > 0 { 235 | var t byte 236 | var index int32 237 | err := binary.Read(buf, binary.LittleEndian, &t) 238 | if err != nil { 239 | break 240 | } 241 | if t == 4 { 242 | var num float32 243 | err = binary.Read(buf, binary.LittleEndian, &num) 244 | if err != nil { 245 | break 246 | } 247 | fmt.Println(num) 248 | continue 249 | } 250 | err = binary.Read(buf, binary.LittleEndian, &index) 251 | if err != nil { 252 | break 253 | } 254 | switch t { 255 | case 1, 2, 3, 9: 256 | fmt.Println(t, index) 257 | case 5, 6, 7, 8, 10: 258 | fmt.Println(t, gStringtable[index]) 259 | default: 260 | fmt.Println("----BADTAG----", t, index) 261 | } 262 | } 263 | } 264 | } 265 | } 266 | func foo() { 267 | gEntities = parserPvf("./testdata/Script.pvf") 268 | initStringtable(getEntityContent("stringtable.bin")) 269 | fmt.Printf("count entity : %d\n", len(gEntities)) 270 | bar() 271 | } 272 | 273 | // func main() { 274 | // foo() 275 | // } 276 | -------------------------------------------------------------------------------- /unpack_CN.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "compress/zlib" 6 | "encoding/binary" 7 | "encoding/hex" 8 | "errors" 9 | "fmt" 10 | "io/ioutil" 11 | "log" 12 | "os" 13 | "strings" 14 | "time" 15 | "unicode/utf16" 16 | ) 17 | 18 | var cur string 19 | var curcnt int 20 | 21 | type PackHeadCN struct { 22 | magic string //00 "nkpi" 23 | unknown [0x14]byte //04 24 | entityCount uint32 //18 25 | unknown2 uint32 //1C 26 | dataSize uint32 //20 27 | groupIndexCount uint32 //24 28 | hashSize uint32 //28 29 | strSize uint32 //2C 30 | } 31 | 32 | type RDAREntity struct { 33 | NameOffset int32 34 | PathOffset int32 35 | GroupIndex uint32 36 | InnerOffset uint32 37 | Size uint32 38 | Type uint32 // 1: compiled file 3: .str .lua .xui plaintext 39 | } 40 | 41 | type RDARGroup struct { 42 | ChunkOffset uint32 43 | DecSize uint32 44 | } 45 | 46 | type RDARScript struct { 47 | head PackHeadCN 48 | entities []RDAREntity 49 | stringA []byte 50 | stringW []uint16 51 | group []RDARGroup 52 | data []byte 53 | mapdata map[uint32][]byte 54 | } 55 | 56 | func (t *PackHeadCN) Parse(b []byte) error { 57 | if len(b) != 0x30 { 58 | return errors.New("bad len") 59 | } 60 | buf := bytes.NewBuffer(b) 61 | bm := make([]byte, 4) 62 | binary.Read(buf, binary.LittleEndian, &bm) 63 | t.magic = string(bm) 64 | binary.Read(buf, binary.LittleEndian, &t.unknown) 65 | binary.Read(buf, binary.LittleEndian, &t.entityCount) 66 | binary.Read(buf, binary.LittleEndian, &t.unknown2) 67 | binary.Read(buf, binary.LittleEndian, &t.dataSize) 68 | binary.Read(buf, binary.LittleEndian, &t.groupIndexCount) 69 | binary.Read(buf, binary.LittleEndian, &t.hashSize) 70 | binary.Read(buf, binary.LittleEndian, &t.strSize) 71 | return nil 72 | } 73 | 74 | func (t *PackHeadCN) String() string { 75 | var sb bytes.Buffer 76 | fmt.Fprintf(&sb, "PackHeadCN {") 77 | fmt.Fprintf(&sb, "magic: %v ", t.magic) 78 | fmt.Fprintf(&sb, "unknown: %v ", hex.EncodeToString(t.unknown[:])) 79 | fmt.Fprintf(&sb, "entityCount: %v ", t.entityCount) 80 | fmt.Fprintf(&sb, "unknown2: %v ", t.unknown2) 81 | fmt.Fprintf(&sb, "dataSize: %v ", t.dataSize) 82 | fmt.Fprintf(&sb, "groupIndexCount: %v ", t.groupIndexCount) 83 | fmt.Fprintf(&sb, "hashSize: %v ", t.hashSize) 84 | fmt.Fprintf(&sb, "strSize: %v", t.strSize) 85 | fmt.Fprintf(&sb, "}") 86 | return sb.String() 87 | } 88 | 89 | func pvfDecrypt(b []byte, key string) { 90 | if len(key) < 4 { 91 | return 92 | } 93 | e := binary.LittleEndian 94 | hash := 866031377*uint32(key[0]) + 915*(uint32(key[3])+915*(uint32(key[2])+915*uint32(key[1]))) 95 | count := len(b) / 4 96 | remain := len(b) % 4 97 | 98 | for index := 0; index < count; index++ { 99 | h1 := 214013*hash + 2531011 100 | h2 := h1 101 | hash = 214013*h1 + 2531011 102 | e.PutUint32(b[index*4:], e.Uint32(b[index*4:])^((hash>>16)+(h2&0xFFFF0000))) 103 | } 104 | if remain > 0 { 105 | hash = ((214013*hash + 2531011) & 0xFFFF0000) + ((214013*(214013*hash+2531011) + 2531011) >> 16) 106 | for index := 0; index < remain; index++ { 107 | k := make([]byte, 4) 108 | e.PutUint32(k, hash) 109 | b[count*4+index] ^= k[index] 110 | } 111 | } 112 | } 113 | 114 | func pvfDecrypt2(b []byte, key string) { 115 | if len(key) < 4 { 116 | return 117 | } 118 | e := binary.LittleEndian 119 | hash := 866031377*uint32(key[0]) + 915*(uint32(key[3])+915*(uint32(key[2])+915*uint32(key[1]))) 120 | count := len(b) / 4 121 | remain := len(b) % 4 122 | 123 | for index := 0; index < count; index++ { 124 | h1 := 214013*hash + 2531017 125 | h2 := h1 126 | hash = 214013*h1 + 2531017 127 | e.PutUint32(b[index*4:], e.Uint32(b[index*4:])^((hash>>16)+(h2&0xFFFF0000))) 128 | } 129 | if remain > 0 { 130 | hash = ((214013*hash + 2531017) & 0xFFFF0000) + ((214013*(214013*hash+2531017) + 2531017) >> 16) 131 | for index := 0; index < remain; index++ { 132 | k := make([]byte, 4) 133 | e.PutUint32(k, hash) 134 | b[count*4+index] ^= k[index] 135 | } 136 | } 137 | } 138 | 139 | func (t *RDARScript) GetStringByOffset(offset int32) string { 140 | var str = "" 141 | if offset < 0 { 142 | return str 143 | } 144 | nstart := offset / 2 145 | 146 | if (offset & 1) != 0 { //unicode 147 | for index := 0; index < len(t.stringW)-int(nstart); index++ { 148 | if t.stringW[int(nstart)+index] == 0 { 149 | str = string(utf16.Decode(t.stringW[nstart : int(nstart)+index])) 150 | break 151 | } 152 | } 153 | } else { //ansi 154 | for index := 0; index < len(t.stringA)-int(nstart); index++ { 155 | if t.stringA[int(nstart)+index] == 0 { 156 | str = string(t.stringA[nstart : int(nstart)+index]) 157 | break 158 | } 159 | } 160 | } 161 | return str 162 | } 163 | 164 | func (t *RDARScript) GetGroupData(groupIndex uint32) []byte { 165 | if int(groupIndex) >= len(t.group) { 166 | return []byte{} 167 | } 168 | if _, ok := t.mapdata[groupIndex]; !ok { 169 | chunkOffset := uint32(0) 170 | if groupIndex != 0 { 171 | chunkOffset = t.group[groupIndex-1].ChunkOffset 172 | } 173 | chunkSize := t.group[groupIndex].ChunkOffset - chunkOffset 174 | body := make([]byte, chunkSize) 175 | copy(body, t.data[chunkOffset:chunkOffset+chunkSize]) 176 | pvfDecrypt(body, "bODy") 177 | 178 | r, err := zlib.NewReader(bytes.NewReader(body)) 179 | if err != nil { 180 | return []byte{} 181 | } 182 | defer r.Close() 183 | chunk, _ := ioutil.ReadAll(r) 184 | t.mapdata[groupIndex] = chunk 185 | } 186 | return t.mapdata[groupIndex] 187 | } 188 | 189 | func (t *RDARScript) BuildHashStream(b []byte) error { 190 | if len(b) < 4 { 191 | return errors.New("fucking small buf @BuildHashStream") 192 | } 193 | buf := bytes.NewBuffer(b) 194 | var hcount uint32 195 | err := binary.Read(buf, binary.LittleEndian, &hcount) 196 | if err != nil { 197 | return err 198 | } 199 | hsize := 8 * hcount 200 | if hsize == 0 || buf.Len()-4 < int(hsize) { 201 | return errors.New("fucking small buf @BuildHashStream") 202 | } 203 | bh := make([]byte, hsize) 204 | err = binary.Read(buf, binary.LittleEndian, &bh) 205 | if err != nil { 206 | return err 207 | } 208 | 209 | return nil 210 | } 211 | 212 | func (t *RDARScript) BuildStringStream(b []byte) error { 213 | v6 := uint32(0) 214 | v7 := uint32(0) 215 | 216 | buf := bytes.NewBuffer(b) 217 | binary.Read(buf, binary.LittleEndian, &v6) 218 | binary.Read(buf, binary.LittleEndian, &v7) 219 | log.Println((v6 ^ 0x9A82F037) + (v7 ^ 0xAA74472E)) 220 | 221 | binary.Read(buf, binary.LittleEndian, &v6) 222 | binary.Read(buf, binary.LittleEndian, &v7) 223 | 224 | compSize := v6 ^ 0xAA74472E 225 | decSize := compSize ^ v7 226 | ba := make([]byte, compSize) 227 | buf.Read(ba) 228 | pvfDecrypt2(ba, "StRa") 229 | r, err := zlib.NewReader(bytes.NewReader(ba)) 230 | if err != nil { 231 | return err 232 | } 233 | defer r.Close() 234 | t.stringA, err = ioutil.ReadAll(r) 235 | if err != nil { 236 | return err 237 | } 238 | if len(t.stringA) != int(decSize) { 239 | log.Println("bad decompress size:", len(t.stringA), decSize) 240 | } 241 | binary.Read(buf, binary.LittleEndian, &v6) 242 | binary.Read(buf, binary.LittleEndian, &v7) 243 | 244 | compSize = v6 ^ 0x9A82F037 245 | decSize = compSize ^ v7 246 | 247 | bw := make([]byte, compSize) 248 | buf.Read(bw) 249 | pvfDecrypt2(bw, "StRw") 250 | r, err = zlib.NewReader(bytes.NewReader(bw)) 251 | if err != nil { 252 | return err 253 | } 254 | defer r.Close() 255 | bsw, _ := ioutil.ReadAll(r) 256 | if len(bsw) != int(decSize) { 257 | log.Println("bad decompress size:", len(bsw), decSize) 258 | } 259 | t.stringW = make([]uint16, len(bsw)/2) 260 | err = binary.Read(bytes.NewBuffer(bsw), binary.LittleEndian, &t.stringW) 261 | if err != nil { 262 | return err 263 | } 264 | return nil 265 | } 266 | 267 | func (t *RDARScript) DecompileScript(b []byte) string { 268 | var sb bytes.Buffer 269 | buf := bytes.NewBuffer(b) 270 | for buf.Len() > 0 { 271 | Type, err := buf.ReadByte() 272 | if err != nil { 273 | return sb.String() 274 | } 275 | switch Type { 276 | case 0, 1: //int 277 | num := int32(0) 278 | err = binary.Read(buf, binary.LittleEndian, &num) 279 | if err != nil { 280 | return sb.String() 281 | } 282 | sb.WriteString(fmt.Sprintf("%v %v\n", Type, num)) 283 | case 2: //float 284 | fnum := float32(0) 285 | err = binary.Read(buf, binary.LittleEndian, &fnum) 286 | if err != nil { 287 | return sb.String() 288 | } 289 | sb.WriteString(fmt.Sprintf("%v %v\n", Type, fnum)) 290 | case 3, 5, 6: //3 [TAG] 5 6 ref string 291 | stroff := int32(0) 292 | err = binary.Read(buf, binary.LittleEndian, &stroff) 293 | if err != nil { 294 | return sb.String() 295 | } 296 | str := t.GetStringByOffset(stroff) 297 | sb.WriteString(fmt.Sprintf("%v %v\n", Type, str)) 298 | case 7: //uint32 299 | num := uint32(0) 300 | err = binary.Read(buf, binary.LittleEndian, &num) 301 | if err != nil { 302 | return sb.String() 303 | } 304 | sb.WriteString(fmt.Sprintf("%v %v\n", Type, num)) 305 | default: 306 | log.Println("\n" + sb.String() + "\n") 307 | log.Println("Unknown Data Type: ", Type, "\n"+hex.Dump(buf.Bytes())) 308 | } 309 | } 310 | return sb.String() 311 | } 312 | 313 | func (t *RDARScript) ParsePVF(filename string) error { 314 | t.mapdata = map[uint32][]byte{} 315 | file, err := os.Open(filename) 316 | if err != nil { 317 | return nil 318 | } 319 | defer file.Close() 320 | b := make([]byte, 0x30) 321 | err = binary.Read(file, binary.LittleEndian, &b) 322 | if err != nil { 323 | return err 324 | } 325 | pvfDecrypt(b, "hEAd") 326 | err = t.head.Parse(b) 327 | if err != nil { 328 | return err 329 | } 330 | log.Println(t.head.String()) 331 | t.entities = make([]RDAREntity, t.head.entityCount) 332 | err = binary.Read(file, binary.LittleEndian, &t.entities) 333 | if err != nil { 334 | return err 335 | } 336 | 337 | b = make([]byte, t.head.hashSize) 338 | err = binary.Read(file, binary.LittleEndian, &b) 339 | if err != nil { 340 | return err 341 | } 342 | pvfDecrypt(b, "hash") 343 | t.BuildHashStream(b) 344 | 345 | b = make([]byte, t.head.strSize) 346 | err = binary.Read(file, binary.LittleEndian, &b) 347 | if err != nil { 348 | return err 349 | } 350 | err = t.BuildStringStream(b) 351 | if err != nil { 352 | return err 353 | } 354 | 355 | b = make([]byte, 8*t.head.groupIndexCount) 356 | err = binary.Read(file, binary.LittleEndian, &b) 357 | if err != nil { 358 | return err 359 | } 360 | pvfDecrypt(b, "grpi") 361 | t.group = make([]RDARGroup, t.head.groupIndexCount) 362 | err = binary.Read(bytes.NewBuffer(b), binary.LittleEndian, &t.group) 363 | if err != nil { 364 | return err 365 | } 366 | t.data = make([]byte, t.head.dataSize) 367 | err = binary.Read(file, binary.LittleEndian, &t.data) 368 | if err != nil { 369 | return err 370 | } 371 | return err 372 | } 373 | 374 | func (t *RDARScript) TestFile(filename string) { 375 | for _, v := range t.entities { 376 | _ = t.GetStringByOffset(v.PathOffset) 377 | name := t.GetStringByOffset(v.NameOffset) 378 | if v.Type == 1 { 379 | if strings.HasSuffix(name, filename) { 380 | groupData := t.GetGroupData(v.GroupIndex) 381 | b := groupData[v.InnerOffset : v.InnerOffset+v.Size] 382 | t.DecompileScript(b) 383 | } 384 | } else if v.Type == 3 { 385 | } else { 386 | log.Println("Bad File Type:", v.Type) 387 | } 388 | } 389 | } 390 | 391 | func (t *RDARScript) Extra(root string) { 392 | go func() { 393 | total := len(t.entities) 394 | for { 395 | log.Println(curcnt, "/", total, cur) 396 | time.Sleep(time.Second) 397 | if curcnt+1 >= total { 398 | break 399 | } 400 | } 401 | }() 402 | for index, v := range t.entities { 403 | path := t.GetStringByOffset(v.PathOffset) 404 | name := t.GetStringByOffset(v.NameOffset) 405 | var content []byte 406 | cur = fmt.Sprintf("%s/%s\n", path, name) 407 | curcnt = index 408 | groupData := t.GetGroupData(v.GroupIndex) 409 | b := groupData[v.InnerOffset : v.InnerOffset+v.Size] 410 | if v.Type == 1 { 411 | content = []byte(t.DecompileScript(b)) 412 | } else if v.Type == 3 { 413 | content = b 414 | } else { 415 | log.Println("Bad File Type:", v.Type) 416 | } 417 | 418 | err := os.MkdirAll(root+path, 0755) 419 | if err != nil { 420 | log.Println() 421 | continue 422 | } 423 | 424 | f, err := os.Create(root + path + "/" + name) 425 | if err != nil { 426 | log.Println() 427 | continue 428 | } 429 | f.Write(content) 430 | f.Close() 431 | } 432 | } 433 | 434 | func (t *RDARScript) Build(srcroot string, objroot string, filename string) { 435 | } 436 | 437 | func (t *RDARScript) Rebuild(srcroot string, objroot string, filename string) { 438 | } 439 | 440 | func fooCN() { 441 | var script RDARScript 442 | 443 | err := script.ParsePVF("./testdata/Script_CN.pvf") 444 | if err != nil { 445 | return 446 | } 447 | script.TestFile("monstername.lst") 448 | //script.Extra("F:/pvf_extra_170620/") 449 | } 450 | 451 | func main() { 452 | fooCN() 453 | } 454 | --------------------------------------------------------------------------------