Kestrel Interface
Loading...
Searching...
No Matches
kest_files.c
Go to the documentation of this file.
1#include <sys/unistd.h>
2#include <sys/stat.h>
3#include <dirent.h>
4
5#include "kest_int.h"
6
7#ifndef PRINTLINES_ALLOWED
8#define PRINTLINES_ALLOWED 0
9#endif
10
11static const char *FNAME = "kest_files.c";
12
13#define IO_BUFFER_SIZE 128
14
15#define write_byte(x) fputc(x, file);
16#define write_short(x) do { arg16 = x; fwrite(&arg16, 1, 2, file);} while(0)
17#define write_int32(x) do { arg32 = x; fwrite(&arg32, sizeof( int32_t), 1, file);} while(0)
18#define write_uint32(x) do {uarg32 = x; fwrite(&uarg32, sizeof(uint32_t), 1, file);} while(0)
19#define write_float(x) fwrite(&x, sizeof(float), 1, file);
20#define write_string(x) \
21 do {if (x) {for (int a = 0; x[a] != 0; a++) {fputc(x[a], file);}} fputc(0, file);} while (0)
22
23#define read_byte(x) x = fgetc(file);
24#define read_short(x) fread(&x, sizeof(uint16_t), 1, file);
25#define read_int32(x) fread(&x, sizeof(int32_t), 1, file);
26#define read_uint32(x) fread(&x, sizeof(uint32_t), 1, file);
27#define read_float(x) fread(&x, sizeof(float), 1, file);
28#define read_string() \
29 do {\
30 for (int i = 0; i < IO_BUFFER_SIZE; i++)\
31 {\
32 string_read_buffer[i] = fgetc(file);\
33 if (!string_read_buffer[i])\
34 break;\
35 }\
36 } while (0);
37#define read_and_strndup_string(x) \
38 do {\
39 for (int i = 0; i < IO_BUFFER_SIZE; i++)\
40 {\
41 string_read_buffer[i] = fgetc(file);\
42 if (!string_read_buffer[i])\
43 break;\
44 }\
45 x = kest_strndup(string_read_buffer, IO_BUFFER_SIZE);\
46 } while (0);
47
48void dump_file_contents(char *fname)
49{
50 KEST_PRINTF("FILE HEX DUMP: %s\n", fname);
51 FILE *file = fopen(fname, "rb");
52
53 if (!file)
54 {
55 KEST_PRINTF("Failed to open file %s\n", fname);
56 return;
57 }
58
59 uint8_t byte;
60
61 int i = 1;
62 while (fread(&byte, 1, 1, file))
63 {
64 if (i % 8 == 1) KEST_PRINTF("\n %s%d | ", (i < 10) ? " " : ((i < 100) ? " " : ""), i - 1);
65 KEST_PRINTF("0x%02x ", byte);
66 i++;
67 }
68
69 KEST_PRINTF((i % 8 == 1) ? "" : "\n");
70 fclose(file);
71}
72
73int file_validity_check(FILE *file, uint8_t magic_byte, uint8_t *byte_out)
74{
75 uint8_t byte;
76
77 read_byte(byte);
78
79 if (byte_out)
80 *byte_out = byte;
81
82 if (byte != magic_byte)
83 return 1;
84
85 read_byte(byte);
86
87 if (byte_out)
88 *byte_out = byte;
89
90 if (byte != KEST_WRITE_FINISHED_BYTE)
91 return 2;
92
93 return 0;
94}
95
96int save_profile_as_file(kest_profile *profile, const char *fname)
97{
98 KEST_PRINTF("save_profile_as_file\n");
99
100 if (!fname || !profile)
101 {
102 KEST_PRINTF("NULL pointer lol\n");
103 return ERR_NULL_PTR;
104 }
105
106 FILE *file = fopen(fname, "wb");
107
108 uint8_t len;
109
110 if (!file)
111 {
112 KEST_PRINTF("Could not open file %s\n", fname);
113 return ERR_FOPEN_FAIL;
114 }
115
116 // Declare that this is a profile file
118
119 // Write status byte; overwritten at the end
121
122 uint8_t buffer[IO_BUFFER_SIZE];
123 uint16_t arg16;
124 int32_t arg32;
125 int ret_val;
126 int n;
127
128 char *units;
129 char *name = profile->name ? profile->name : "Unnamed Profile";
130
131 write_string(name);
132
133 kest_effect_pll *current_effect = profile->pipeline.effects;
134 kest_parameter_pll *current_param;
135 kest_setting_pll *current_setting;
136
137 n = 0;
138
139 while (current_effect)
140 {
141 current_effect = current_effect->next;
142 n++;
143 }
144
145 write_short(n);
146
147 current_effect = profile->pipeline.effects;
148
149 while (current_effect)
150 {
151 if (!current_effect->data || !current_effect->data->eff)
152 {
154 current_effect = current_effect->next;
155 continue;
156 }
157
158 write_string(current_effect->data->eff->cname);
159 write_short(current_effect->data->id);
160
161 current_param = current_effect->data->parameters;
162
163 while (current_param)
164 {
165 if (current_param->data)
166 write_float(current_param->data->value);
167
168 current_param = current_param->next;
169 }
170
171 current_setting = current_effect->data->settings;
172
173 while (current_setting)
174 {
175 if (current_setting->data)
176 write_int32(current_setting->data->value);
177
178 current_setting = current_setting->next;
179 }
180
181 current_effect = current_effect->next;
182 }
183
184 fseek(file, 1, SEEK_SET);
186
187 fclose(file);
188
189 KEST_PRINTF("save_profile_as_file done\n");
190
191 return NO_ERROR;
192}
193
194int save_sequence_as_file(kest_sequence *sequence, const char *fname)
195{
196 if (!sequence || !fname)
197 return ERR_NULL_PTR;
198
199 KEST_PRINTF("Saving sequence %s to sd card!\n", sequence->name ? "(unnamed)" : sequence->name);
200 FILE *file = fopen(fname, "wb");
201
202 if (!file)
203 {
204 KEST_PRINTF("Failed to open file %s\n", fname);
205 return ERR_FOPEN_FAIL;
206 }
207
209
211
212 char *name = sequence->name ? sequence->name : "Unnamed Sequence";
213
214 write_string(name);
215
216 seq_profile_ll *current = sequence->profiles;
217
218 uint16_t n_profiles = 0;
219 uint16_t arg16;
220
221 while (current)
222 {
223 n_profiles++;
224 current = current->next;
225 }
226
227 KEST_PRINTF("Sequence has %d profiles...\n", n_profiles);
228 write_short(n_profiles);
229
230 current = sequence->profiles;
231 while (current)
232 {
233 if (current->data)
234 {
235 if (!current->data->has_fname || current->data->unsaved_changes)
236 {
237 save_profile(current->data);
238 }
239
240 KEST_PRINTF("Profile %s...\n", current->data->fname);
241 write_string(current->data->fname);
242 }
243
244 current = current->next;
245 }
246
247 fseek(file, 1, SEEK_SET);
249
250 fclose(file);
251
252 KEST_PRINTF("Success\n");
253
254 dump_file_contents(fname);
255 return NO_ERROR;
256}
257
258int save_state_to_file(kest_state *state, const char *fname)
259{
260 if (!state || !fname)
261 return ERR_NULL_PTR;
262
263 KEST_PRINTF("Saving state to sd card!\n");
264 FILE *file = fopen(fname, "wb");
265 int32_t arg32;
266
267 if (!file)
268 {
269 KEST_PRINTF("Failed to open file %s\n", fname);
270 return ERR_FOPEN_FAIL;
271 }
272
274
276
277 write_float(state->input_gain);
278 write_float(state->output_gain);
279
281
282 KEST_PRINTF("Write state->current_page.type = %d = 0x%08x\n", state->current_page.type, state->current_page.type);
286
287 fseek(file, 1, SEEK_SET);
289
290 fclose(file);
291
292 KEST_PRINTF("Success\n");
293
294 dump_file_contents(fname);
295 return NO_ERROR;
296}
297
298int load_state_from_file(kest_state *state, const char *fname)
299{
300 if (!state || !fname)
301 return ERR_NULL_PTR;
302
303 KEST_PRINTF("load state from file %s...\n", fname);
304
305 dump_file_contents(fname);
306
307 FILE *file = fopen(fname, "rb");
308
309 char string_read_buffer[IO_BUFFER_SIZE];
310 int ret_val = NO_ERROR;
311 uint8_t byte;
312 void *ptr;
313 float f;
314 int i;
315 int j;
316
317 if (!file)
318 {
319 KEST_PRINTF("Failed to open file %s\n", fname);
320 return ERR_FOPEN_FAIL;
321 }
322
323 fseek(file, 0, SEEK_END);
324 int file_size = ftell(file);
325 fseek(file, 0, SEEK_SET);
326
327 uint8_t *content = kest_alloc(file_size * sizeof(uint8_t));
328
329 if (!content)
330 return ERR_ALLOC_FAIL;
331
332 fread(content, 1, file_size, file);
333 fclose(file);
334
335 byte = content[0];
336
337 if (byte != KEST_STATE_MAGIC_BYTE)
338 {
339 ret_val = ERR_MANGLED_FILE;
340 goto read_settings_exit;
341 }
342
343 byte = content[1];
344
345 if (byte != KEST_WRITE_FINISHED_BYTE)
346 {
347 ret_val = ERR_MANGLED_FILE;
348 goto read_settings_exit;
349 }
350
351 ptr = (void*)&content[2];
352
353 state->input_gain = *((float*)(&content[2]));
354 KEST_PRINTF("Obtained input gain as %f = 0x%08x\n", state->input_gain, *((int*)(&content[2])));
355 state->output_gain = *((float*)(&content[6]));
356 KEST_PRINTF("Obtained output gain as %f = 0x%08x\n", state->output_gain, *((int*)(&content[6])));
357
358 i = 10;
359 KEST_PRINTF("Reading active profile fname from position %d\n", i);
360 if (content[i])
361 {
362 j = 10;
363 while (content[i] && i - j < 31)
364 {
365 KEST_PRINTF("\t0x%02x = '%c'\n", content[i], content[i]);
366 state->active_profile_fname[i - j] = (char)content[i];
367 i++;
368 }
369 state->active_profile_fname[i - j] = 0;
370 }
371 else
372 {
373 state->active_profile_fname[0] = 0;
374 i++;
375 }
376
377 if (content[i])
378 {
379 j = i;
380
381 while (content[i] && i - j < 31)
382 {
383 state->active_sequence_fname[i - j] = (char)content[i];
384 i++;
385 }
386 state->active_sequence_fname[i - j] = 0;
387 }
388 else
389 {
390 state->active_sequence_fname[0] = 0;
391 i++;
392 }
393
394 KEST_PRINTF("Reading current page identifier struct, starting at position %d\n", i);
395
396 state->current_page.type = *((int32_t*)(&content[i]));
397 KEST_PRINTF("Obtained current_page.type as %d = 0x%08x\n", state->current_page.type, *((int*)(&content[i])));
398 i += sizeof(int32_t);
399 state->current_page.id = *((int32_t*)(&content[i]));
400 KEST_PRINTF("Obtained current_page.type as %d = 0x%08x\n", state->current_page.id, *((int*)(&content[i])));
401 i += sizeof(int32_t);
402
403 KEST_PRINTF("Reading state->current_page.fname from position %d\n", i);
404 if (content[i])
405 {
406 j = i;
407
408 while (content[i] && i - j < 32)
409 {
410 KEST_PRINTF("\t0x%02x = '%c'\n", content[i], content[i]);
411 state->current_page.fname[i - j] = (char)content[i];
412 i++;
413 }
414 state->current_page.fname[i - j] = 0;
415 }
416 else
417 {
418 state->current_page.fname[0] = 0;
419 i++;
420 }
421
422 KEST_PRINTF("read input gain: %f\n", state->input_gain);
423 KEST_PRINTF("read output gain: %f\n", state->output_gain);
424 KEST_PRINTF("read active profile fname: %s\n", state->active_profile_fname);
425 KEST_PRINTF("read active sequence fname: %s\n", state->active_sequence_fname);
426 KEST_PRINTF("read current page: {type = %d, id = %d, fname = \"%s\"}\n", state->current_page.type, state->current_page.id,
427 state->current_page.fname);
428
429read_settings_exit:
430
431 return ret_val;
432}
433
434int read_profile_from_file(kest_profile *profile, const char *fname)
435{
436 //kest_printf("read_profile_from_file\n");
437 if (!fname || !profile)
438 {
439 //kest_printf("NULL pointer lol\n");
440 return ERR_NULL_PTR;
441 }
442
443 dump_file_contents(fname);
444
445 FILE *file = fopen(fname, "r");
446
447 if (!file)
448 {
449 //kest_printf("Could not open file %s\n", fname);
450 return ERR_FOPEN_FAIL;
451 }
452
453
454 KEST_PRINTF("Reading profile from %s\n", fname);
455
456 uint8_t byte;
457 uint16_t arg16;
458 int32_t arg32;
459 uint16_t n_effects;
460 char string_read_buffer[IO_BUFFER_SIZE];
461 char *name = NULL;
462 int ret_val = NO_ERROR;
463 kest_effect *effect = NULL;
464 kest_parameter_pll *current_param = NULL;
465 kest_setting_pll *current_setting = NULL;
466
467 // Check that this is a profile file
468 byte = fgetc(file);
469
470 if (byte != KEST_PROFILE_MAGIC_BYTE)
471 {
472 KEST_PRINTF("Attempted load of profile from file \"%s\", whose first byte 0x%02x is not the profile magic byte 0x%02x\n",
473 fname, byte, KEST_PROFILE_MAGIC_BYTE);
474 ret_val = ERR_BAD_ARGS;
475 goto profile_read_bail;
476 }
477
478 // Check that the write was finished
479 byte = fgetc(file);
480
481 if (byte != KEST_WRITE_FINISHED_BYTE)
482 {
483 KEST_PRINTF("Attempted load of profile from file \"%s\", whose second byte 0x%02x indicates that its write was unfinished\n",
484 fname, byte);
485 ret_val = ERR_UNFINISHED_WRITE;
486 goto profile_read_bail;
487 }
488
490
491 if (!name)
492 {
493 KEST_PRINTF("Allocation fail allocating string of length %d for profile name from file %s\n", (int)byte, fname);
494 goto profile_read_bail;
495 }
496
497 profile->name = name;
498
499 KEST_PRINTF("Loaded profile name: %s\n", profile->name);
500
501 read_short(n_effects);
502
503 kest_effect_desc *eff = NULL;
504
505 for (int i = 0; i < n_effects; i++)
506 {
507 KEST_PRINTF("Profile professes to contain %d effects\n", n_effects);
508 //Get effect type
509 read_string();
510
511 eff = kest_cxt_get_effect_desc_from_cname(&global_cxt, string_read_buffer);
512
513 if (!eff)
514 {
515 KEST_PRINTF("Profile references non-existent effect. Aborting.\n");
516 ret_val = ERR_MANGLED_FILE;
517 goto profile_read_bail;
518 }
519
520 KEST_PRINTF("Encountered %s in position %d\n", eff->name, (int)i);
521
522 effect = kest_profile_append_effect_eff(profile, eff);
523
524 if (!effect)
525 {
526 KEST_PRINTF("Failed to append effect \"%s\"", eff->name);
527 ret_val = ERR_MANGLED_FILE;
528 goto profile_read_bail;
529 }
530
531 // Get effect ID
532 read_short(arg16);
533
534
535 KEST_PRINTF("Transformer ID: %d\n", (int)arg16);
536 effect->id = arg16;
537
538 current_param = effect->parameters;
539 while (current_param)
540 {
541 if (current_param->data)
542 read_float(current_param->data->value);
543
544 current_param = current_param->next;
545 }
546
547 current_setting = effect->settings;
548 while (current_setting)
549 {
550 if (current_setting->data)
551 read_float(current_setting->data->value);
552
553 current_setting = current_setting->next;
554 }
555
556 //kest_effect_init_view_page(effect);
557 }
558
559 KEST_PRINTF("File done! closing...\n");
560 fclose(file);
561 KEST_PRINTF("Closed. Returning\n");
562
563 for (int k = 0; k < KEST_FILENAME_LEN; k++)
564 {
565 if (!fname[k])
566 {
567 profile->fname[k] = 0;
568 break;
569 }
570
571 profile->fname[k] = fname[k];
572 }
573
574 profile->has_fname = 1;
575
576
577
578 profile->unsaved_changes = 0;
579
580 return ret_val;
581
582profile_read_bail:
583 //kest_printf("BAILING\n");
584 fclose(file);
585
586 //kest_printf("BAILED\n");
587 return ret_val;
588}
589
590int read_sequence_from_file(kest_sequence *sequence, const char *fname)
591{
592 KEST_PRINTF("read_sequence_from_file\n");
593 if (!fname || !sequence)
594 {
595 return ERR_NULL_PTR;
596 }
597
598 dump_file_contents(fname);
599
600 FILE *file = fopen(fname, "r");
601
602 if (!file)
603 {
604 KEST_PRINTF("Could not open file \"%s\"\n", fname);
605 return ERR_FOPEN_FAIL;
606 }
607
608 KEST_PRINTF("Reading sequence from %s\n", fname);
609
610 uint8_t byte;
611 uint16_t arg16;
612 uint16_t n_profiles;
613 char string_read_buffer[IO_BUFFER_SIZE];
614 char *name = NULL;
615 char *profile_fname = NULL;
616
617 int ret_val = NO_ERROR;
618
619 switch (file_validity_check(file, KEST_SEQUENCE_MAGIC_BYTE, &byte))
620 {
621 case 0:
622 break;
623
624 case 1:
625 KEST_PRINTF("Attempted load of sequence from file \"%s\", whose first byte 0x%02x is not the sequence magic byte 0x%02x",
626 fname, byte, KEST_PROFILE_MAGIC_BYTE);
627 ret_val = ERR_BAD_ARGS;
628 goto sequence_read_bail;
629
630 case 2:
631 KEST_PRINTF("Attempted load of sequence from file \"%s\", whose second byte 0x%02x indicates that its write was unfinishedn",
632 fname, byte);
633 ret_val = ERR_UNFINISHED_WRITE;
634 goto sequence_read_bail;
635 }
636
638
639 if (!name)
640 {
641 KEST_PRINTF("Allocation fail allocating string of length %d for sequence name from file %s", (int)byte, fname);
642 goto sequence_read_bail;
643 }
644
645 sequence->name = name;
646
647 KEST_PRINTF("Loaded sequence name: %s\n", sequence->name);
648
649 read_short(n_profiles);
650
651 kest_profile *profile;
652
653 for (int i = 0; i < n_profiles; i++)
654 {
655 read_string();
656
657 KEST_PRINTF("Sequence contains profile %s...\n", string_read_buffer);
658 profile = cxt_get_profile_by_fname(&global_cxt, string_read_buffer);
659
660 if (profile)
661 {
662 sequence_append_profile(sequence, profile);
663 }
664 else
665 {
666 KEST_PRINTF("Error: sequence %s contains profile %s, but no such profile found!\n", fname, string_read_buffer);
667 }
668 }
669
670 KEST_PRINTF("File done! closing...\n");
671 fclose(file);
672 KEST_PRINTF("Closed. Returning\n");
673
674 for (int k = 0; k < KEST_FILENAME_LEN; k++)
675 {
676 if (!fname[k])
677 {
678 sequence->fname[k] = 0;
679 break;
680 }
681
682 sequence->fname[k] = fname[k];
683 }
684
685 sequence->has_fname = 1;
686
687 sequence->unsaved_changes = 0;
688
689 return ret_val;
690
691sequence_read_bail:
692 fclose(file);
693
694 return ret_val;
695}
696
698{
699 struct stat statbuf;
700
701 if (stat(KEST_PROFILES_DIR, &statbuf) == 0)
702 {
703 KEST_PRINTF("Profiles directory %s found\n", KEST_PROFILES_DIR);
704 }
705 else
706 {
707 KEST_PRINTF("Profiles directory %s doesn't exist. Creating...\n", KEST_PROFILES_DIR);
708 if (mkdir(KEST_PROFILES_DIR, 07777) != 0)
709 {
710 KEST_PRINTF("Failed to create profiles directory\n");
711 }
712 else
713 {
714 KEST_PRINTF("Directory created sucessfully\n");
715 }
716 }
717
718 if (stat(KEST_SEQUENCES_DIR, &statbuf) == 0)
719 {
720 KEST_PRINTF("Sequences directory %s found", KEST_SEQUENCES_DIR);
721 }
722 else
723 {
724 KEST_PRINTF("Sequences directory %s doesn't exist. Creating...\n", KEST_SEQUENCES_DIR);
725 if (mkdir(KEST_SEQUENCES_DIR, 07777) != 0)
726 {
727 KEST_PRINTF("Failed to create sequences directory\n");
728 }
729 else
730 {
731 KEST_PRINTF("Directory created sucessfully\n");
732 }
733 }
734
735 return NO_ERROR;
736}
737
738int safe_file_write(int (*write_func)(void *arg, const char *fname), void *arg, const char *fname)
739{
740 if (!write_func)
741 return ERR_NULL_PTR;
742
743 // Check if the file exists
744 FILE *target = fopen(fname, "r");
745 char buf[strlen(fname) + 5];
746 int backup = 0;
747
748 if (target)
749 {
750 backup = 1;
751
752 // Append ".bak" to the filename
753 sprintf(buf, "%s.bak", fname);
754
755 // Check if a file with that name exists
756 FILE *bakfile = fopen(buf, "r");
757 if (bakfile)
758 {
759 // If so, delete it
760 remove(buf);
761 fclose(bakfile);
762 }
763
764 // Rename the current version
765 rename(fname, buf);
766
767 fclose(target);
768 }
769
770 int ret_val = write_func(arg, fname);
771
772 // If we backed up but the write failed,
773 // replace the newly written file with
774 // the old backup
775 if (backup && ret_val != NO_ERROR)
776 {
777 // Remove any busted file we wrote
778 remove(fname);
779 // Move the backup back in place
780 rename(buf, fname);
781 }
782
783 return ret_val;
784}
785
786int save_profile_as_file_safe(kest_profile *profile, const char *fname)
787{
788 // Check if the file exists
789 FILE *target = fopen(fname, "r");
790 char buf[strlen(fname) + 5];
791 int backup = 0;
792
793 if (target)
794 {
795 backup = 1;
796
797 // Append ".bak" to the filename
798 sprintf(buf, "%s.bak", fname);
799
800 // Check if a file with that name exists
801 FILE *bakfile = fopen(buf, "r");
802 if (bakfile)
803 {
804 // If so, delete it
805 remove(buf);
806 fclose(bakfile);
807 }
808
809 // Rename the current version
810 rename(fname, buf);
811
812 fclose(target);
813 }
814
815 int ret_val = save_profile_as_file(profile, fname);
816
817 // If we backed up but the write failed,
818 // replace the newly written file with
819 // the old backup
820 if (backup && ret_val != NO_ERROR)
821 {
822 // Remove any busted file we wrote
823 remove(fname);
824 // Move the backup back in place
825 rename(buf, fname);
826 }
827
828 return ret_val;
829}
830
831#define FNAME_DIGITS 4
832
833void generate_filename(char *prefix, char *suffix, char *dest)
834{
835 if (!dest)
836 return;
837
838 int plen = 0, slen = 0;
839
840 if (prefix)
841 plen = strlen(prefix);
842 if (suffix)
843 slen = strlen(suffix);
844
845 char fname[KEST_FILENAME_LEN];
846
847 int index = 0;
848
849 for (int i = 0; i < plen; i++)
850 fname[index++] = prefix[i];
851
852 char c;
853 int x;
854
855 for (int i = 0; i < FNAME_DIGITS; i++)
856 {
857 x = rand() % 36;
858
859 fname[index++] = (x < 10) ? '0' + x : 'A' + (x - 10);
860 }
861
862 for (int i = 0; i < slen; i++)
863 fname[index++] = (suffix[i] == '%') ? '_' : suffix[i];
864
865 fname[index] = 0;
866
867 KEST_PRINTF("Generated filename %s\n", fname);
868
869 for (int k = 0; k < index && k < KEST_FILENAME_LEN; k++)
870 {
871 if (fname[k] == 0)
872 {
873 dest[k] = 0;
874 break;
875 }
876
877 dest[k] = fname[k];
878 }
879
880 return;
881}
882
884{
885 if (!profile->has_fname)
886 {
887 FILE *test = NULL;
888
889 do {
891
892 if (!profile)
893 return ERR_ALLOC_FAIL;
894
895 test = fopen(profile->fname, "r");
896
897 if (test)
898 {
899 fclose(test);
900 }
901 } while (test);
902
903 profile->has_fname = 1;
904 }
905
906 int ret_val = save_profile_as_file(profile, profile->fname);
907
908 if (ret_val == NO_ERROR)
909 {
910 KEST_PRINTF("Sucessfully saved profile as %s. Dumping file...\n", profile->fname);
911 dump_file_contents(profile->fname);
912 }
913 else
914 {
915 KEST_PRINTF("Profile save error: %s\n", kest_error_code_to_string(ret_val));
916 }
917
918 return ret_val;
919}
920
922{
923 if (!sequence)
924 return ERR_NULL_PTR;
925
926 if (!sequence->has_fname)
927 {
928 FILE *test = NULL;
929
930 do {
932
933 test = fopen(sequence->fname, "r");
934
935 if (test)
936 {
937 kest_free(sequence->fname);
938 fclose(test);
939 }
940 } while (test);
941
942 sequence->has_fname = 1;
943 }
944
945 int ret_val = save_sequence_as_file(sequence, sequence->fname);
946
947 if (ret_val == NO_ERROR)
948 {
949 KEST_PRINTF("Sucessfully saved sequence as %s. Dumping file...\n", sequence->fname);
950 dump_file_contents(sequence->fname);
951 }
952 else
953 {
954 KEST_PRINTF("Sequence save error: %s\n", kest_error_code_to_string(ret_val));
955 }
956
957 return ret_val;
958}
959
961{
962 KEST_PRINTF("load_saved_profiles...\n");
964
965 string_ll *cf = current_file;
966
967 KEST_PRINTF("Profile files fonund:\n");
968 if (!cf)
969 {
970 KEST_PRINTF("none!!!\n");
971 }
972 else
973 {
974 while (cf)
975 {
976 KEST_PRINTF("%s\n", cf->data);
977 cf = cf->next;
978 }
979 }
980
981 kest_profile *profile;
982
983 kest_profile_pll *nl;
984
985 int ret_val;
986
987 while (current_file)
988 {
989 KEST_PRINTF("Loading profile %s...\n", current_file->data);
990 profile = kest_alloc(sizeof(kest_profile));
991
992 if (!profile)
993 return ERR_ALLOC_FAIL;
994
995 init_m_profile(profile);
996 ret_val = read_profile_from_file(profile, current_file->data);
997
998 if (ret_val == NO_ERROR)
999 {
1000 nl = kest_profile_pll_append(cxt->profiles, profile);
1001
1002 if (!nl)
1003 {
1004 free_profile(profile);
1005 return ERR_ALLOC_FAIL;
1006 }
1007 cxt->profiles = nl;
1008
1009 create_profile_view_for(profile);
1010 }
1011 else
1012 {
1013 free_profile(profile);
1014 }
1015
1016 current_file = current_file->next;
1017 }
1018
1019 global_cxt.saved_profiles_loaded = 1;
1020
1021 return NO_ERROR;
1022}
1023
1025{
1026 int ret_val;
1027
1029
1031
1032 kest_sequence *sequence;
1033
1034 kest_sequence_pll *nl;
1035
1036 while (current_file)
1037 {
1038 sequence = kest_alloc(sizeof(kest_sequence));
1039
1040 if (!sequence)
1041 return ERR_ALLOC_FAIL;
1042
1043 init_m_sequence(sequence);
1044 ret_val = read_sequence_from_file(sequence, current_file->data);
1045
1046 if (ret_val == NO_ERROR)
1047 {
1048 nl = kest_sequence_pll_append(cxt->sequences, sequence);
1049
1050 if (!nl)
1051 {
1052 free_sequence(sequence);
1053 return ERR_ALLOC_FAIL;
1054 }
1055 cxt->sequences = nl;
1056
1057 create_sequence_view_for(sequence);
1058 }
1059 else
1060 {
1061 free_sequence(sequence);
1062 }
1063
1064 current_file = current_file->next;
1065 }
1066
1067 global_cxt.saved_sequences_loaded = 1;
1068
1069 return NO_ERROR;
1070}
1071
1073{
1074 if (!cxt)
1075 return ERR_NULL_PTR;
1076
1078
1079 kest_effect_desc *eff = NULL;
1080 int ret_val = NO_ERROR;
1081
1082 if (current)
1083 {
1085 if (ret_val != NO_ERROR)
1086 {
1087 return ret_val;
1088 }
1089 }
1090
1091 while (current)
1092 {
1093 KEST_PRINTF("Attempting to load effect from file \"%s\"...\n", current->data);
1094
1095 eff = kest_read_eff_desc_from_file(current->data);
1096
1097 KEST_PRINTF("kest_read_eff_desc_from_file returned the pointer %p\n", eff);
1098
1099 if (eff)
1100 {
1101 KEST_PRINTF("Obtained an effect descriptor by the name of \"%s\" ! Adding it to the list %p...\n",
1102 eff->name, &cxt->effects);
1103 ret_val = kest_effect_desc_pll_safe_append(&cxt->effects, eff);
1104
1105 if (ret_val != NO_ERROR)
1106 {
1107 KEST_PRINTF("Error adding effect \"%s\"; error %s\n", eff->name, kest_error_code_to_string(ret_val));
1108 }
1109 }
1110
1112 current = current->next;
1113 }
1114
1116
1117 return NO_ERROR;
1118}
1119
1120
1122{
1123 #ifndef USE_SDCARD
1124 return NULL;
1125 #endif
1126
1127 if (!dir)
1128 return NULL;
1129
1130 KEST_PRINTF("Generating list of files in %s\n", dir);
1131
1132 char *fname = NULL;
1133
1134 DIR *directory = opendir(dir);
1135
1136 if (!directory)
1137 {
1138 KEST_PRINTF("Failed to open directory!\n");
1139 return NULL;
1140 }
1141
1142 struct dirent *directory_entry = readdir(directory);
1143
1144 string_ll *list = NULL;
1145 string_ll *nl;
1146
1147 while (directory_entry)
1148 {
1149 KEST_PRINTF("Directory entry: %s\n", directory_entry->d_name);
1150 if (directory_entry->d_type == DT_DIR)
1151 {
1152 KEST_PRINTF("... is itself a directory!\n");
1153 directory_entry = readdir(directory);
1154 continue;
1155 }
1156
1157 fname = kest_alloc(strlen(dir) + 1 + 255);
1158
1159 if (!fname)
1160 {
1161 KEST_PRINTF("Error: couldn't allocate string to list directory entry %s/%s", dir, directory_entry->d_name);
1162 return list;
1163 }
1164
1165 sprintf(fname, "%s%s", dir, directory_entry->d_name);
1166
1167 nl = char_pll_append(list, fname);
1168
1169 if (nl)
1170 {
1171 list = nl;
1172 }
1173 else
1174 {
1175 KEST_PRINTF("Error: couldn't append linked list to list directory entry %s/%s", dir, directory_entry->d_name);
1176 return list;
1177 }
1178
1179 directory_entry = readdir(directory);
1180 }
1181
1182 return list;
1183}
1184
1186{
1187 #ifdef USE_SDCARD
1188 erase_sd_card();
1189 #endif
1190}
1191
1192int erase_folder(const char *dir)
1193{
1194 KEST_PRINTF("Erasing directory %s...\n", dir);
1195
1196 DIR *directory = opendir(dir);
1197
1198 if (!directory)
1199 {
1200 KEST_PRINTF("Failed to open directory!\n");
1201 return ERR_BAD_ARGS;
1202 }
1203
1204 struct dirent *directory_entry = readdir(directory);
1205
1206 int ret_val = NO_ERROR;
1207 int bufsize = strlen(dir) + NAME_MAX + 1;
1208 char *buf = kest_alloc(sizeof(bufsize));
1209
1210 if (!buf)
1211 return ERR_ALLOC_FAIL;
1212
1213 while (directory_entry)
1214 {
1215 KEST_PRINTF("Directory entry: %s\n", directory_entry->d_name);
1216 if (directory_entry->d_type == DT_DIR)
1217 {
1218 KEST_PRINTF("... is itself a directory!\n");
1219 snprintf(buf, bufsize, "%s/%s", dir, directory_entry->d_name);
1220 KEST_PRINTF("Full name: %s\n", buf);
1221 kest_free(buf);
1222 ret_val = erase_folder(buf);
1223 rmdir(buf);
1224 buf = kest_alloc(sizeof(bufsize));
1225 if (!buf)
1226 return ERR_ALLOC_FAIL;
1227 }
1228 else
1229 {
1230 KEST_PRINTF("... is a file. Deleting...\n");
1231 snprintf(buf, bufsize, "%s/%s", dir, directory_entry->d_name);
1232 KEST_PRINTF("Full name: %s\n", buf);
1233 remove(buf);
1234 }
1235
1236 directory_entry = readdir(directory);
1237 }
1238
1239 return ret_val;
1240}
1241
1243{
1245}
1246
1247int fnames_agree(char *a, char *b)
1248{
1249 if (!a || !b)
1250 return 0;
1251
1252 for (int k = 0; a[k] && b[k]; k++)
1253 {
1254 if (a[k] != b[k])
1255 {
1256 if (char_is_letter(a[k]) && char_is_letter(b[k]) && ((a[k] - b[k] == 'A' - 'a') || (a[k] - b[k] == 'a' - 'A')))
1257 continue;
1258 else
1259 return 0;
1260 }
1261 }
1262
1263 return 1;
1264}
void kest_free(void *ptr)
Definition kest_alloc.c:32
void * kest_alloc(size_t size)
Definition kest_alloc.c:11
kest_effect_desc * kest_cxt_get_effect_desc_from_cname(kest_context *cxt, const char *cname)
kest_profile * cxt_get_profile_by_fname(kest_context *cxt, const char *fname)
int kest_eff_parser_reset_mempool()
kest_effect_desc * kest_read_eff_desc_from_file(char *fname)
int kest_eff_parser_deinit_mempool()
const char * kest_error_code_to_string(int error_code)
#define ERR_ALLOC_FAIL
#define ERR_BAD_ARGS
#define ERR_UNFINISHED_WRITE
#define NO_ERROR
#define ERR_FOPEN_FAIL
#define ERR_MANGLED_FILE
#define ERR_NULL_PTR
int save_sequence_as_file(kest_sequence *sequence, const char *fname)
Definition kest_files.c:194
#define read_and_strndup_string(x)
Definition kest_files.c:37
int file_validity_check(FILE *file, uint8_t magic_byte, uint8_t *byte_out)
Definition kest_files.c:73
int load_saved_sequences(kest_context *cxt)
#define write_short(x)
Definition kest_files.c:16
int safe_file_write(int(*write_func)(void *arg, const char *fname), void *arg, const char *fname)
Definition kest_files.c:738
int load_state_from_file(kest_state *state, const char *fname)
Definition kest_files.c:298
#define write_float(x)
Definition kest_files.c:19
int kest_init_directories()
Definition kest_files.c:697
#define read_byte(x)
Definition kest_files.c:23
#define write_string(x)
Definition kest_files.c:20
void erase_sd_card_void_cb(void *data)
int fnames_agree(char *a, char *b)
#define read_short(x)
Definition kest_files.c:24
int load_saved_profiles(kest_context *cxt)
Definition kest_files.c:960
#define read_float(x)
Definition kest_files.c:27
void generate_filename(char *prefix, char *suffix, char *dest)
Definition kest_files.c:833
int save_profile(kest_profile *profile)
Definition kest_files.c:883
void dump_file_contents(char *fname)
Definition kest_files.c:48
#define read_string()
Definition kest_files.c:28
int load_effects(kest_context *cxt)
#define IO_BUFFER_SIZE
Definition kest_files.c:13
int save_profile_as_file(kest_profile *profile, const char *fname)
Definition kest_files.c:96
#define write_byte(x)
Definition kest_files.c:15
int read_sequence_from_file(kest_sequence *sequence, const char *fname)
Definition kest_files.c:590
int save_state_to_file(kest_state *state, const char *fname)
Definition kest_files.c:258
void erase_sd_card()
int read_profile_from_file(kest_profile *profile, const char *fname)
Definition kest_files.c:434
string_ll * list_files_in_directory(char *dir)
int save_sequence(kest_sequence *sequence)
Definition kest_files.c:921
#define write_int32(x)
Definition kest_files.c:17
int save_profile_as_file_safe(kest_profile *profile, const char *fname)
Definition kest_files.c:786
#define FNAME_DIGITS
Definition kest_files.c:831
int erase_folder(const char *dir)
#define KEST_WRITE_UNFINISHED_BYTE
Definition kest_files.h:13
#define SEQUENCE_EXTENSION
Definition kest_files.h:32
#define KEST_PROFILES_DIR
Definition kest_files.h:25
#define KEST_SEQUENCE_MAGIC_BYTE
Definition kest_files.h:11
#define KEST_PROFILE_MAGIC_BYTE
Definition kest_files.h:4
#define KEST_EFFECT_DESC_DIR
Definition kest_files.h:27
#define KEST_PROFILE_BROKEN_TRANSFORMER
Definition kest_files.h:7
#define KEST_WRITE_FINISHED_BYTE
Definition kest_files.h:14
#define KEST_STATE_MAGIC_BYTE
Definition kest_files.h:9
#define KEST_SEQUENCES_DIR
Definition kest_files.h:26
#define MAIN_SEQUENCE_FNAME
Definition kest_files.h:23
#define PROFILE_EXTENSION
Definition kest_files.h:31
kest_context global_cxt
Definition kest_int.c:12
#define KEST_FILENAME_LEN
Definition kest_int.h:72
char_pll string_ll
Definition kest_int.h:70
#define KEST_PRINTF(...)
Definition kest_printf.h:10
int init_m_profile(kest_profile *profile)
void free_profile(kest_profile *profile)
kest_effect * kest_profile_append_effect_eff(kest_profile *profile, kest_effect_desc *eff)
kest_ui_page * create_profile_view_for(kest_profile *profile)
#define MOUNT_POINT
Definition kest_sd.h:7
int init_m_sequence(kest_sequence *sequence)
void free_sequence(kest_sequence *sequence)
int sequence_append_profile(kest_sequence *sequence, kest_profile *profile)
int create_sequence_view_for(kest_sequence *sequence)
int char_is_letter(char c)
profile_ll * profiles
kest_sequence main_sequence
kest_effect_desc_pll * effects
sequence_ll * sequences
const char * name
kest_setting_pll * settings
Definition kest_effect.h:35
uint16_t id
Definition kest_effect.h:21
kest_parameter_pll * parameters
Definition kest_effect.h:34
kest_effect_pll * effects
kest_pipeline pipeline
char fname[KEST_FILENAME_LEN]
char fname[KEST_FILENAME_LEN]
seq_profile_ll * profiles
float input_gain
Definition kest_state.h:6
kest_page_identifier current_page
Definition kest_state.h:9
float output_gain
Definition kest_state.h:7
char active_profile_fname[32]
Definition kest_state.h:10
char active_sequence_fname[32]
Definition kest_state.h:11
kest_profile * data
struct seq_profile_ll * next