1 | /********************************************************************** |
2 | * |
3 | * File scanner |
4 | * |
5 | * Copyright (c) 2021 Dario Deledda. All rights reserved. |
6 | * Use of this source code is governed by an MIT license |
7 | * that can be found in the LICENSE file. |
8 | * |
9 | * TODO: |
10 | **********************************************************************/ |
11 | import os |
12 | |
13 | // STBI supported format |
14 | // STBI_NO_JPEG * |
15 | // STBI_NO_PNG * |
16 | // STBI_NO_BMP * |
17 | // STBI_NO_PSD |
18 | // STBI_NO_TGA * |
19 | // STBI_NO_GIF * |
20 | // STBI_NO_HDR * |
21 | // STBI_NO_PIC * |
22 | // STBI_NO_PNM * |
23 | |
24 | /****************************************************************************** |
25 | * |
26 | * Struct and Enums |
27 | * |
28 | ******************************************************************************/ |
29 | enum Item_type { |
30 | file = 0 |
31 | folder |
32 | // archive format |
33 | zip = 16 |
34 | archive_file |
35 | // graphic format, MUST stay after the other types!! |
36 | bmp = 32 |
37 | jpg |
38 | png |
39 | gif |
40 | tga |
41 | ppm |
42 | pgm |
43 | pic |
44 | hdr |
45 | } |
46 | |
47 | pub struct Item { |
48 | pub mut: |
49 | path string |
50 | name string |
51 | size u64 |
52 | i_type Item_type = .file |
53 | container_index int // used if the item is in a container (.zip, .rar, etc) |
54 | container_item_index int // index in the container if the item is contained |
55 | need_extract bool // if true need to extraction from the container |
56 | drawable bool // if true the image can be showed |
57 | n_item int // |
58 | rotation int // number of rotation of PI/2 |
59 | } |
60 | |
61 | struct Item_list { |
62 | pub mut: |
63 | lst []Item |
64 | path_sep string |
65 | item_index int = -1 // image currently shown |
66 | n_item int // number of images scanned |
67 | loaded bool // flag that indicate that the list is ready to be used |
68 | } |
69 | |
70 | /****************************************************************************** |
71 | * |
72 | * Utility functions |
73 | * |
74 | ******************************************************************************/ |
75 | [inline] |
76 | fn modulo(x int, n int) int { |
77 | return (x % n + n) % n |
78 | } |
79 | |
80 | [inline] |
81 | fn get_extension(x string) Item_type { |
82 | // 4 char extension check |
83 | if x.len > 4 { |
84 | ext4 := x[x.len - 4..].to_lower() |
85 | match ext4 { |
86 | // containers |
87 | '.zip' { return .zip } |
88 | // graphic formats |
89 | '.jpg' { return .jpg } |
90 | '.png' { return .png } |
91 | '.bmp' { return .bmp } |
92 | '.gif' { return .gif } |
93 | '.tga' { return .tga } |
94 | '.ppm' { return .ppm } |
95 | '.pgm' { return .pgm } |
96 | '.pic' { return .pic } |
97 | '.hdr' { return .hdr } |
98 | else {} |
99 | } |
100 | } |
101 | // 5 char extension check |
102 | if x.len > 5 { |
103 | ext5 := x[x.len - 5..].to_lower() |
104 | if ext5 == '.jpeg' { |
105 | { |
106 | return .jpg |
107 | } |
108 | } |
109 | } |
110 | return .file |
111 | } |
112 | |
113 | [inline] |
114 | fn is_image(x Item_type) bool { |
115 | if int(x) >= int(Item_type.bmp) { |
116 | return true |
117 | } |
118 | return false |
119 | } |
120 | |
121 | [inline] |
122 | fn is_container(x Item_type) bool { |
123 | if x in [.zip, .folder] { |
124 | return true |
125 | } |
126 | return false |
127 | } |
128 | |
129 | [inline] |
130 | fn (item_list Item_list) is_inside_a_container() bool { |
131 | if item_list.lst.len <= 0 || item_list.n_item <= 0 { |
132 | return false |
133 | } |
134 | return item_list.lst[item_list.item_index].need_extract |
135 | } |
136 | |
137 | [inline] |
138 | fn (item_list Item_list) get_file_path() string { |
139 | if item_list.lst.len <= 0 || item_list.n_item <= 0 { |
140 | return '' |
141 | } |
142 | if item_list.lst[item_list.item_index].path.len > 0 { |
143 | return '${item_list.lst[item_list.item_index].path}${item_list.path_sep}${item_list.lst[item_list.item_index].name}' |
144 | } |
145 | return item_list.lst[item_list.item_index].name |
146 | } |
147 | |
148 | /****************************************************************************** |
149 | * |
150 | * Scan functions |
151 | * |
152 | ******************************************************************************/ |
153 | fn (mut item_list Item_list) scan_folder(path string, in_index int) ! { |
154 | println('Scanning [${path}]') |
155 | mut folder_list := []string{} |
156 | lst := os.ls(path)! |
157 | |
158 | // manage the single files |
159 | for c, x in lst { |
160 | pt := '${path}${item_list.path_sep}${x}' |
161 | mut item := Item{ |
162 | path: path |
163 | name: x |
164 | container_index: in_index |
165 | container_item_index: c |
166 | } |
167 | if os.is_dir(pt) { |
168 | folder_list << x |
169 | } else { |
170 | ext := get_extension(x) |
171 | if ext == .zip { |
172 | item.i_type = .zip |
173 | item_list.lst << item |
174 | item_list.scan_zip(pt, item_list.lst.len - 1)! |
175 | continue |
176 | } |
177 | if is_image(ext) == true { |
178 | item_list.n_item += 1 |
179 | item.n_item = item_list.n_item |
180 | item.i_type = ext |
181 | item.drawable = true |
182 | item_list.lst << item |
183 | continue |
184 | } |
185 | } |
186 | } |
187 | |
188 | // manage the folders |
189 | for x in folder_list { |
190 | pt := '${path}${item_list.path_sep}${x}' |
191 | item := Item{ |
192 | path: path |
193 | name: x |
194 | i_type: .folder |
195 | } |
196 | item_list.lst << item |
197 | item_list.scan_folder(pt, item_list.lst.len - 1)! |
198 | } |
199 | // println(item_list.lst.len) |
200 | // println("==================================") |
201 | } |
202 | |
203 | fn (item_list Item_list) print_list() { |
204 | println('================================') |
205 | for x in item_list.lst { |
206 | if x.i_type == .folder { |
207 | print('[]') |
208 | } |
209 | if x.i_type == .zip { |
210 | print('[ZIP]') |
211 | } |
212 | println('${x.path} => ${x.container_index} ${x.container_item_index} ${x.name} ne:${x.need_extract}') |
213 | } |
214 | println('n_item: ${item_list.n_item} index: ${item_list.item_index}') |
215 | println('================================') |
216 | } |
217 | |
218 | fn (mut item_list Item_list) get_items_list(args []string) { |
219 | item_list.loaded = false |
220 | println('Args: ${args}') |
221 | |
222 | item_list.path_sep = $if windows { '\\' } $else { '/' } |
223 | for x in args { |
224 | // scan folder |
225 | if os.is_dir(x) { |
226 | mut item := Item{ |
227 | path: x |
228 | name: x |
229 | container_index: item_list.lst.len |
230 | i_type: .folder |
231 | } |
232 | item_list.lst << item |
233 | item_list.scan_folder(x, item_list.lst.len - 1) or { |
234 | eprintln('ERROR: scanning folder [${x}]!') |
235 | continue |
236 | } |
237 | } else { |
238 | mut item := Item{ |
239 | path: '' |
240 | name: x |
241 | container_index: -1 |
242 | } |
243 | ext := get_extension(x) |
244 | // scan .zip |
245 | if ext == .zip { |
246 | item.i_type = .zip |
247 | item_list.lst << item |
248 | item_list.scan_zip(x, item_list.lst.len - 1) or { |
249 | eprintln('ERROR: scanning zip [${x}]!') |
250 | continue |
251 | } |
252 | continue |
253 | } |
254 | // single images |
255 | if is_image(ext) == true { |
256 | item_list.n_item += 1 |
257 | item.n_item = item_list.n_item |
258 | item.i_type = ext |
259 | item.drawable = true |
260 | item_list.lst << item |
261 | continue |
262 | } |
263 | } |
264 | } |
265 | // debug call for list all the loaded items |
266 | // item_list.print_list() |
267 | |
268 | println('Items: ${item_list.n_item}') |
269 | println('Scanning done.') |
270 | |
271 | item_list.get_next_item(1) |
272 | item_list.loaded = true |
273 | } |
274 | |
275 | /****************************************************************************** |
276 | * |
277 | * Navigation functions |
278 | * |
279 | ******************************************************************************/ |
280 | fn (mut item_list Item_list) get_next_item(in_inc int) { |
281 | // if empty exit |
282 | if item_list.lst.len <= 0 || item_list.n_item <= 0 { |
283 | return |
284 | } |
285 | |
286 | inc := if in_inc > 0 { 1 } else { -1 } |
287 | mut i := item_list.item_index + in_inc |
288 | i = modulo(i, item_list.lst.len) |
289 | start := i |
290 | for { |
291 | if item_list.lst[i].drawable == true { |
292 | item_list.item_index = i |
293 | break |
294 | } |
295 | i = i + inc |
296 | i = modulo(i, item_list.lst.len) |
297 | // if we are in a loop break it |
298 | if i == start { |
299 | break |
300 | } |
301 | } |
302 | // println("Found: ${item_list.item_index}") |
303 | } |
304 | |
305 | fn (mut item_list Item_list) go_to_next_container(in_inc int) { |
306 | // if empty exit |
307 | if item_list.lst.len <= 0 || item_list.n_item <= 0 { |
308 | return |
309 | } |
310 | inc := if in_inc > 0 { 1 } else { -1 } |
311 | mut i := item_list.item_index + in_inc |
312 | i = modulo(i, item_list.lst.len) |
313 | start := i |
314 | for { |
315 | // check if we found a folder |
316 | if is_container(item_list.lst[i].i_type) == true |
317 | && i != item_list.lst[item_list.item_index].container_index { |
318 | item_list.item_index = i |
319 | item_list.get_next_item(1) |
320 | break |
321 | } |
322 | // continue to search |
323 | i = i + inc |
324 | i = modulo(i, item_list.lst.len) |
325 | // if we are in a loop break it |
326 | if i == start { |
327 | break |
328 | } |
329 | } |
330 | } |
331 | |
332 | /****************************************************************************** |
333 | * |
334 | * Other functions |
335 | * |
336 | ******************************************************************************/ |
337 | [inline] |
338 | fn (mut item_list Item_list) rotate(in_inc int) { |
339 | item_list.lst[item_list.item_index].rotation += in_inc |
340 | if item_list.lst[item_list.item_index].rotation >= 4 { |
341 | item_list.lst[item_list.item_index].rotation = 0 |
342 | } |
343 | } |