1
+ #include < nana/gui.hpp>
2
+ #include < nana/gui/widgets/label.hpp>
3
+ #include < nana/gui/filebox.hpp>
4
+ #include < nana/gui/widgets/button.hpp>
5
+ #include < nana/gui/widgets/progress.hpp>
6
+ #include < nana/gui/msgbox.hpp>
7
+
8
+ #include < iostream>
9
+ #include < fstream>
10
+ #include < thread>
11
+ #include < atomic>
12
+
13
+ using std::cout;
14
+ using std::endl;
15
+
16
+ class ftca_form : public nana ::form
17
+ {
18
+ nana::label l_in, l_inpath, l_out, l_outpath;
19
+ nana::button btn_in, btn_out, btn_gen;
20
+ nana::progress prog;
21
+
22
+ std::filesystem::path inpath, outpath;
23
+ int line_chars_max{120 };
24
+ std::atomic<bool > working{false }, abort{false };
25
+ const char *gen_text{" Generate C array" };
26
+
27
+ public:
28
+
29
+ ftca_form () : nana::form(nana::API::make_center(600 , 185 ), appear::decorate<appear::minimize>())
30
+ {
31
+ nana::place &plc{get_place ()};
32
+ const auto bg{nana::colors::white};
33
+
34
+ nana::API::track_window_size (handle (), {600 , 185 }, false );
35
+ caption (" File To C Array" );
36
+ bgcolor (bg);
37
+
38
+ div (" vert margin=15 < weight=20 <l_in weight=70><weight=15><l_inpath><weight=15><btn_in weight=20> >"
39
+ " <weight=15> < weight=20 <l_out weight=70><weight=15><l_outpath><weight=15><btn_out weight=20> >"
40
+ " <weight=15> <prog weight=30> <weight=15> <btn_gen weight=40>"
41
+ );
42
+
43
+ l_in.create (handle (), true );
44
+ l_in.caption (" Input file:" );
45
+ l_in.bgcolor (bg);
46
+ l_in.text_align (nana::align::right, nana::align_v::center);
47
+ plc[" l_in" ] << l_in;
48
+
49
+ l_inpath.create (handle (), true );
50
+ l_inpath.bgcolor (nana::color{" #eef6ee" });
51
+ l_inpath.text_align (nana::align::center, nana::align_v::center);
52
+ l_inpath.caption (" Select a file you want to make a C array out of." );
53
+ plc[" l_inpath" ] << l_inpath;
54
+
55
+ btn_in.create (handle (), true );
56
+ btn_in.caption (" ..." );
57
+ btn_in.bgcolor (bg);
58
+ plc[" btn_in" ] << btn_in;
59
+
60
+ l_out.create (handle (), true );
61
+ l_out.caption (" Output file:" );
62
+ l_out.bgcolor (bg);
63
+ l_out.text_align (nana::align::right, nana::align_v::center);
64
+ plc[" l_out" ] << l_out;
65
+
66
+ l_outpath.create (handle (), true );
67
+ l_outpath.bgcolor (nana::color{" #eef6ee" });
68
+ l_outpath.text_align (nana::align::center, nana::align_v::center);
69
+ l_outpath.caption (" Choose which file you want to save the C array to." );
70
+ plc[" l_outpath" ] << l_outpath;
71
+
72
+ btn_out.create (handle (), true );
73
+ btn_out.caption (" ..." );
74
+ btn_out.bgcolor (bg);
75
+ plc[" btn_out" ] << btn_out;
76
+
77
+ btn_gen.create (handle (), true );
78
+ btn_gen.caption (gen_text);
79
+ btn_gen.bgcolor (nana::colors::white);
80
+ btn_gen.fgcolor (nana::color{" #406080" });
81
+ btn_gen.typeface ({typeface ().name (), 15 , nana::paint::font::font_style{800 }});
82
+ btn_gen.events ().mouse_enter ([this ] { btn_gen.fgcolor (nana::color{" #557799" }); });
83
+ btn_gen.events ().mouse_leave ([this ] { btn_gen.fgcolor (nana::color{" #406080" }); });
84
+ btn_gen.enabled (false );
85
+ plc[" btn_gen" ] << btn_gen;
86
+
87
+ prog.create (handle (), true );
88
+ prog.scheme ().gradient_bgcolor = nana::color{" #f5f5f5" };
89
+ prog.scheme ().gradient_fgcolor = nana::color{" #b7d3db" };
90
+ prog.scheme ().background = nana::color{" #e4e4e4" };
91
+ prog.scheme ().foreground = nana::color{" #64a3b5" };
92
+ plc[" prog" ] << prog;
93
+
94
+ collocate ();
95
+
96
+ btn_in.events ().click ([this ]
97
+ {
98
+ nana::filebox fb{handle (), true };
99
+ fb.title (" Select a file you want to make a C array out of" );
100
+ auto res = fb.show ();
101
+ if (!res.empty ())
102
+ {
103
+ inpath = res.front ();
104
+ if (inpath == outpath)
105
+ {
106
+ outpath.replace_filename (std::wstring{L" arr_" } + outpath.filename ().c_str ());
107
+ outpath.replace_extension (L" hpp" );
108
+ label_path_caption (l_outpath, outpath);
109
+ }
110
+ label_path_caption (l_inpath, inpath);
111
+ btn_gen.enabled (!inpath.empty () && !outpath.empty ());
112
+ }
113
+ });
114
+
115
+ btn_out.events ().click ([this ]
116
+ {
117
+ nana::filebox fb{handle (), false };
118
+ fb.title (" Choose which file you want to save the C array to." );
119
+ fb.init_file (" out.hpp" );
120
+ auto res = fb.show ();
121
+ if (!res.empty ())
122
+ {
123
+ outpath = res.front ();
124
+ if (inpath == outpath)
125
+ {
126
+ outpath.replace_filename (std::wstring{L" arr_" } + outpath.filename ().c_str ());
127
+ outpath.replace_extension (L" hpp" );
128
+ label_path_caption (l_outpath, outpath);
129
+ }
130
+ label_path_caption (l_outpath, outpath);
131
+ btn_gen.enabled (!inpath.empty () && !outpath.empty ());
132
+ }
133
+ });
134
+
135
+ btn_gen.events ().click ([this ]
136
+ {
137
+ if (working)
138
+ {
139
+ abort = true ;
140
+ while (working) std::this_thread::sleep_for (std::chrono::milliseconds{75 });
141
+ abort = false ;
142
+ std::filesystem::remove (outpath);
143
+ btn_gen.caption (gen_text);
144
+ prog.value (0 );
145
+ }
146
+ else
147
+ {
148
+ btn_gen.caption (" Abort" );
149
+ nana::API::refresh_window (btn_gen);
150
+ std::thread ([this ]
151
+ {
152
+ try { file_to_c_array (); }
153
+ catch (std::exception &e)
154
+ {
155
+ btn_gen.caption (gen_text);
156
+ working = false ;
157
+ nana::msgbox mbox{handle (), " Error" };
158
+ mbox << e.what ();
159
+ mbox.icon (nana::msgbox::icon_t ::icon_error);
160
+ mbox.show ();
161
+ }
162
+ }).detach ();
163
+ }
164
+ });
165
+
166
+ events ().unload ([this ]
167
+ {
168
+ if (working)
169
+ {
170
+ abort = true ;
171
+ while (working) std::this_thread::sleep_for (std::chrono::milliseconds{75 });
172
+ }
173
+ });
174
+ }
175
+
176
+ private:
177
+
178
+ std::string make_valstr (char *buf, unsigned width) const
179
+ {
180
+ union uint_t
181
+ {
182
+ uint8_t uint8;
183
+ uint16_t uint16;
184
+ uint32_t uint32;
185
+ uint64_t uint64;
186
+ };
187
+
188
+ auto pval = reinterpret_cast <uint_t *>(buf);
189
+ std::stringstream ss;
190
+
191
+ switch (width)
192
+ {
193
+ case 8 :
194
+ if (pval->uint64 > 999'999'999'999u )
195
+ ss << std::hex << std::showbase << pval->uint64 ;
196
+ else ss << pval->uint64 ;
197
+ break ;
198
+
199
+ case 4 :
200
+ ss << pval->uint32 ;
201
+ break ;
202
+
203
+ case 2 :
204
+ ss << pval->uint16 ;
205
+ break ;
206
+
207
+ case 1 :
208
+ ss << std::to_string (pval->uint8 );
209
+ break ;
210
+ }
211
+
212
+ return ss.str ();
213
+ }
214
+
215
+ void file_to_c_array ()
216
+ {
217
+ working = true ;
218
+ if (!std::filesystem::exists (inpath))
219
+ throw (std::exception{" Input file does not exist!" });
220
+ auto insize = std::filesystem::file_size (inpath);
221
+ unsigned width = sizeof (uint64_t );
222
+ while (insize % width) width /= 2 ;
223
+ auto buf{std::make_unique<char []>(width)};
224
+ const int prog_steps{568 };
225
+ prog.amount (prog_steps);
226
+ prog.value (0 );
227
+ uintmax_t prog_step{0 }, step_treshold{0 };
228
+ if (insize >= 10000 )
229
+ {
230
+ prog_step = insize / prog_steps;
231
+ step_treshold = prog_step;
232
+ }
233
+
234
+ std::ifstream infile{inpath, std::ios::binary};
235
+ if (!infile.good ()) throw (std::exception{" Failed to open the input file!" });
236
+ std::ofstream outfile{outpath};
237
+ if (!outfile.good ()) throw (std::exception{" Failed to open the output file!" });
238
+
239
+ auto name{" arr_" + inpath.filename ().generic_u8string ()};
240
+ for (auto &c : name) if (!isalnum (c)) c = ' _' ;
241
+
242
+ outfile << " #include <cstdint>\n\n " ;
243
+ if (width > 1 ) outfile << " // length in bytes: " << insize << " \n " ;
244
+ outfile << " const uint" << std::to_string (width*8 ) << " _t " << name << ' [' << std::to_string (insize/width) << " ] = {" ;
245
+ if (line_chars_max) outfile << " \n\t " ;
246
+ size_t line_chars{0 };
247
+
248
+ while (infile.read (buf.get (), width))
249
+ {
250
+ auto elstr{make_valstr (buf.get (), width) + ' ,' };
251
+ if (line_chars_max)
252
+ {
253
+ line_chars += elstr.size ();
254
+ if (line_chars > line_chars_max)
255
+ {
256
+ line_chars = elstr.size ();
257
+ outfile << " \n\t " ;
258
+ }
259
+ }
260
+ outfile << elstr;
261
+ if (prog_step && infile.tellg () >= step_treshold)
262
+ {
263
+ step_treshold += prog_step;
264
+ prog.inc ();
265
+ }
266
+ if (abort) { working = false ; return ; }
267
+ }
268
+
269
+ if (infile.bad ()) throw (std::exception{" Failed trying to read the input file!" });
270
+
271
+ outfile.seekp (static_cast <std::streamoff>(outfile.tellp ())-1 );
272
+ if (line_chars_max) outfile << ' \n ' ;
273
+ outfile << " };" ;
274
+ btn_gen.caption (gen_text);
275
+ working = false ;
276
+ }
277
+
278
+ void label_path_caption (nana::label &l, const std::filesystem::path &p)
279
+ {
280
+ l.caption (p);
281
+ int offset = 0 ;
282
+ while (l.measure (1234 ).width > l.size ().width )
283
+ {
284
+ offset += 6 ;
285
+ l.caption (L" ..." + std::wstring{p.c_str ()}.substr (offset));
286
+ }
287
+ }
288
+ };
0 commit comments