| 1 | module embed_file |
| 2 | |
| 3 | // EmbedFileData encapsulates functionality for the `$embed_file()` compile time call. |
| 4 | pub struct EmbedFileData { |
| 5 | apath string |
| 6 | compression_type string |
| 7 | mut: |
| 8 | compressed &u8 = unsafe { nil } |
| 9 | uncompressed &u8 = unsafe { nil } |
| 10 | free_compressed bool |
| 11 | free_uncompressed bool |
| 12 | pub: |
| 13 | len int |
| 14 | path string |
| 15 | } |
| 16 | |
| 17 | pub fn (ed EmbedFileData) str() string { |
| 18 | return 'embed_file.EmbedFileData{ len: ${ed.len}, path: "${ed.path}", apath: "${ed.apath}", uncompressed: ${ptr_str(ed.uncompressed)} }' |
| 19 | } |
| 20 | |
| 21 | @[unsafe] |
| 22 | pub fn (mut ed EmbedFileData) free() { |
| 23 | unsafe { |
| 24 | ed.path.free() |
| 25 | ed.apath.free() |
| 26 | ed.compression_type.free() |
| 27 | if ed.free_compressed { |
| 28 | free(ed.compressed) |
| 29 | ed.compressed = &u8(nil) |
| 30 | } |
| 31 | if ed.free_uncompressed { |
| 32 | free(ed.uncompressed) |
| 33 | ed.uncompressed = &u8(nil) |
| 34 | } |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | pub fn (original &EmbedFileData) to_string() string { |
| 39 | unsafe { |
| 40 | mut ed := &EmbedFileData(original) |
| 41 | the_copy := &u8(memdup(ed.data(), ed.len)) |
| 42 | return the_copy.vstring_with_len(ed.len) |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | pub fn (original &EmbedFileData) to_bytes() []u8 { |
| 47 | unsafe { |
| 48 | mut ed := &EmbedFileData(original) |
| 49 | the_copy := memdup(ed.data(), ed.len) |
| 50 | return the_copy.vbytes(ed.len) |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | pub fn (mut ed EmbedFileData) data() &u8 { |
| 55 | if ed.uncompressed != unsafe { nil } { |
| 56 | return ed.uncompressed |
| 57 | } |
| 58 | if ed.uncompressed == unsafe { nil } && ed.compressed != unsafe { nil } { |
| 59 | decoder := g_embed_file_decoders.decoders[ed.compression_type] or { |
| 60 | panic('EmbedFileData error: unknown compression of "${ed.path}": "${ed.compression_type}"') |
| 61 | } |
| 62 | compressed := unsafe { ed.compressed.vbytes(ed.len) } |
| 63 | decompressed := decoder.decompress(compressed) or { |
| 64 | panic('EmbedFileData error: decompression of "${ed.path}" failed: ${err}') |
| 65 | } |
| 66 | unsafe { |
| 67 | ed.uncompressed = &u8(memdup(decompressed.data, ed.len)) |
| 68 | } |
| 69 | } else { |
| 70 | $if !freestanding { |
| 71 | reload_from_file_at_runtime(mut ed) |
| 72 | } |
| 73 | } |
| 74 | return ed.uncompressed |
| 75 | } |
| 76 | |
| 77 | ////////////////////////////////////////////////////////////////////////////// |
| 78 | // EmbedFileIndexEntry is used internally by the V compiler when you compile a |
| 79 | // program that uses $embed_file('file.bin') in -prod mode. |
| 80 | // V will generate a static index of all embedded files, and will call the |
| 81 | // find_index_entry_by_path over the index and the relative paths of the embeds. |
| 82 | // Note: these are public on purpose, to help -usecache. |
| 83 | pub struct EmbedFileIndexEntry { |
| 84 | id int |
| 85 | path string |
| 86 | algo string |
| 87 | data &u8 = unsafe { nil } |
| 88 | } |
| 89 | |
| 90 | // find_index_entry_by_path is used internally by the V compiler: |
| 91 | @[markused] |
| 92 | pub fn find_index_entry_by_path(start voidptr, path string, algo string) &EmbedFileIndexEntry { |
| 93 | unsafe { |
| 94 | mut x := &EmbedFileIndexEntry(start) |
| 95 | for x.id >= 0 && x.data != 0 && (x.algo != algo || x.path != path) { |
| 96 | x++ |
| 97 | } |
| 98 | $if trace_embed_file ? { |
| 99 | eprintln('>> v.embed_file find_index_entry_by_path ${ptr_str(start)}, id: ${x.id}, path: "${path}", algo: "${algo}" => ${ptr_str(x)}') |
| 100 | } |
| 101 | return x |
| 102 | } |
| 103 | } |
| 104 | |