@neoanaloglabkk/lensfun-wasm 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,799 @@
1
+ #include "glib.h"
2
+
3
+ #include <dirent.h>
4
+ #include <errno.h>
5
+ #include <fcntl.h>
6
+ #include <fnmatch.h>
7
+ #include <stdarg.h>
8
+ #include <stdio.h>
9
+ #include <stdlib.h>
10
+ #include <string.h>
11
+ #include <sys/stat.h>
12
+
13
+ #include <algorithm>
14
+ #include <fstream>
15
+ #include <string>
16
+ #include <vector>
17
+
18
+ #include "tinyxml2.h"
19
+ #include "utf8proc.h"
20
+
21
+ struct _GDir
22
+ {
23
+ DIR *dir = nullptr;
24
+ struct dirent *entry = nullptr;
25
+ };
26
+
27
+ struct _GPatternSpec
28
+ {
29
+ std::string pattern;
30
+ };
31
+
32
+ struct _GMarkupParseContext
33
+ {
34
+ const GMarkupParser *parser = nullptr;
35
+ gpointer user_data = nullptr;
36
+ GDestroyNotify user_data_dnotify = nullptr;
37
+ std::vector<std::string> element_stack;
38
+ gint current_line = 1;
39
+ gint current_column = 0;
40
+ };
41
+
42
+ static std::string vformat(const char *format, va_list args)
43
+ {
44
+ va_list copy;
45
+ va_copy(copy, args);
46
+ const int needed = vsnprintf(nullptr, 0, format, copy);
47
+ va_end(copy);
48
+
49
+ if (needed <= 0)
50
+ {
51
+ return std::string();
52
+ }
53
+
54
+ std::string out(static_cast<size_t>(needed), '\0');
55
+ vsnprintf(out.data(), out.size() + 1, format, args);
56
+ return out;
57
+ }
58
+
59
+ static std::string xml_escape(const std::string &input)
60
+ {
61
+ std::string out;
62
+ out.reserve(input.size());
63
+ for (char c : input)
64
+ {
65
+ switch (c)
66
+ {
67
+ case '&':
68
+ out += "&amp;";
69
+ break;
70
+ case '<':
71
+ out += "&lt;";
72
+ break;
73
+ case '>':
74
+ out += "&gt;";
75
+ break;
76
+ case '\"':
77
+ out += "&quot;";
78
+ break;
79
+ case '\'':
80
+ out += "&apos;";
81
+ break;
82
+ default:
83
+ out.push_back(c);
84
+ break;
85
+ }
86
+ }
87
+ return out;
88
+ }
89
+
90
+ extern "C" {
91
+
92
+ void g_assertion_message(const char *expr, const char *file, int line)
93
+ {
94
+ fprintf(stderr, "[glib-compat] assertion failed: %s (%s:%d)\n", expr, file, line);
95
+ abort();
96
+ }
97
+
98
+ void *g_malloc(gsize n_bytes)
99
+ {
100
+ const gsize size = n_bytes == 0 ? 1 : n_bytes;
101
+ void *ptr = malloc(size);
102
+ if (!ptr)
103
+ {
104
+ fprintf(stderr, "[glib-compat] out of memory\n");
105
+ abort();
106
+ }
107
+ return ptr;
108
+ }
109
+
110
+ void *g_realloc(gpointer mem, gsize n_bytes)
111
+ {
112
+ const gsize size = n_bytes == 0 ? 1 : n_bytes;
113
+ void *ptr = realloc(mem, size);
114
+ if (!ptr)
115
+ {
116
+ fprintf(stderr, "[glib-compat] out of memory\n");
117
+ abort();
118
+ }
119
+ return ptr;
120
+ }
121
+
122
+ void g_free(gpointer mem)
123
+ {
124
+ free(mem);
125
+ }
126
+
127
+ gchar *g_strdup(const gchar *str)
128
+ {
129
+ if (!str)
130
+ {
131
+ return nullptr;
132
+ }
133
+ const size_t len = strlen(str) + 1;
134
+ auto *copy = static_cast<gchar *>(g_malloc(len));
135
+ memcpy(copy, str, len);
136
+ return copy;
137
+ }
138
+
139
+ void g_mutex_lock(GMutex *mutex)
140
+ {
141
+ if (mutex)
142
+ {
143
+ mutex->lock.lock();
144
+ }
145
+ }
146
+
147
+ void g_mutex_unlock(GMutex *mutex)
148
+ {
149
+ if (mutex)
150
+ {
151
+ mutex->lock.unlock();
152
+ }
153
+ }
154
+
155
+ void g_static_mutex_lock(GStaticMutex *mutex)
156
+ {
157
+ if (mutex)
158
+ {
159
+ mutex->lock.lock();
160
+ }
161
+ }
162
+
163
+ void g_static_mutex_unlock(GStaticMutex *mutex)
164
+ {
165
+ if (mutex)
166
+ {
167
+ mutex->lock.unlock();
168
+ }
169
+ }
170
+
171
+ gchar *g_build_filename(const gchar *first_element, ...)
172
+ {
173
+ if (!first_element)
174
+ {
175
+ return g_strdup("");
176
+ }
177
+
178
+ std::vector<std::string> parts;
179
+ va_list args;
180
+ va_start(args, first_element);
181
+
182
+ const gchar *part = first_element;
183
+ while (part)
184
+ {
185
+ if (*part)
186
+ {
187
+ parts.emplace_back(part);
188
+ }
189
+ part = va_arg(args, const gchar *);
190
+ }
191
+
192
+ va_end(args);
193
+
194
+ if (parts.empty())
195
+ {
196
+ return g_strdup("");
197
+ }
198
+
199
+ std::string out;
200
+ out.reserve(128);
201
+ for (size_t i = 0; i < parts.size(); ++i)
202
+ {
203
+ const std::string &p = parts[i];
204
+ if (i > 0 && !out.empty() && out.back() != '/')
205
+ {
206
+ out.push_back('/');
207
+ }
208
+ if (i > 0 && !p.empty() && p.front() == '/')
209
+ {
210
+ out += p.substr(1);
211
+ }
212
+ else
213
+ {
214
+ out += p;
215
+ }
216
+ }
217
+
218
+ return g_strdup(out.c_str());
219
+ }
220
+
221
+ const gchar *g_get_user_data_dir(void)
222
+ {
223
+ static const char *path = "/tmp";
224
+ return path;
225
+ }
226
+
227
+ int g_open(const char *filename, int flags, int mode)
228
+ {
229
+ return open(filename, flags, mode);
230
+ }
231
+
232
+ gboolean g_file_test(const gchar *filename, GFileTest test)
233
+ {
234
+ if (!filename)
235
+ {
236
+ return FALSE;
237
+ }
238
+
239
+ struct stat st;
240
+ if (stat(filename, &st) != 0)
241
+ {
242
+ return FALSE;
243
+ }
244
+
245
+ if (test == G_FILE_TEST_IS_DIR)
246
+ {
247
+ return S_ISDIR(st.st_mode) ? TRUE : FALSE;
248
+ }
249
+
250
+ return FALSE;
251
+ }
252
+
253
+ gboolean g_file_get_contents(const gchar *filename, gchar **contents, gsize *length, GError **error)
254
+ {
255
+ if (!filename || !contents)
256
+ {
257
+ if (error)
258
+ {
259
+ g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Invalid filename");
260
+ }
261
+ return FALSE;
262
+ }
263
+
264
+ std::ifstream in(filename, std::ios::binary);
265
+ if (!in)
266
+ {
267
+ const int code = (errno == EACCES) ? G_FILE_ERROR_ACCES : G_FILE_ERROR_NOENT;
268
+ if (error)
269
+ {
270
+ g_set_error(error, G_FILE_ERROR, code, "Cannot read file %s", filename);
271
+ }
272
+ return FALSE;
273
+ }
274
+
275
+ std::string data((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
276
+
277
+ auto *buf = static_cast<gchar *>(g_malloc(data.size() + 1));
278
+ if (!data.empty())
279
+ {
280
+ memcpy(buf, data.data(), data.size());
281
+ }
282
+ buf[data.size()] = '\0';
283
+
284
+ *contents = buf;
285
+ if (length)
286
+ {
287
+ *length = data.size();
288
+ }
289
+
290
+ return TRUE;
291
+ }
292
+
293
+ GDir *g_dir_open(const gchar *path, guint, GError **error)
294
+ {
295
+ DIR *dir = opendir(path);
296
+ if (!dir)
297
+ {
298
+ if (error)
299
+ {
300
+ g_set_error(error, G_FILE_ERROR, errno == EACCES ? G_FILE_ERROR_ACCES : G_FILE_ERROR_NOENT, "Cannot open directory %s", path);
301
+ }
302
+ return nullptr;
303
+ }
304
+
305
+ auto *gdir = static_cast<GDir *>(g_malloc(sizeof(GDir)));
306
+ gdir->dir = dir;
307
+ gdir->entry = nullptr;
308
+ return gdir;
309
+ }
310
+
311
+ const gchar *g_dir_read_name(GDir *dir)
312
+ {
313
+ if (!dir || !dir->dir)
314
+ {
315
+ return nullptr;
316
+ }
317
+
318
+ while ((dir->entry = readdir(dir->dir)) != nullptr)
319
+ {
320
+ const char *name = dir->entry->d_name;
321
+ if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
322
+ {
323
+ continue;
324
+ }
325
+ return name;
326
+ }
327
+
328
+ return nullptr;
329
+ }
330
+
331
+ void g_dir_close(GDir *dir)
332
+ {
333
+ if (!dir)
334
+ {
335
+ return;
336
+ }
337
+ if (dir->dir)
338
+ {
339
+ closedir(dir->dir);
340
+ }
341
+ g_free(dir);
342
+ }
343
+
344
+ GPatternSpec *g_pattern_spec_new(const gchar *pattern)
345
+ {
346
+ auto *spec = static_cast<GPatternSpec *>(g_malloc(sizeof(GPatternSpec)));
347
+ new (&spec->pattern) std::string(pattern ? pattern : "");
348
+ return spec;
349
+ }
350
+
351
+ gboolean g_pattern_match(GPatternSpec *pspec, gsize, const gchar *string, const gchar *)
352
+ {
353
+ if (!pspec || !string)
354
+ {
355
+ return FALSE;
356
+ }
357
+ return fnmatch(pspec->pattern.c_str(), string, 0) == 0 ? TRUE : FALSE;
358
+ }
359
+
360
+ void g_pattern_spec_free(GPatternSpec *pspec)
361
+ {
362
+ if (!pspec)
363
+ {
364
+ return;
365
+ }
366
+ pspec->pattern.~basic_string();
367
+ g_free(pspec);
368
+ }
369
+
370
+ GString *g_string_sized_new(gsize dfl_size)
371
+ {
372
+ auto *str = static_cast<GString *>(g_malloc(sizeof(GString)));
373
+ str->allocated_len = std::max<gsize>(dfl_size + 1, 16);
374
+ str->len = 0;
375
+ str->str = static_cast<gchar *>(g_malloc(str->allocated_len));
376
+ str->str[0] = '\0';
377
+ return str;
378
+ }
379
+
380
+ GString *g_string_append(GString *string, const gchar *val)
381
+ {
382
+ if (!string || !val)
383
+ {
384
+ return string;
385
+ }
386
+ const gsize add_len = strlen(val);
387
+ const gsize needed = string->len + add_len + 1;
388
+ if (needed > string->allocated_len)
389
+ {
390
+ gsize next = string->allocated_len;
391
+ while (next < needed)
392
+ {
393
+ next *= 2;
394
+ }
395
+ string->str = static_cast<gchar *>(g_realloc(string->str, next));
396
+ string->allocated_len = next;
397
+ }
398
+
399
+ memcpy(string->str + string->len, val, add_len + 1);
400
+ string->len += add_len;
401
+ return string;
402
+ }
403
+
404
+ gchar *g_string_free(GString *string, gboolean free_segment)
405
+ {
406
+ if (!string)
407
+ {
408
+ return nullptr;
409
+ }
410
+
411
+ gchar *segment = string->str;
412
+ if (free_segment)
413
+ {
414
+ g_free(segment);
415
+ segment = nullptr;
416
+ }
417
+
418
+ g_free(string);
419
+ return segment;
420
+ }
421
+
422
+ GPtrArray *g_ptr_array_new(void)
423
+ {
424
+ auto *array = static_cast<GPtrArray *>(g_malloc(sizeof(GPtrArray)));
425
+ array->pdata = nullptr;
426
+ array->len = 0;
427
+ array->allocated_len = 0;
428
+ return array;
429
+ }
430
+
431
+ void g_ptr_array_set_size(GPtrArray *array, gint length)
432
+ {
433
+ if (!array || length < 0)
434
+ {
435
+ return;
436
+ }
437
+
438
+ const guint target = static_cast<guint>(length);
439
+ if (target > array->allocated_len)
440
+ {
441
+ guint next = array->allocated_len == 0 ? 8U : array->allocated_len;
442
+ while (next < target)
443
+ {
444
+ next *= 2U;
445
+ }
446
+ array->pdata = static_cast<gpointer *>(g_realloc(array->pdata, sizeof(gpointer) * next));
447
+ for (guint i = array->allocated_len; i < next; ++i)
448
+ {
449
+ array->pdata[i] = nullptr;
450
+ }
451
+ array->allocated_len = next;
452
+ }
453
+
454
+ if (target > array->len)
455
+ {
456
+ for (guint i = array->len; i < target; ++i)
457
+ {
458
+ array->pdata[i] = nullptr;
459
+ }
460
+ }
461
+
462
+ array->len = target;
463
+ }
464
+
465
+ gpointer *g_ptr_array_free(GPtrArray *array, gboolean free_segment)
466
+ {
467
+ if (!array)
468
+ {
469
+ return nullptr;
470
+ }
471
+
472
+ gpointer *segment = array->pdata;
473
+ if (free_segment)
474
+ {
475
+ g_free(segment);
476
+ segment = nullptr;
477
+ }
478
+
479
+ g_free(array);
480
+ return segment;
481
+ }
482
+
483
+ void g_warning(const gchar *format, ...)
484
+ {
485
+ va_list args;
486
+ va_start(args, format);
487
+ std::string message = vformat(format, args);
488
+ va_end(args);
489
+ fprintf(stderr, "%s\n", message.c_str());
490
+ }
491
+
492
+ void g_set_error(GError **err, gint domain, gint code, const gchar *format, ...)
493
+ {
494
+ if (!err)
495
+ {
496
+ return;
497
+ }
498
+
499
+ va_list args;
500
+ va_start(args, format);
501
+ std::string message = vformat(format, args);
502
+ va_end(args);
503
+
504
+ auto *e = static_cast<GError *>(g_malloc(sizeof(GError)));
505
+ e->domain = domain;
506
+ e->code = code;
507
+ e->message = g_strdup(message.c_str());
508
+ *err = e;
509
+ }
510
+
511
+ gunichar g_utf8_get_char(const gchar *p)
512
+ {
513
+ if (!p || *p == '\0')
514
+ {
515
+ return 0;
516
+ }
517
+
518
+ utf8proc_int32_t codepoint = 0;
519
+ utf8proc_ssize_t len = utf8proc_iterate(reinterpret_cast<const utf8proc_uint8_t *>(p), -1, &codepoint);
520
+ if (len < 0)
521
+ {
522
+ return static_cast<gunichar>(*reinterpret_cast<const unsigned char *>(p));
523
+ }
524
+ return static_cast<gunichar>(codepoint);
525
+ }
526
+
527
+ const gchar *g_utf8_next_char(const gchar *p)
528
+ {
529
+ if (!p || *p == '\0')
530
+ {
531
+ return p;
532
+ }
533
+
534
+ const int width = utf8proc_charwidth(static_cast<utf8proc_int8_t>(*p));
535
+ if (width <= 0)
536
+ {
537
+ return p + 1;
538
+ }
539
+ return p + width;
540
+ }
541
+
542
+ gchar *g_utf8_casefold(const gchar *str, gssize len)
543
+ {
544
+ if (!str)
545
+ {
546
+ return nullptr;
547
+ }
548
+
549
+ utf8proc_uint8_t *mapped = nullptr;
550
+ utf8proc_ssize_t rc = utf8proc_map(
551
+ reinterpret_cast<const utf8proc_uint8_t *>(str),
552
+ static_cast<utf8proc_ssize_t>(len),
553
+ &mapped,
554
+ static_cast<utf8proc_option_t>(UTF8PROC_CASEFOLD | UTF8PROC_STABLE));
555
+
556
+ if (rc < 0 || !mapped)
557
+ {
558
+ return g_strdup("");
559
+ }
560
+
561
+ return reinterpret_cast<gchar *>(mapped);
562
+ }
563
+
564
+ gboolean g_unichar_isspace(gunichar c)
565
+ {
566
+ if (c <= 0x7F)
567
+ {
568
+ return (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v') ? TRUE : FALSE;
569
+ }
570
+
571
+ const utf8proc_category_t cat = utf8proc_category(static_cast<utf8proc_int32_t>(c));
572
+ return (cat == UTF8PROC_CATEGORY_ZS || cat == UTF8PROC_CATEGORY_ZL || cat == UTF8PROC_CATEGORY_ZP) ? TRUE : FALSE;
573
+ }
574
+
575
+ gunichar g_unichar_tolower(gunichar c)
576
+ {
577
+ return static_cast<gunichar>(utf8proc_tolower(static_cast<utf8proc_int32_t>(c)));
578
+ }
579
+
580
+ static gboolean walk_element(
581
+ GMarkupParseContext *context,
582
+ tinyxml2::XMLElement *element,
583
+ GError **error)
584
+ {
585
+ context->element_stack.emplace_back(element->Name() ? element->Name() : "");
586
+ context->current_line = element->GetLineNum();
587
+ context->current_column = 0;
588
+
589
+ std::vector<const gchar *> attr_names;
590
+ std::vector<const gchar *> attr_values;
591
+
592
+ for (const tinyxml2::XMLAttribute *attr = element->FirstAttribute(); attr; attr = attr->Next())
593
+ {
594
+ attr_names.push_back(attr->Name());
595
+ attr_values.push_back(attr->Value());
596
+ }
597
+ attr_names.push_back(nullptr);
598
+ attr_values.push_back(nullptr);
599
+
600
+ if (context->parser && context->parser->start_element)
601
+ {
602
+ context->parser->start_element(
603
+ context,
604
+ context->element_stack.back().c_str(),
605
+ attr_names.data(),
606
+ attr_values.data(),
607
+ context->user_data,
608
+ error);
609
+
610
+ if (error && *error)
611
+ {
612
+ context->element_stack.pop_back();
613
+ return FALSE;
614
+ }
615
+ }
616
+
617
+ for (tinyxml2::XMLNode *child = element->FirstChild(); child; child = child->NextSibling())
618
+ {
619
+ if (auto *text = child->ToText())
620
+ {
621
+ if (context->parser && context->parser->text)
622
+ {
623
+ const char *value = text->Value();
624
+ if (value)
625
+ {
626
+ context->current_line = text->GetLineNum();
627
+ context->parser->text(context, value, strlen(value), context->user_data, error);
628
+ if (error && *error)
629
+ {
630
+ context->element_stack.pop_back();
631
+ return FALSE;
632
+ }
633
+ }
634
+ }
635
+ continue;
636
+ }
637
+
638
+ if (auto *nested = child->ToElement())
639
+ {
640
+ if (!walk_element(context, nested, error))
641
+ {
642
+ context->element_stack.pop_back();
643
+ return FALSE;
644
+ }
645
+ }
646
+ }
647
+
648
+ if (context->parser && context->parser->end_element)
649
+ {
650
+ context->parser->end_element(
651
+ context,
652
+ context->element_stack.back().c_str(),
653
+ context->user_data,
654
+ error);
655
+ if (error && *error)
656
+ {
657
+ context->element_stack.pop_back();
658
+ return FALSE;
659
+ }
660
+ }
661
+
662
+ context->element_stack.pop_back();
663
+ return TRUE;
664
+ }
665
+
666
+ GMarkupParseContext *g_markup_parse_context_new(
667
+ const GMarkupParser *parser,
668
+ GMarkupParseFlags,
669
+ gpointer user_data,
670
+ GDestroyNotify user_data_dnotify)
671
+ {
672
+ auto *ctx = static_cast<GMarkupParseContext *>(g_malloc(sizeof(GMarkupParseContext)));
673
+ new (ctx) GMarkupParseContext();
674
+ ctx->parser = parser;
675
+ ctx->user_data = user_data;
676
+ ctx->user_data_dnotify = user_data_dnotify;
677
+ return ctx;
678
+ }
679
+
680
+ gboolean g_markup_parse_context_parse(
681
+ GMarkupParseContext *context,
682
+ const gchar *text,
683
+ gssize text_len,
684
+ GError **error)
685
+ {
686
+ if (!context || !text)
687
+ {
688
+ if (error)
689
+ {
690
+ g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Invalid markup input");
691
+ }
692
+ return FALSE;
693
+ }
694
+
695
+ tinyxml2::XMLDocument doc;
696
+ tinyxml2::XMLError rc;
697
+ if (text_len < 0)
698
+ {
699
+ rc = doc.Parse(text);
700
+ }
701
+ else
702
+ {
703
+ rc = doc.Parse(text, static_cast<size_t>(text_len));
704
+ }
705
+
706
+ if (rc != tinyxml2::XML_SUCCESS)
707
+ {
708
+ context->current_line = doc.ErrorLineNum();
709
+ if (error)
710
+ {
711
+ g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "%s", doc.ErrorStr());
712
+ }
713
+ return FALSE;
714
+ }
715
+
716
+ for (tinyxml2::XMLElement *root = doc.FirstChildElement(); root; root = root->NextSiblingElement())
717
+ {
718
+ if (!walk_element(context, root, error))
719
+ {
720
+ return FALSE;
721
+ }
722
+ }
723
+
724
+ return TRUE;
725
+ }
726
+
727
+ void g_markup_parse_context_free(GMarkupParseContext *context)
728
+ {
729
+ if (!context)
730
+ {
731
+ return;
732
+ }
733
+
734
+ if (context->user_data_dnotify)
735
+ {
736
+ context->user_data_dnotify(context->user_data);
737
+ }
738
+
739
+ context->~_GMarkupParseContext();
740
+ g_free(context);
741
+ }
742
+
743
+ const gchar *g_markup_parse_context_get_element(GMarkupParseContext *context)
744
+ {
745
+ if (!context || context->element_stack.empty())
746
+ {
747
+ return nullptr;
748
+ }
749
+
750
+ return context->element_stack.back().c_str();
751
+ }
752
+
753
+ void g_markup_parse_context_get_position(GMarkupParseContext *context, gint *line_number, gint *char_number)
754
+ {
755
+ if (!context)
756
+ {
757
+ if (line_number)
758
+ {
759
+ *line_number = 1;
760
+ }
761
+ if (char_number)
762
+ {
763
+ *char_number = 0;
764
+ }
765
+ return;
766
+ }
767
+
768
+ if (line_number)
769
+ {
770
+ *line_number = context->current_line;
771
+ }
772
+ if (char_number)
773
+ {
774
+ *char_number = context->current_column;
775
+ }
776
+ }
777
+
778
+ gchar *g_markup_vprintf_escaped(const gchar *format, va_list args)
779
+ {
780
+ if (!format)
781
+ {
782
+ return g_strdup("");
783
+ }
784
+
785
+ std::string raw = vformat(format, args);
786
+ std::string escaped = xml_escape(raw);
787
+ return g_strdup(escaped.c_str());
788
+ }
789
+
790
+ gchar *g_markup_printf_escaped(const gchar *format, ...)
791
+ {
792
+ va_list args;
793
+ va_start(args, format);
794
+ gchar *result = g_markup_vprintf_escaped(format, args);
795
+ va_end(args);
796
+ return result;
797
+ }
798
+
799
+ } // extern "C"