diff options
Diffstat (limited to 'res/Embed.cmake')
-rw-r--r-- | res/Embed.cmake | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/res/Embed.cmake b/res/Embed.cmake new file mode 100644 index 00000000..8da9e1d6 --- /dev/null +++ b/res/Embed.cmake | |||
@@ -0,0 +1,162 @@ | |||
1 | # CMake Helper for Binary Resources | ||
2 | # Copyright: 2020 Jaakko Keränen <jaakko.keranen@iki.fi> | ||
3 | # License: BSD 2-Clause | ||
4 | |||
5 | option (ENABLE_RESOURCE_EMBED "Embed resources inside the executable" OFF) | ||
6 | |||
7 | # Build "bincat" for concatenating files. | ||
8 | if (NOT ENABLE_RESOURCE_EMBED) | ||
9 | message (STATUS "Compiling bincat for merging resource files...") | ||
10 | set (_catDir ${CMAKE_BINARY_DIR}/res) | ||
11 | execute_process (COMMAND ${CMAKE_COMMAND} -E make_directory ${_catDir}) | ||
12 | execute_process (COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}/res WORKING_DIRECTORY ${_catDir}) | ||
13 | execute_process (COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${_catDir}) | ||
14 | set (BINCAT_COMMAND ${_catDir}/bincat) | ||
15 | endif () | ||
16 | |||
17 | function (embed_getname output fn) | ||
18 | get_filename_component (name ${fn} NAME_WE) | ||
19 | string (REPLACE "-" "" name ${name}) | ||
20 | string (REPLACE "=" "" name ${name}) | ||
21 | string (SUBSTRING ${name} 0 1 first) | ||
22 | string (TOUPPER ${first} first) | ||
23 | string (SUBSTRING ${name} 1 -1 remainder) | ||
24 | set (name "${first}${remainder}") | ||
25 | get_filename_component (ext ${fn} EXT) | ||
26 | if (ext STREQUAL .ttf) | ||
27 | set (resName "font") | ||
28 | elseif (ext STREQUAL .png) | ||
29 | set (resName "image") | ||
30 | else () | ||
31 | set (resName "blob") | ||
32 | endif () | ||
33 | set (resName "${resName}${name}_Embedded" PARENT_SCOPE) | ||
34 | endfunction (embed_getname) | ||
35 | |||
36 | function (embed_write path name fnSource fnHeader) | ||
37 | message (STATUS "${path}") | ||
38 | file (READ ${path} fileData HEX) | ||
39 | string (REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," cList ${fileData}) | ||
40 | string (REGEX REPLACE | ||
41 | "(0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],0x[0-9a-f][0-9a-f],)" | ||
42 | "\\1\n " cList ${cList}) | ||
43 | string (LENGTH ${fileData} len) | ||
44 | math (EXPR alen "${len} / 2") | ||
45 | set (src "static const uint8_t bytes_${name}_[] = {\n") | ||
46 | string (APPEND src " ${cList}\n") | ||
47 | string (APPEND src "}; | ||
48 | static iBlockData data_${name}_ = { | ||
49 | .refCount = 2, .data = iConstCast(char *, bytes_${name}_), .size = ${alen}, .allocSize = ${alen} | ||
50 | }; | ||
51 | const iBlock ${name} = { &data_${name}_ }; | ||
52 | ") | ||
53 | set (header "extern const iBlock ${name};\n") | ||
54 | # Output the results. | ||
55 | file (APPEND ${fnSource} "${src}") | ||
56 | file (APPEND ${fnHeader} "${header}") | ||
57 | endfunction (embed_write) | ||
58 | |||
59 | function (embed_make) | ||
60 | set (EMB_H ${CMAKE_CURRENT_BINARY_DIR}/embedded.h) | ||
61 | set (EMB_C ${CMAKE_CURRENT_BINARY_DIR}/embedded.c) | ||
62 | if (ENABLE_RESOURCE_EMBED) | ||
63 | set (needGen NO) | ||
64 | if (NOT EXISTS ${EMB_H} OR NOT EXISTS ${EMB_C}) | ||
65 | set (needGen YES) | ||
66 | else () | ||
67 | file (TIMESTAMP ${EMB_H} genTime %s) | ||
68 | foreach (resPath ${ARGV}) | ||
69 | set (fn "${CMAKE_CURRENT_LIST_DIR}/${resPath}") | ||
70 | file (TIMESTAMP ${fn} resTime %s) | ||
71 | if (${resTime} GREATER ${genTime}) | ||
72 | set (needGen YES) | ||
73 | endif () | ||
74 | endforeach (resPath) | ||
75 | endif () | ||
76 | else () | ||
77 | set (needGen YES) | ||
78 | endif () | ||
79 | if (needGen) | ||
80 | if (ENABLE_RESOURCE_EMBED) | ||
81 | # Compose a source file with the resource data in an array. | ||
82 | file (WRITE ${EMB_H} "#include <the_Foundation/block.h>\n") | ||
83 | file (WRITE ${EMB_C} "#include \"embedded.h\"\n") | ||
84 | foreach (fn ${ARGV}) | ||
85 | embed_getname (resName ${fn}) | ||
86 | embed_write (${fn} ${resName} ${EMB_C} ${EMB_H}) | ||
87 | endforeach (fn) | ||
88 | else () | ||
89 | # Collect resources in a single binary file. | ||
90 | set (EMB_BIN ${CMAKE_CURRENT_BINARY_DIR}/resources.binary) | ||
91 | file (REMOVE ${EMB_BIN}) | ||
92 | list (LENGTH ARGV fileCount) | ||
93 | execute_process (COMMAND ${BINCAT_COMMAND} ${EMB_BIN} ${ARGV} | ||
94 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||
95 | OUTPUT_VARIABLE fileSizes | ||
96 | ) | ||
97 | set (offsets) | ||
98 | set (fpos 0) | ||
99 | foreach (fileSize ${fileSizes}) | ||
100 | list (APPEND offsets "${fpos}") | ||
101 | math (EXPR fpos "${fpos} + ${fileSize}") | ||
102 | endforeach (fileSize) | ||
103 | file (WRITE ${EMB_H} "#include <the_Foundation/block.h>\n | ||
104 | #define iHaveLoadEmbed 1 | ||
105 | iBool load_Embed(const char *path);\n\n") | ||
106 | file (WRITE ${EMB_C} [[ | ||
107 | #include "embedded.h" | ||
108 | #include <the_Foundation/file.h> | ||
109 | #include <the_Foundation/fileinfo.h> | ||
110 | |||
111 | iDeclareType(EmbedChunk) | ||
112 | |||
113 | struct Impl_EmbedChunk { | ||
114 | size_t pos; | ||
115 | size_t size; | ||
116 | }; | ||
117 | |||
118 | static const iEmbedChunk chunks_Embed_[] = { | ||
119 | ]]) | ||
120 | set (index 0) | ||
121 | foreach (fn ${ARGV}) | ||
122 | list (GET fileSizes ${index} fileSize) | ||
123 | list (GET offsets ${index} fpos) | ||
124 | file (APPEND ${EMB_C} " { ${fpos}, ${fileSize} },\n") | ||
125 | math (EXPR index "${index} + 1") | ||
126 | endforeach (fn) | ||
127 | file (APPEND ${EMB_C} "};\n\n") | ||
128 | foreach (fn ${ARGV}) | ||
129 | embed_getname (resName ${fn}) | ||
130 | file (APPEND ${EMB_H} "extern iBlock ${resName};\n") | ||
131 | file (APPEND ${EMB_C} "iBlock ${resName};\n") | ||
132 | endforeach (fn) | ||
133 | file (APPEND ${EMB_C} "\nstatic iBlock *blocks_Embed_[] = {\n") | ||
134 | foreach (fn ${ARGV}) | ||
135 | embed_getname (resName ${fn}) | ||
136 | file (APPEND ${EMB_C} " &${resName},\n") | ||
137 | endforeach (fn) | ||
138 | file (APPEND ${EMB_C} [[ | ||
139 | }; | ||
140 | |||
141 | iBool load_Embed(const char *path) { | ||
142 | const size_t fileSize = (size_t) fileSizeCStr_FileInfo(path); | ||
143 | iFile *f = iClob(newCStr_File(path)); | ||
144 | if (open_File(f, readOnly_FileMode)) { | ||
145 | iForIndices(i, blocks_Embed_) { | ||
146 | const iEmbedChunk *chunk = &chunks_Embed_[i]; | ||
147 | iBlock *data = blocks_Embed_[i]; | ||
148 | if (chunk->pos + chunk->size > fileSize) { | ||
149 | return iFalse; | ||
150 | } | ||
151 | init_Block(data, chunk->size); | ||
152 | seek_File(f, chunk->pos); | ||
153 | readData_File(f, chunk->size, data_Block(data)); | ||
154 | } | ||
155 | return iTrue; | ||
156 | } | ||
157 | return iFalse; | ||
158 | } | ||
159 | ]]) | ||
160 | endif () | ||
161 | endif () | ||
162 | endfunction (embed_make) | ||