1
- use std:: collections:: HashMap ;
1
+ use std:: collections:: { HashMap , HashSet } ;
2
2
use std:: ffi:: OsString ;
3
3
use std:: io:: Read ;
4
4
use std:: path:: { Path , PathBuf } ;
@@ -19,7 +19,7 @@ struct Config {
19
19
}
20
20
21
21
type AssetMap = HashMap < PathBuf , Vec < u8 > > ;
22
- type FolderMap = HashMap < OsString , bool > ;
22
+ type FolderSet = HashSet < OsString > ;
23
23
type ExtractTask = Vec < JoinHandle < Result < ( ) , io:: Error > > > ;
24
24
25
25
fn parse_arguments ( ) -> Config {
@@ -64,11 +64,11 @@ fn read_asset_to_memory<R: Read>(
64
64
mut entry : tar:: Entry < ' _ , R > ,
65
65
path : PathBuf ,
66
66
) -> Result < ( ) , io:: Error > {
67
- debug ! ( "reading asset to memory « {:?}» " , path) ;
67
+ debug ! ( "reading asset to memory {:?}" , path) ;
68
68
let mut asset_data = Vec :: new ( ) ;
69
69
entry. read_to_end ( & mut asset_data) ?;
70
70
trace ! (
71
- "saving « {:?}» with {} bytes to memory" ,
71
+ "saving {:?} with {} bytes to memory" ,
72
72
path,
73
73
asset_data. len( ) ,
74
74
) ;
@@ -77,22 +77,22 @@ fn read_asset_to_memory<R: Read>(
77
77
}
78
78
79
79
fn check_for_folders < R : Read > (
80
- folders : & mut FolderMap ,
80
+ folders : & mut FolderSet ,
81
81
mut entry : tar:: Entry < ' _ , R > ,
82
82
path : PathBuf ,
83
83
) -> Result < ( ) , io:: Error > {
84
- debug ! ( "reading asset to memory « {:?}» " , path) ;
84
+ debug ! ( "reading asset to memory {:?}" , path) ;
85
85
let mut metadata = String :: new ( ) ;
86
86
entry. read_to_string ( & mut metadata) ?;
87
87
if metadata. contains ( "folderAsset: yes\n " ) {
88
- folders. insert ( path. into_os_string ( ) , true ) ;
88
+ folders. insert ( path. into_os_string ( ) ) ;
89
89
}
90
90
Ok ( ( ) )
91
91
}
92
92
93
93
fn read_destination_path_and_write < R : Read > (
94
94
assets : & mut AssetMap ,
95
- folders : & FolderMap ,
95
+ folders : & FolderSet ,
96
96
tasks : & mut ExtractTask ,
97
97
mut entry : tar:: Entry < ' _ , R > ,
98
98
path : PathBuf ,
@@ -104,44 +104,49 @@ fn read_destination_path_and_write<R: Read>(
104
104
if let Some ( asset_data) = assets. remove ( & asset_path) {
105
105
tasks. push ( tokio:: spawn ( write_asset_to_pathname (
106
106
asset_data,
107
- path. clone ( ) ,
107
+ path. to_string_lossy ( ) . to_string ( ) ,
108
108
path_name,
109
109
) ) ) ;
110
110
} else {
111
111
let path_string = path. into_os_string ( ) ;
112
- if folders. contains_key ( & path_string) {
113
- warn ! ( "no asset data found for «{}» " , path_name. escape_default( ) ) ;
112
+ if folders. contains ( & path_string) {
113
+ warn ! ( "no asset data found for {} " , path_name. escape_default( ) ) ;
114
114
}
115
115
}
116
116
Ok ( ( ) )
117
117
}
118
118
119
119
async fn write_asset_to_pathname (
120
120
asset_data : Vec < u8 > ,
121
- entry_hash : PathBuf ,
121
+ entry_hash : String ,
122
122
path_name : String ,
123
123
) -> Result < ( ) , io:: Error > {
124
124
let target_path = sanitize_path:: sanitize_path ( & path_name) ?;
125
+ let asset_hash: & str ;
126
+
127
+ match entry_hash. find ( '/' ) {
128
+ Some ( idx) => {
129
+ ( asset_hash, _) = entry_hash. split_at ( idx) ;
130
+ }
131
+ None => {
132
+ asset_hash = & entry_hash;
133
+ }
134
+ }
125
135
126
136
if path_name != target_path {
127
- debug ! (
128
- "sanitizing path «{}» => «{}»" ,
129
- path_name. escape_default( ) ,
130
- target_path. escape_default( ) ,
131
- ) ;
137
+ debug ! ( "sanitizing path {:?} => {:?}" , path_name, target_path, ) ;
132
138
}
133
139
134
140
if let Some ( parent) = Path :: new ( & target_path) . parent ( ) {
135
141
fs:: create_dir_all ( parent) . await ?;
136
142
}
137
143
138
- info ! ( "extracting: «{:?}» to «{}» " , entry_hash , target_path) ;
144
+ info ! ( "extracting {} to {:?} " , asset_hash , target_path) ;
139
145
let file = fs:: File :: create ( & target_path) . await ?;
140
146
let mut file_writer = io:: BufWriter :: new ( file) ;
141
147
file_writer. write_all ( & asset_data) . await ?;
142
148
file_writer. flush ( ) . await ?;
143
-
144
- trace ! ( "done extracting «{:?}»" , entry_hash) ;
149
+ trace ! ( "{} is written to disk" , asset_hash) ;
145
150
Ok ( ( ) )
146
151
}
147
152
@@ -150,7 +155,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
150
155
let config = parse_arguments ( ) ;
151
156
SimpleLogger :: new ( ) . with_level ( config. log_level ) . init ( ) ?;
152
157
debug ! ( "opening unitypackage file at {}" , & config. input_path) ;
153
-
154
158
let file = std:: fs:: File :: open ( & config. input_path ) ;
155
159
156
160
if let Err ( err) = file {
@@ -161,7 +165,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
161
165
let decoder = GzDecoder :: new ( file?) ;
162
166
let mut archive = tar:: Archive :: new ( decoder) ;
163
167
let mut assets: AssetMap = HashMap :: new ( ) ;
164
- let mut folders: FolderMap = HashMap :: new ( ) ;
168
+ let mut folders: FolderSet = HashSet :: new ( ) ;
165
169
let mut tasks: ExtractTask = Vec :: new ( ) ;
166
170
167
171
debug ! ( "iterating archive's entries" ) ;
@@ -188,8 +192,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
188
192
check_for_folders ( & mut folders, entry, path) ?;
189
193
} else if path. ends_with ( "pathname" ) {
190
194
read_destination_path_and_write ( & mut assets, & folders, & mut tasks, entry, path) ?;
195
+ } else if path. ends_with ( "/" ) {
196
+ trace ! ( "skipping folder {}" , path. display( ) ) ;
191
197
} else {
192
- trace ! ( "skipping entry with name «{:?}» " , path)
198
+ trace ! ( "skipping entry with name {} " , path. display ( ) )
193
199
}
194
200
}
195
201
0 commit comments