/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- pouziti
- inicializace_pole
- spocti_cetnosti
- nejvetsi_cetnost
- najdi_nejmensi
- najdi_koren
- vytvor_strom
- merak_cb
- zapis_kod
- nacti_kod
- zapis_data
- komprese
- dekomprese
- f_ch_b_file_set_cb
- quit_cb
- komprese_cb
- dekomprese_cb
- about_cb
- main
1 #include "main.h"
2
3 /**
4 * \brief Vypis napovedy
5 *
6 * Vypise do terminalu zpusob pouziti programu
7 * @param str Nazev programu - obvykle argv[0]
8 */
9 void pouziti(gchar *str)
10 {
11 g_print("Huffressor %s\n", VERZE);
12 g_print("Pouziti:\n%s [-cdg] [-v] [-i VSTUP] [-o VYSTUP]\n", str);
13 g_print("\t-c ....... komprese\n");
14 g_print("\t-d ....... dekomprese\n");
15 g_print("\t-g ....... graficke rozhrani (vychozi)\n");
16 g_print("\t-v ....... upovidany rezim\n");
17 //g_print("\t-V ....... debugovaci vypisy\n"); // Pri velkych souborech extremne pomale - radsi neukazovat :-)
18 g_print("\tVSTUP .... cesta ke vstupnimu souboru\n");
19 g_print("\tVYSTUP ... cesta k vystupnimu souboru\n");
20 }
21
22 /**
23 * \brief Inicializace pole cetnosti a stromu
24 *
25 * Nastavi vychozi hodnoty promennych v poli struktur pro vytvareni stromu
26 */
27 void inicializace_pole(void)
28 {
29 gint i;
30 gint j;
31
32 for (i = 0; i < VELIKOST_POLE; i++) {
33 pole[i].cetnost = 0;
34 if (i < 256) pole[i].znak = i;
35 else pole[i].znak = 0;
36 pole[i].spoj = -1;
37 pole[i].vetev1 = -1;
38 pole[i].vetev2 = -1;
39 for (j = 0; j < 256; j++) {
40 pole[i].kod[j] = '\0';
41 }
42 }
43 }
44
45 /**
46 * \brief Nacteni cetnosti ze vstupniho souboru
47 *
48 * Alokuje pamet pro vstupni a vystupni buffer, zkopiruje data vstupniho
49 * souboru a spocita cetnosti jednotlivych znaku, ktere uklada do pole.
50 * @param file Vstupni soubor
51 * @param data Struktura obsahujici pointery na graficke prvky
52 * @return
53 */
54 guchar *spocti_cetnosti(FILE *file, ChData *data)
55 {
56 glong i, j;
57 glong velikost;
58 glong precteno;
59 guchar *buffer;
60
61 fseek(file, 0L, SEEK_END); // Konec souboru
62 velikost = ftell(file);
63 if (vypisy > 0) printf("Velikost vstupniho souboru: %ld\n", velikost);
64
65 buffer = malloc(velikost);
66 if (buffer == NULL) {
67 fprintf(stderr, "Malo RAM\n\n");
68 if (grafika) gtk_label_set_label(GTK_LABEL(data->label_info), "Malo RAM\n\n");
69 return NULL;
70 }
71 fseek(file, 0L, SEEK_SET);
72 precteno = fread(buffer, sizeof(guchar), velikost, file);
73 if (vypisy > 0) printf("Precteno: %ld\n", precteno);
74
75 for (i = 0; i < precteno; i++) {
76 pole[buffer[i]].cetnost++; // Inkrement poctu vyskytu tohoo znaku
77 velikost_vstup++;
78 pocet_znaku++;
79 }
80
81 if (vypisy > 0) {
82 g_print("Tabulka cetnosti:\n");
83 g_print(" \t0\t1\t2\t3\t4\t5\t6\t7\n");
84 for (j = 0; j < 32; j++) {
85 g_print("%3ld", j * 8);
86 for (i = 0; i < 8; i++) {
87 if (pole[8 * j + i].cetnost == 0)
88 g_print("\t.");
89 else
90 g_print("\t%d", pole[8 * j + i].cetnost);
91 }
92 g_print("\t%ld\n", j * 8 + 7);
93 }
94 g_print(" \t0\t1\t2\t3\t4\t5\t6\t7\n");
95 }
96
97 return buffer;
98 }
99
100 /**
101 * \brief Nalezeni nejvyssi cetnosti
102 *
103 * Prohleda pole a najde nejvyssi cetnost vyskytu
104 * @return Nejvyssi cetnost
105 */
106 gint nejvetsi_cetnost()
107 {
108 gint i;
109 gint cetnost = 0;
110
111 for (i = 0; i < VELIKOST_POLE; i++) {
112 if (pole[i].cetnost > cetnost)
113 cetnost = pole[i].cetnost;
114 }
115
116 if (vypisy > 1) {
117 g_print("Maximalni cetnost: %d\n", cetnost);
118 }
119
120 return cetnost;
121 }
122
123 /**
124 * \brief Nalezeni uzlu s nejnizsi cetnosti
125 *
126 * Prohleda pole a najde uzel, ktery ma nejnizsi cetnost vyskytu
127 * @return Index uzlu s nejnizsim vyskytem
128 */
129 gint najdi_nejmensi()
130 {
131 gint i;
132 gint nejmensi = 0;
133 gint nejmensi_cetnost = nejvetsi_cetnost(); // Pro inicializaci nejvetsi cetnost uzlu
134
135 for (i = 0; i < VELIKOST_POLE; i++) {
136 if (pole[i].cetnost != 0 && pole[i].cetnost <= nejmensi_cetnost && pole[i].spoj == -1) {
137 nejmensi = i;
138 nejmensi_cetnost = pole[i].cetnost;
139 }
140 }
141
142 return nejmensi;
143 }
144
145 /**
146 * \brief Nalezeni korenoveho uzlu
147 *
148 * Prohleda pole a najde korenovy uzel, tedy uzel s nejnvyssi cetnosti vyskytu
149 * @return Index uzlu s nejvyssim vyskytem
150 */
151 gint najdi_koren()
152 {
153 gint i;
154 gint nejvetsi = 0;
155 gint nejvetsi_cetnost = 0;
156
157 for (i = 0; i < VELIKOST_POLE; i++) {
158 if (pole[i].cetnost > nejvetsi_cetnost) {
159 nejvetsi = i;
160 nejvetsi_cetnost = pole[i].cetnost;
161 }
162 }
163
164 return nejvetsi;
165 }
166
167 /**
168 * \brief Vytvoreni stromu
169 *
170 * Prochazi pole a spojovanim uzlu vytvari strom pro kodovani nebo dekodovani
171 * @param data Struktura obsahujici pointery na graficke prvky
172 * @return Vraci nulu, pokud nedoslo k chybe
173 */
174 gint vytvor_strom(ChData *data)
175 {
176 gint nejmensi;
177 gint dalsi_uzel = 256;
178 gint i;
179 gint j;
180 guchar tmp[256];
181 gint error = 0;
182
183 nejmensi = najdi_nejmensi();
184 while (pole[nejmensi].cetnost < pocet_znaku) {
185 pole[nejmensi].spoj = dalsi_uzel;
186 strcat(pole[nejmensi].kod, "1");
187 pole[dalsi_uzel].vetev1 = nejmensi;
188
189 nejmensi = najdi_nejmensi();
190 pole[nejmensi].spoj = dalsi_uzel;
191 strcat(pole[nejmensi].kod, "0");
192 pole[dalsi_uzel].vetev2 = nejmensi;
193
194 pole[dalsi_uzel].cetnost = pole[pole[dalsi_uzel].vetev1].cetnost + pole[pole[dalsi_uzel].vetev2].cetnost;
195
196 if (vypisy > 1) {
197 g_print("Uzel %d[%d] spojuje uzly %d[%d] a %d[%d]\n", dalsi_uzel, pole[dalsi_uzel].cetnost, pole[dalsi_uzel].vetev1, pole[pole[dalsi_uzel].vetev1].cetnost, pole[dalsi_uzel].vetev2, pole[pole[dalsi_uzel].vetev2].cetnost);
198 }
199
200 dalsi_uzel++;
201 nejmensi = najdi_nejmensi();
202 }
203
204 for (i = 0; i < 256; i++) {
205 if (pole[i].cetnost != 0) {
206 j = pole[i].spoj;
207 if (j < 0 || j > 512) {
208 fprintf(stderr, "Kriticka chyba pri vytvareni stromu\n");
209 if (grafika) gtk_label_set_label(GTK_LABEL(data->label_info), "Soubor nelze dekodovat");
210 error = 1;
211 break;
212 }
213 while (pole[j].spoj != -1) {
214 strcpy(tmp, pole[i].kod);
215 strcpy(pole[i].kod, pole[j].kod);
216 strcat(pole[i].kod, tmp);
217 j = pole[j].spoj;
218 }
219 if (vypisy > 1) {
220 isprint(pole[i].znak);
221 g_print("%c = %s\n", pole[i].znak, pole[i].kod);
222 }
223 }
224 }
225
226 return error;
227 }
228
229 /**
230 * \brief Mereni rychlosti a prubehu
231 *
232 * Meri a zobrazuje rychlost komprese v MB/s a prubeh zpracovani v %
233 * @param data Struktura obsahujici pointery na graficke prvky
234 * @return TRUE pokud vypocet pokracuje, FALSE po ukonceni
235 */
236 gboolean merak_cb(gpointer data)
237 {
238 glong diff = pro_merak - pro_merak_posledni;
239 gfloat speed;
240 ChData *chdata = (ChData*) data;
241 gchar buf[50];
242 gfloat prubeh;
243
244 pro_merak_posledni = pro_merak;
245
246 prubeh = (gfloat) pro_merak / (gfloat) pro_merak_celkem * 100;
247
248 if (diff == 0) {
249 if (grafika) gtk_label_set_label(GTK_LABEL(chdata->label_info), "Ukladam soubor");
250 if (grafika) gtk_statusbar_push(GTK_STATUSBAR(chdata->statusbar), gtk_statusbar_get_context_id(GTK_STATUSBAR(chdata->statusbar), "uvitani"), VERZE);
251
252 return FALSE;
253 } else {
254 speed = (gfloat) diff * 1000.0 / (gfloat) TIMEOUT / 1e6;
255 if (vypisy > 1) g_print("%s\n", buf);
256 sprintf(buf, "Zpracovano: %.1f%%", prubeh);
257 if (grafika) gtk_label_set_label(GTK_LABEL(chdata->label_info), buf);
258 sprintf(buf, "Aktualni rychlost: %.3fMB/s", speed);
259 if (grafika) gtk_statusbar_push(GTK_STATUSBAR(chdata->statusbar), gtk_statusbar_get_context_id(GTK_STATUSBAR(chdata->statusbar), "rychlost"), buf);
260 return TRUE;
261 }
262 }
263
264 /**
265 * \brief Zapise zakodovany soubor na vystup
266 *
267 * Vytvori hlavicku souboru a podle kodovaciho stromu zakoduje data z bufferu.
268 * Struktura hlavicky:\n
269 * 1B Pocet znaku v tabulce\n
270 * 1B znak 1\n
271 * 4B cetnost znaku 1\n
272 * 1B znak 2\n
273 * 4B cetnost znaku 2\n
274 * atd...
275 * @param buffer_in Pointer na data pro kompresi
276 * @param file Vystupni soubor
277 * @param data Struktura obsahujici pointery na graficke prvky
278 * @return 0 pokud nedojde k chybe
279 */
280 gint zapis_kod(guchar *buffer_in, FILE *file, ChData *data)
281 {
282 guchar *buffer;
283 gint znaku_v_tabulce = 0;
284 gint i;
285 glong velikost_bufferu;
286 guchar kod1[VELIKOST_BUFF];
287 guchar kod2[VELIKOST_BUFF];
288 guchar byte;
289 gint j;
290
291 velikost_bufferu = velikost_vstup + 256 * (sizeof(guchar) + sizeof(gint)) + 1;
292 buffer = malloc(velikost_bufferu);
293 if (buffer == NULL) {
294 fprintf(stderr, "Malo RAM\n");
295 if (grafika) gtk_label_set_label(GTK_LABEL(data->label_info), "Malo RAM\n");
296 return 1;
297 }
298 memset(buffer, 0, velikost_bufferu);
299
300 for (i = 0; i < 256; i++) {
301 if (pole[i].cetnost > 0) {
302 buffer[znaku_v_tabulce * 5 + 1] = pole[i].znak;
303 buffer[znaku_v_tabulce * 5 + 2] = (guchar) ((pole[i].cetnost >> 24) & 0x000000ff);
304 buffer[znaku_v_tabulce * 5 + 3] = (guchar) ((pole[i].cetnost >> 16) & 0x000000ff);
305 buffer[znaku_v_tabulce * 5 + 4] = (guchar) ((pole[i].cetnost >> 8) & 0x000000ff);
306 buffer[znaku_v_tabulce * 5 + 5] = (guchar) ((pole[i].cetnost >> 0) & 0x000000ff);
307 znaku_v_tabulce++;
308 }
309 }
310 if (znaku_v_tabulce == 0) {
311 buffer[0] = 0;
312 } else {
313 buffer[0] = (guchar) znaku_v_tabulce - 1;
314 }
315 hlavicka = znaku_v_tabulce * 5 + 1;
316 velikost_vystup = hlavicka;
317
318 pro_merak_celkem = velikost_vstup;
319 pro_merak = 0;
320 g_timeout_add(TIMEOUT, merak_cb, data);
321
322 memset(kod1, 0, VELIKOST_BUFF);
323 memset(kod2, 0, VELIKOST_BUFF);
324 for (i = 0; i < velikost_vstup; i++) {
325 strcat(kod1, pole[buffer_in[i]].kod);
326 while (strlen(kod1) >= 8) {
327 byte = 0x00;
328 for (j = 0; j < 8; j++) {
329 if (kod1[j] == '1') {
330 byte |= 0x80 >> j;
331 }
332 }
333 buffer[velikost_vystup] = byte;
334 velikost_vystup++;
335 strcpy(kod2, &kod1[8]);
336 strcpy(kod1, kod2);
337 pro_merak++;
338 }
339 }
340 if (strlen(kod1) > 0) {
341 byte = 0x00;
342 for (j = 0; j < 8; j++) {
343 if (kod1[j] == '1') {
344 byte |= 0x80 >> j;
345 } else if (kod1[j] == '\0') {
346 break;
347 }
348 }
349 buffer[velikost_vystup] = byte;
350 velikost_vystup++;
351 }
352
353 if (vypisy > 0) {
354 g_print("Velikost souboru pred kompresi: %ld\n", velikost_vstup);
355 g_print("Velikost souboru po kompresi: %ld\n", velikost_vystup);
356 g_print("Z toho hlavicka: %ld\n", hlavicka);
357 g_print("Relativni velikost vystupniho souboru: %f\n", (float) velikost_vystup / (float) velikost_vstup);
358 }
359
360
361 fwrite(buffer, sizeof(guchar), velikost_vystup, file);
362 free(buffer);
363
364 return 0;
365 }
366
367 /**
368 * \brief Nacte zakodovany soubor
369 *
370 * Alokuje buffer a nacte zakodovany soubor. Z hlavicky inicializuje pole pro
371 * kodovaci strom. Prvni faze kontroly souboru na vyskyt chyb.
372 * @param file Vstupni soubor
373 * @param data Struktura obsahujici pointery na graficke prvky
374 * @return Pointer na buffer nactenych dat
375 */
376 guchar *nacti_kod(FILE *file, ChData *data)
377 {
378 guchar *buffer;
379 glong velikost;
380 glong precteno;
381 gint i;
382 gint znaku_v_tabulce;
383
384 fseek(file, 0L, SEEK_END); // Konec souboru
385 velikost = ftell(file);
386 if (vypisy > 0) g_print("Velikost vstupniho souboru: %ld\n", velikost);
387
388 buffer = malloc(velikost);
389 if (buffer == NULL) {
390 fprintf(stderr, "Malo RAM\n");
391 if (grafika) gtk_label_set_label(GTK_LABEL(data->label_info), "Malo RAM\n");
392 return NULL;
393 }
394 fseek(file, 0L, SEEK_SET);
395 precteno = fread(buffer, sizeof(guchar), velikost, file);
396 if (vypisy > 0) g_print("Precteno: %ld\n", precteno);
397 velikost_vstup = precteno;
398
399 if (velikost < 2) { // Jinak rozbalujeme prazdny soubor
400 znaku_v_tabulce = 0;
401 } else {
402 znaku_v_tabulce = buffer[0] + 1;
403 }
404
405 for (i = 0; i < znaku_v_tabulce; i++) {
406 if (5 * i + 5 > precteno) {
407 fprintf(stderr, "Soubor pravdepodobne nebyl komprimovan Huffressorem\n");
408 znaku_v_tabulce = 0; // Aby nic nedelal
409 pocet_znaku = 0; // Aby nic nedelal
410 }
411 pole[buffer[5 * i + 1]].cetnost = (((gint) buffer[5 * i + 2]) << 24) & 0xff000000;
412 pole[buffer[5 * i + 1]].cetnost |= (((gint) buffer[5 * i + 3]) << 16) & 0x00ff0000;
413 pole[buffer[5 * i + 1]].cetnost |= (((gint) buffer[5 * i + 4]) << 8) & 0x0000ff00;
414 pole[buffer[5 * i + 1]].cetnost |= (((gint) buffer[5 * i + 5]) << 0) & 0x000000ff;
415 pocet_znaku += pole[buffer[5 * i + 1]].cetnost;
416 }
417 hlavicka = znaku_v_tabulce * 5 + 1;
418
419 if (vypisy > 0) {
420 g_print("Velikost hlavicky: %ld\n", hlavicka);
421 }
422
423 return buffer;
424 }
425
426 /**
427 * \brief Zapis dekodovanych dat
428 *
429 * Podle binarniho stromu dekoduje vstupni buffer a zapise data do vystupniho
430 * souboru. Druha faze kontroly chyb.
431 * @param buffer_in Buffer zakodovanych dat
432 * @param file Vystupni soubor
433 * @param data Struktura obsahujici pointery na graficke prvky
434 * @return 0 pokud nedoslo k chybe
435 */
436 gint zapis_data(guchar *buffer_in, FILE *file, ChData *data)
437 {
438 guchar byte;
439 gint koren;
440 guchar *buffer;
441 glong i = 0;
442 gint j;
443 gint k = -1;
444 glong pozice = hlavicka; // Prvni byte dat
445
446 buffer = malloc(pocet_znaku);
447 if (buffer == NULL) {
448 fprintf(stderr, "Malo RAM\n");
449 if (grafika) gtk_label_set_label(GTK_LABEL(data->label_info), "Malo RAM\n");
450 return 1;
451 }
452
453 pro_merak_celkem = pocet_znaku;
454 pro_merak = 0;
455 g_timeout_add(TIMEOUT, merak_cb, data);
456
457 koren = najdi_koren(); // Vychozi uzel
458 while (i < pocet_znaku) {
459 j = koren;
460 do {
461 if (k == -1) { // Zpracovani dalsiho bytu
462 if (pozice >= velikost_vstup) {
463 fprintf(stderr, "Soubor poskozen, nebo nebyl komprimovan Huffressorem\n");
464 return 1;
465 }
466 byte = buffer_in[pozice++];
467 k = 7;
468 }
469 if ((byte >> k) & 0x01) {
470 j = pole[j].vetev1;
471 if (vypisy > 1) printf("1");
472 } else {
473 j = pole[j].vetev2;
474 if (vypisy > 1) printf("0");
475 }
476 k--;
477 } while (pole[j].vetev1 != -1); // Dosli jsme ke znaku
478 buffer[i] = pole[j].znak;
479 i++;
480 if (vypisy > 1) printf(" = %c\n", pole[j].znak);
481 pro_merak++;
482 }
483
484 fwrite(buffer, sizeof(gchar), pocet_znaku, file);
485 free(buffer);
486
487 return 0;
488 }
489
490 /**
491 * \brief Hlavni funkce komprese
492 *
493 * Otevre vstupni a vystupni soubory a vola funkce provadejici jednotlive kroky
494 * komprese. Nakonec uzavira soubory a uvolnuje alokovany buffer.
495 * @param data Struktura obsahujici pointery na graficke prvky
496 * @return 0 pokud nedojde k chybe
497 */
498 gint komprese(gpointer data)
499 {
500 guchar *buffer_in;
501 FILE *in;
502 FILE *out;
503 gchar *f_name_in = ((ChData*) data)->f_in;
504 gchar *f_name_out = ((ChData*) data)->f_out;
505
506 pocet_znaku = 0;
507 velikost_vstup = 0;
508 velikost_vystup = 0;
509
510 in = fopen(f_name_in, "rb");
511 if (in == NULL) {
512 fprintf(stderr, "Nepodarilo se otevrit %s\n", f_name_in);
513 return -1;
514 }
515 out = fopen(f_name_out, "wb");
516 if (out == NULL) {
517 fprintf(stderr, "Nepodarilo se otevrit %s\n", f_name_out);
518 return -1;
519 }
520
521 inicializace_pole();
522 if ((buffer_in = spocti_cetnosti(in, data)) == NULL) return 1;
523 if (vytvor_strom(data)) {
524 free(buffer_in);
525 return 1;
526 }
527 if (zapis_kod(buffer_in, out, data)) {
528 free(buffer_in);
529 return 1;
530 }
531
532 free(buffer_in);
533 fclose(in);
534 fclose(out);
535
536 if (grafika) gtk_label_set_label(GTK_LABEL(((ChData *) data)->label_info), "Uspesne dokonceno");
537
538 return 0;
539 }
540
541 /**
542 * \brief Hlavni funkce dekomprese
543 *
544 * Otevre vstupni a vystupni soubory a vola funkce provadejici jednotlive kroky
545 * dekomprese. Nakonec uzavira soubory a uvolnuje alokovany buffer.
546 * @param data Struktura obsahujici pointery na graficke prvky
547 * @return 0 pokud nedojde k chybe
548 */
549 gint dekomprese(gpointer data)
550 {
551 guchar *buffer_in;
552 FILE *in;
553 FILE *out;
554 gchar *f_name_in = ((ChData*) data)->f_in;
555 gchar *f_name_out = ((ChData*) data)->f_out;
556
557 pocet_znaku = 0;
558 velikost_vstup = 0;
559 velikost_vystup = 0;
560
561 in = fopen(f_name_in, "rb");
562 if (in == NULL) {
563 fprintf(stderr, "Nepodarilo se otevrit %s\n", f_name_in);
564 return -1;
565 }
566 out = fopen(f_name_out, "wb");
567 if (out == NULL) {
568 fprintf(stderr, "Nepodarilo se otevrit %s\n", f_name_out);
569 return -1;
570 }
571
572 inicializace_pole();
573 if ((buffer_in = nacti_kod(in, data)) == NULL) return 1;
574 if (vytvor_strom(data)) {
575 free(buffer_in);
576 return 1;
577 }
578 if (zapis_data(buffer_in, out, data)) {
579 free(buffer_in);
580 return 1;
581 }
582
583 free(buffer_in);
584 fclose(in);
585 fclose(out);
586
587 if (grafika) gtk_label_set_label(GTK_LABEL(((ChData *) data)->label_info), "Uspesne dokonceno");
588
589 return 0;
590 }
591
592 /**
593 * \brief Callback funkce widgetu vyber souboru
594 *
595 * Zpracuje nastaveny vstupni soubor, ulozi jeho nazev do struktury a podle
596 * pripony nastavi vystupni soubor.
597 * @param widget Pointer na tlacitko vyberu souboru
598 * @param data Struktura obsahujici pointery na graficke prvky
599 */
600 G_MODULE_EXPORT void f_ch_b_file_set_cb(GtkWidget *widget, ChData *data)
601 {
602 gchar buf[500];
603
604 data->f_in = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
605 g_print("%s\n", data->f_in);
606
607 if (strlen(data->f_in) > 4);
608 if (strcmp(&(data->f_in)[strlen(data->f_in) - 4], ".hcr") == 0) {
609 if (vypisy > 0) g_print("Vybran zabaleny soubor\n");
610 strcpy(buf, data->f_in);
611 buf[strlen(buf) - 4] = 0; // Urizne priponu
612 gtk_entry_set_text(GTK_ENTRY(data->entry_vystup), buf);
613 if (vypisy > 0) g_print("Vystupni soubor: %s\n", buf);
614 strcpy(data->f_out, buf);
615 } else {
616 if (vypisy > 0) g_print("Vybran neznamy soubor\n");
617 strcpy(buf, data->f_in);
618 strcat(buf, ".hcr");
619 gtk_entry_set_text(GTK_ENTRY(data->entry_vystup), buf);
620 if (vypisy > 0) g_print("Vystupni soubor: %s\n", buf);
621 strcpy(data->f_out, buf);
622 }
623 }
624
625 /**
626 * \brief Callback ukonceni programu
627 *
628 * Ukonci hlavni smycku GTK.
629 * @param widget Pointer na volajici widget
630 * @param data Struktura obsahujici pointery na graficke prvky
631 */
632 G_MODULE_EXPORT void quit_cb(GtkWidget *widget, ChData *data)
633 {
634 fprintf(stderr, "Koncim\n");
635 gtk_main_quit();
636 }
637
638 /**
639 * \brief Callback kliku na tlacitko komprese
640 *
641 * Nastavi informaci o spusteni komprese a spusti funkci komprese v novem
642 * vlaknu.
643 * @param widget Pointer na widget tlacitka
644 * @param data Struktura obsahujici pointery na graficke prvky
645 */
646 G_MODULE_EXPORT void komprese_cb(GtkWidget *widget, ChData *data)
647 {
648 if (vypisy > 0) g_print("Spustena komprese\n");
649 gtk_label_set_label(GTK_LABEL(data->label_info), "Nacitam soubor");
650
651 strcpy(data->f_out, gtk_entry_get_text(GTK_ENTRY(data->entry_vystup)));
652
653 if ((thread = g_thread_create((GThreadFunc) komprese, data, FALSE, &err)) == NULL) {
654 fprintf(stderr, "Spusteni threadu se nepovedlo: %s!\n", err->message);
655 g_error_free(err);
656 }
657 }
658
659 /**
660 * \brief Callback kliku na tlacitko dekomprese
661 *
662 * Nastavi informaci o spusteni dekomprese a spusti funkci dekomprese v novem
663 * vlaknu.
664 * @param widget Pointer na widget tlacitka
665 * @param data Struktura obsahujici pointery na graficke prvky
666 */
667 G_MODULE_EXPORT void dekomprese_cb(GtkWidget *widget, ChData *data)
668 {
669 if (vypisy > 0) g_print("Spustena dekomprese\n");
670 gtk_label_set_label(GTK_LABEL(data->label_info), "Nacitam soubor");
671
672 strcpy(data->f_out, gtk_entry_get_text(GTK_ENTRY(data->entry_vystup)));
673
674 if ((thread = g_thread_create((GThreadFunc) dekomprese, data, FALSE, &err)) == NULL) {
675 fprintf(stderr, "Spusteni threadu se nepovedlo: %s!\n", err->message);
676 g_error_free(err);
677 }
678 }
679
680 /**
681 * \brief Callback menu About
682 *
683 * Pomoci GtkBuilderu vytvori a zobrazi About dialog. Nastavi callback pro
684 * zavreni okna (dulezite)
685 * @param widget Pointer na volbu menu
686 * @param data Struktura obsahujici pointery na graficke prvky
687 */
688 G_MODULE_EXPORT void about_cb(GtkWidget *widget, ChData *data)
689 {
690 GtkBuilder *builder;
691 GtkWidget *about_dialog;
692 GError *error = NULL;
693
694 builder = gtk_builder_new();
695 if (!gtk_builder_add_from_file(builder, ABOUT_FILE, &error)) {
696 g_warning("%s", error->message);
697 g_free(error);
698 return;
699 }
700 about_dialog = GTK_WIDGET(gtk_builder_get_object(builder, "aboutdialog"));
701 gtk_builder_connect_signals(builder, NULL);
702 g_signal_connect_swapped(about_dialog, "response", G_CALLBACK(gtk_widget_destroy), about_dialog); // Aby fungovalo Close
703 g_object_unref(G_OBJECT(builder));
704 gtk_widget_show(about_dialog);
705 }
706
707 /**
708 * \brief Hlavni funkce
709 *
710 * Provede nacteni parametru prikazove radky, inicializuje nazvy souboru a podle
711 * voleb spusti kompresi, dekompresi, zobrazi napovedu nebo nacte a zobrazi
712 * graficke rozhrani.
713 * @param argc Pocet retezcu v shellu pri spusteni
714 * @param argv Pole pointeru na retezce v shellu pri spusteni
715 * @return 0 pokud nedojde k chybe
716 */
717 gint main(int argc, char **argv)
718 {
719 ChData *data; /**< Struktura obsahujici pointery na graficke prvky */
720 GtkBuilder *builder; /**< Struktura pro nacteni GUI z .glade souboru */
721 GError *error = NULL; /**< Chyby pri nacitani GUI */
722 gint akce = GRAFIKA; /**< Prepinac provedene akce */
723 gchar f_in[1024] = {0}; /**< Retezec nazvu vstupniho souboru */
724 gchar f_out[1024] = {0}; /**< Retezec nazvu vystupniho souboru */
725 gint c; /**< Promenna pouzita pro zpracovani parametru shellu */
726
727 opterr = 0;
728 grafika = 1;
729
730 while ((c = getopt(argc, argv, "cdghi:o:vV")) != -1) {
731 switch (c) {
732 case 'c':
733 akce = KOMPRESE;
734 grafika = 0;
735 break;
736 case 'd':
737 akce = DEKOMPRESE;
738 grafika = 0;
739 break;
740 case 'g':
741 akce = GRAFIKA;
742 grafika = 1;
743 break;
744 case 'h':
745 pouziti(argv[0]);
746 return 0;
747 break;
748 case 'i':
749 strcpy(f_in, optarg);
750 break;
751 case 'o':
752 strcpy(f_out, optarg);
753 break;
754 case 'v':
755 vypisy = 1;
756 break;
757 case 'V':
758 vypisy = 2;
759 break;
760 case '?':
761 if (optopt == 'i' || optopt == 'o')
762 fprintf(stderr, "Parametru -%c chybi nazev souboru.\n", optopt);
763 else if (isprint(optopt))
764 fprintf(stderr, "Neznamy parametr '-%c'.\n", optopt);
765 else
766 fprintf(stderr, "Neznamy znak '\\x%x'.\n", optopt);
767 return -1;
768 default:
769 return -1;
770 }
771 }
772
773 if ((akce == 0 || f_in[0] == '\0' || f_out[0] == '\0') && akce != GRAFIKA) {
774 pouziti(argv[0]);
775 return 0;
776 }
777
778 data = g_slice_new(ChData);
779 data->f_in = f_in;
780 data->f_out = f_out;
781
782 if (akce == GRAFIKA) {
783 gtk_init(&argc, &argv);
784 g_thread_init(NULL);
785 builder = gtk_builder_new();
786 if (!gtk_builder_add_from_file(builder, GUI_FILE, &error)) {
787 g_warning("%s", error->message);
788 g_free(error);
789 return 1;
790 }
791
792 data->main_window = GTK_WIDGET(gtk_builder_get_object(builder, "main_window"));
793 data->label_info = GTK_WIDGET(gtk_builder_get_object(builder, "label_info"));
794 data->f_ch_b = GTK_WIDGET(gtk_builder_get_object(builder, "f_ch_b"));
795 data->entry_vystup = GTK_WIDGET(gtk_builder_get_object(builder, "entry_vystup"));
796 data->statusbar = GTK_WIDGET(gtk_builder_get_object(builder, "statusbar"));
797
798 gtk_builder_connect_signals(builder, data);
799 g_object_unref(G_OBJECT(builder));
800 gtk_widget_show(data->main_window);
801 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(data->f_ch_b), f_in);
802 gtk_entry_set_text(GTK_ENTRY(data->entry_vystup), f_out);
803 gtk_statusbar_push(GTK_STATUSBAR(data->statusbar), gtk_statusbar_get_context_id(GTK_STATUSBAR(data->statusbar), "uvitani"), VERZE);
804
805 gtk_main();
806
807 } else if (akce == KOMPRESE) {
808 if (komprese(data) != 0) {
809 fprintf(stderr, "Komprese se nezdarila.\n");
810 return -1;
811 }
812
813 } else if (akce == DEKOMPRESE) {
814 if (dekomprese(data) != 0) {
815 fprintf(stderr, "Dekomprese se nezdarila.\n");
816 return -1;
817 }
818 }
819
820 g_slice_free(ChData, data);
821
822 return 0;
823 }