koffi 2.12.3 → 2.12.5-beta.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,109 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ # this software and associated documentation files (the “Software”), to deal in
7
+ # the Software without restriction, including without limitation the rights to use,
8
+ # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
9
+ # Software, and to permit persons to whom the Software is furnished to do so,
10
+ # subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ # OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ # This script uses the database of mimetypes distributed here: https://github.com/jshttp/mime-db
25
+ # to produce the X-header file mimetypes.inc
26
+
27
+ import os
28
+ import argparse
29
+
30
+ CRC32_POLY = 0xEDB88320
31
+ CRC32C_POLY = 0x82F63B78
32
+ CRC64_XZ_POLY = 0xC96C5795D7870F42
33
+ CRC64_NVME_POLY = 0x9A6C9329AC4BC9B5
34
+
35
+ LICENSE_HEADER = """// Copyright (C) 2025 Niels Martignène <niels.martignene@protonmail.com>
36
+
37
+ // Permission is hereby granted, free of charge, to any person obtaining a copy of
38
+ // this software and associated documentation files (the “Software”), to deal in
39
+ // the Software without restriction, including without limitation the rights to use,
40
+ // copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
41
+ // Software, and to permit persons to whom the Software is furnished to do so,
42
+ // subject to the following conditions:
43
+
44
+ // The above copyright notice and this permission notice shall be included in all
45
+ // copies or substantial portions of the Software.
46
+
47
+ // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
48
+ // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
49
+ // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
50
+ // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
51
+ // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
52
+ // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
53
+ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
54
+ // OTHER DEALINGS IN THE SOFTWARE."""
55
+
56
+ def write_crc32_table(f, name, poly):
57
+ f.write(f'static const uint32_t {name}[256] = {{')
58
+ for i in range(0, 256):
59
+ value = i
60
+ for j in range(0, 8):
61
+ value = (value >> 1) ^ (poly if value & 1 else 0)
62
+
63
+ if i % 6 == 0:
64
+ f.write('\n ')
65
+ f.write(f' 0x{value:08X}u,')
66
+ f.write('\n};\n\n')
67
+
68
+ def write_crc64_tables(f, name, poly):
69
+ for table in range(0, 16):
70
+ count = table * 8 + 8
71
+
72
+ f.write(f'static const uint64_t {name}{table}[256] = {{')
73
+ for i in range(0, 256):
74
+ value = i
75
+ for j in range(0, count):
76
+ value = (value >> 1) ^ (poly if value & 1 else 0)
77
+
78
+ if i % 4 == 0:
79
+ f.write('\n ')
80
+ f.write(f' 0x{value:016X}ull,')
81
+ f.write('\n};\n')
82
+
83
+ f.write('\n')
84
+
85
+ if __name__ == "__main__":
86
+ parser = argparse.ArgumentParser(description = 'Update CRC tables header file')
87
+ parser.add_argument('-O', '--output_file', dest = 'output_file', action = 'store', help = 'Output file')
88
+ args = parser.parse_args()
89
+
90
+ if args.output_file is None:
91
+ output_file = os.path.join(os.path.dirname(__file__), 'crc.inc')
92
+ else:
93
+ output_file = args.output_file
94
+
95
+ with open(output_file, 'w') as f:
96
+ f.write(f'''{LICENSE_HEADER}
97
+
98
+ // This file is autogenerated by crc_gen.py
99
+
100
+ namespace RG {{
101
+
102
+ ''')
103
+
104
+ write_crc32_table(f, 'Crc32Table', CRC32_POLY)
105
+ write_crc32_table(f, 'Crc32CTable', CRC32C_POLY)
106
+ write_crc64_tables(f, 'Crc64XzTable', CRC64_XZ_POLY)
107
+ write_crc64_tables(f, 'Crc64NvmeTable', CRC64_NVME_POLY)
108
+
109
+ f.write('}\n')
@@ -242,24 +242,25 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
242
242
  return env.Null();
243
243
  }
244
244
 
245
- bool named = info.Length() > 1;
245
+ bool skip = (info.Length() > 1);
246
+ bool named = skip && !IsNullOrUndefined(info[0]);
246
247
  bool redefine = named && CheckValueTag(instance, info[0], &TypeInfoMarker);
247
248
 
248
249
  if (named && !info[0].IsString() && !redefine) {
249
250
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
250
251
  return env.Null();
251
252
  }
252
- if (!IsObject(info[named])) {
253
+ if (!IsObject(info[skip])) {
253
254
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
254
255
  return env.Null();
255
256
  }
256
257
 
257
258
  Napi::String name = info[0].As<Napi::String>();
258
- Napi::Object obj = info[named].As<Napi::Object>();
259
+ Napi::Object obj = info[skip].As<Napi::Object>();
259
260
  Napi::Array keys = GetOwnPropertyNames(obj);
260
261
 
261
262
  RG_DEFER_NC(err_guard, count = instance->types.count) {
262
- Size start = count + !named;
263
+ Size start = count + !skip;
263
264
 
264
265
  for (Size i = start; i < instance->types.count; i++) {
265
266
  const TypeInfo *it = &instance->types[i];
@@ -409,24 +410,25 @@ static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
409
410
  return env.Null();
410
411
  }
411
412
 
412
- bool named = info.Length() > 1;
413
+ bool skip = (info.Length() > 1);
414
+ bool named = skip && !IsNullOrUndefined(info[0]);
413
415
  bool redefine = named && CheckValueTag(instance, info[0], &TypeInfoMarker);
414
416
 
415
417
  if (named && !info[0].IsString() && !redefine) {
416
418
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
417
419
  return env.Null();
418
420
  }
419
- if (!IsObject(info[named])) {
421
+ if (!IsObject(info[skip])) {
420
422
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
421
423
  return env.Null();
422
424
  }
423
425
 
424
426
  Napi::String name = info[0].As<Napi::String>();
425
- Napi::Object obj = info[named].As<Napi::Object>();
427
+ Napi::Object obj = info[skip].As<Napi::Object>();
426
428
  Napi::Array keys = GetOwnPropertyNames(obj);
427
429
 
428
430
  RG_DEFER_NC(err_guard, count = instance->types.count) {
429
- Size start = count + !named;
431
+ Size start = count + !skip;
430
432
 
431
433
  for (Size i = start; i < instance->types.count; i++) {
432
434
  const TypeInfo *it = &instance->types[i];
@@ -584,7 +586,7 @@ static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
584
586
  Napi::Env env = info.Env();
585
587
  InstanceData *instance = env.GetInstanceData<InstanceData>();
586
588
 
587
- bool named = (info.Length() >= 1);
589
+ bool named = (info.Length() >= 1) && !IsNullOrUndefined(info[0]);
588
590
 
589
591
  if (named && !info[0].IsString()) {
590
592
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
@@ -621,7 +623,8 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
621
623
  return env.Null();
622
624
  }
623
625
 
624
- bool named = (info.Length() >= 2 && !info[1].IsNumber());
626
+ bool skip = (info.Length() > 1) && !info[1].IsNumber();
627
+ bool named = skip && !IsNullOrUndefined(info[0]);
625
628
 
626
629
  if (named && !info[0].IsString()) {
627
630
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
@@ -630,18 +633,18 @@ static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
630
633
 
631
634
  std::string name = named ? info[0].As<Napi::String>() : std::string();
632
635
 
633
- const TypeInfo *type = ResolveType(info[named]);
636
+ const TypeInfo *type = ResolveType(info[skip]);
634
637
  if (!type)
635
638
  return env.Null();
636
639
 
637
640
  int count = 0;
638
- if (info.Length() >= 2u + named) {
639
- if (!info[1 + named].IsNumber()) {
640
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 + named]));
641
+ if (info.Length() >= 2u + skip) {
642
+ if (!info[1 + skip].IsNumber()) {
643
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 + skip]));
641
644
  return env.Null();
642
645
  }
643
646
 
644
- count = info[1 + named].As<Napi::Number>();
647
+ count = info[1 + skip].As<Napi::Number>();
645
648
 
646
649
  if (count < 1 || count > 4) {
647
650
  ThrowError<Napi::TypeError>(env, "Value of count must be between 1 and 4");
@@ -727,7 +730,8 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
727
730
  return env.Null();
728
731
  }
729
732
 
730
- bool named = (info.Length() >= 2 && !info[1].IsFunction());
733
+ bool skip = (info.Length() > 1) && !info[1].IsFunction();
734
+ bool named = skip && !IsNullOrUndefined(info[0]);
731
735
 
732
736
  if (named && !info[0].IsString()) {
733
737
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
@@ -736,7 +740,7 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
736
740
 
737
741
  Napi::String name = info[0].As<Napi::String>();
738
742
 
739
- const TypeInfo *src = ResolveType(info[named]);
743
+ const TypeInfo *src = ResolveType(info[skip]);
740
744
  if (!src)
741
745
  return env.Null();
742
746
  if (src->primitive != PrimitiveKind::Pointer &&
@@ -753,8 +757,8 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
753
757
 
754
758
  DisposeFunc *dispose;
755
759
  Napi::Function dispose_func;
756
- if (info.Length() >= 2u + named && !IsNullOrUndefined(info[1 + named])) {
757
- Napi::Function func = info[1 + named].As<Napi::Function>();
760
+ if (info.Length() >= 2u + skip && !IsNullOrUndefined(info[1 + skip])) {
761
+ Napi::Function func = info[1 + skip].As<Napi::Function>();
758
762
 
759
763
  if (!func.IsFunction()) {
760
764
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, func));
@@ -989,7 +993,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
989
993
  return WrapType(env, instance, type);
990
994
  }
991
995
 
992
- static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *out_func)
996
+ static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete, FunctionInfo *out_func)
993
997
  {
994
998
  Napi::Env env = info.Env();
995
999
  InstanceData *instance = env.GetInstanceData<InstanceData>();
@@ -1010,6 +1014,8 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *o
1010
1014
  parameters = info[3u].As<Napi::Array>();
1011
1015
  }
1012
1016
 
1017
+ bool named = true;
1018
+
1013
1019
  #if defined(_WIN32)
1014
1020
  if (name.IsNumber()) {
1015
1021
  out_func->ordinal_name = name.As<Napi::Number>().Int32Value();
@@ -1017,11 +1023,16 @@ static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *o
1017
1023
  }
1018
1024
  #endif
1019
1025
  if (!name.IsString()) {
1020
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
1021
- return false;
1026
+ if (!concrete && IsNullOrUndefined(name)) {
1027
+ named = false;
1028
+ } else {
1029
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
1030
+ return false;
1031
+ }
1022
1032
  }
1023
1033
 
1024
- out_func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
1034
+ // Leave anonymous naming responsibility to caller
1035
+ out_func->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr : nullptr;
1025
1036
 
1026
1037
  out_func->ret.type = ResolveType(ret);
1027
1038
  if (!out_func->ret.type)
@@ -1086,7 +1097,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1086
1097
  RG_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
1087
1098
 
1088
1099
  if (info.Length() >= 3) {
1089
- if (!ParseClassicFunction(info, func))
1100
+ if (!ParseClassicFunction(info, false, func))
1090
1101
  return env.Null();
1091
1102
  } else if (info.Length() >= 1) {
1092
1103
  if (!info[0].IsString()) {
@@ -1095,13 +1106,19 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1095
1106
  }
1096
1107
 
1097
1108
  std::string proto = info[0u].As<Napi::String>();
1098
- if (!ParsePrototype(env, proto.c_str(), func))
1109
+ if (!ParsePrototype(env, proto.c_str(), false, func))
1099
1110
  return env.Null();
1100
1111
  } else {
1101
1112
  ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, got %1", info.Length());
1102
1113
  return env.Null();
1103
1114
  }
1104
1115
 
1116
+ bool named = func->name;
1117
+
1118
+ if (!named) {
1119
+ func->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
1120
+ }
1121
+
1105
1122
  if (!AnalyseFunction(env, instance, func))
1106
1123
  return env.Null();
1107
1124
 
@@ -1112,7 +1129,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1112
1129
  func->required_parameters += 2;
1113
1130
 
1114
1131
  // We cannot fail after this check
1115
- if (instance->types_map.Find(func->name)) {
1132
+ if (named && instance->types_map.Find(func->name)) {
1116
1133
  ThrowError<Napi::Error>(env, "Duplicate type name '%1'", func->name);
1117
1134
  return env.Null();
1118
1135
  }
@@ -1649,7 +1666,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
1649
1666
  func->lib = lib->Ref();
1650
1667
 
1651
1668
  if (info.Length() >= 3) {
1652
- if (!ParseClassicFunction(info, func))
1669
+ if (!ParseClassicFunction(info, true, func))
1653
1670
  return env.Null();
1654
1671
  } else if (info.Length() >= 1) {
1655
1672
  if (!info[0].IsString()) {
@@ -1658,7 +1675,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
1658
1675
  }
1659
1676
 
1660
1677
  std::string proto = info[0u].As<Napi::String>();
1661
- if (!ParsePrototype(env, proto.c_str(), func))
1678
+ if (!ParsePrototype(env, proto.c_str(), true, func))
1662
1679
  return env.Null();
1663
1680
  } else {
1664
1681
  ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, got %1", info.Length());
@@ -27,7 +27,7 @@
27
27
 
28
28
  namespace RG {
29
29
 
30
- bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
30
+ bool PrototypeParser::Parse(const char *str, bool concrete, FunctionInfo *out_func)
31
31
  {
32
32
  tokens.Clear();
33
33
  offset = 0;
@@ -41,7 +41,18 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
41
41
  return false;
42
42
  }
43
43
  offset += (offset < tokens.len && DetectCallConvention(tokens[offset], &out_func->convention));
44
- out_func->name = ParseIdentifier();
44
+
45
+ if (offset >= tokens.len) {
46
+ MarkError("Unexpected end of prototype, expected identifier");
47
+ return false;
48
+ }
49
+ if (IsIdentifier(tokens[offset])) {
50
+ Span<const char> tok = tokens[offset++];
51
+ out_func->name = DuplicateString(tok, &instance->str_alloc).ptr;
52
+ } else if (concrete) {
53
+ MarkError("Unexpected token '%1', expected identifier", tokens[offset]);
54
+ return false;
55
+ }
45
56
 
46
57
  Consume("(");
47
58
  offset += (offset + 1 < tokens.len && tokens[offset] == "void" && tokens[offset + 1] == ")");
@@ -169,23 +180,6 @@ const TypeInfo *PrototypeParser::ParseType(int *out_directions)
169
180
  return instance->void_type;
170
181
  }
171
182
 
172
- const char *PrototypeParser::ParseIdentifier()
173
- {
174
- if (offset >= tokens.len) {
175
- MarkError("Unexpected end of prototype, expected identifier");
176
- return "";
177
- }
178
- if (!IsIdentifier(tokens[offset])) {
179
- MarkError("Unexpected token '%1', expected identifier", tokens[offset]);
180
- return "";
181
- }
182
-
183
- Span<const char> tok = tokens[offset++];
184
- const char *ident = DuplicateString(tok, &instance->str_alloc).ptr;
185
-
186
- return ident;
187
- }
188
-
189
183
  bool PrototypeParser::Consume(const char *expect)
190
184
  {
191
185
  if (offset >= tokens.len) {
@@ -217,10 +211,10 @@ bool PrototypeParser::IsIdentifier(Span<const char> tok) const
217
211
  return IsAsciiAlpha(tok[0]) || tok[0] == '_';
218
212
  }
219
213
 
220
- bool ParsePrototype(Napi::Env env, const char *str, FunctionInfo *out_func)
214
+ bool ParsePrototype(Napi::Env env, const char *str, bool concrete, FunctionInfo *out_func)
221
215
  {
222
216
  PrototypeParser parser(env);
223
- return parser.Parse(str, out_func);
217
+ return parser.Parse(str, concrete, out_func);
224
218
  }
225
219
 
226
220
  }
@@ -44,13 +44,12 @@ class PrototypeParser {
44
44
  public:
45
45
  PrototypeParser(Napi::Env env) : env(env), instance(env.GetInstanceData<InstanceData>()) {}
46
46
 
47
- bool Parse(const char *str, FunctionInfo *out_func);
47
+ bool Parse(const char *str, bool concrete, FunctionInfo *out_func);
48
48
 
49
49
  private:
50
50
  void Tokenize(const char *str);
51
51
 
52
52
  const TypeInfo *ParseType(int *out_directions);
53
- const char *ParseIdentifier();
54
53
 
55
54
  bool Consume(const char *expect);
56
55
  bool Match(const char *expect);
@@ -68,6 +67,6 @@ private:
68
67
  }
69
68
  };
70
69
 
71
- bool ParsePrototype(Napi::Env env, const char *str, FunctionInfo *out_func);
70
+ bool ParsePrototype(Napi::Env env, const char *str, bool concrete, FunctionInfo *out_func);
72
71
 
73
72
  }