koffi 2.5.10 → 2.5.11

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@
4
4
 
5
5
  ### Koffi 2.5
6
6
 
7
+ #### Koffi 2.5.11
8
+
9
+ - Support casting function pointers with [koffi.as()](parameters.md#input-polymorphism)
10
+ - Build in C++20 mode
11
+
7
12
  #### Koffi 2.5.10
8
13
 
9
14
  - Fix CMake regression when client has to build Koffi
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.5.10",
4
- "stable": "2.5.10",
3
+ "version": "2.5.11",
4
+ "stable": "2.5.11",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -801,6 +801,108 @@ bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags,
801
801
  return false;
802
802
  }
803
803
 
804
+ bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags, Span<const char> *out_remaining)
805
+ {
806
+ uint64_t size = 0;
807
+
808
+ if (!ParseInt(str, &size, flags & ~(int)ParseFlag::End, &str))
809
+ return false;
810
+ if (size > INT64_MAX) [[unlikely]]
811
+ goto overflow;
812
+
813
+ if (str.len) {
814
+ uint64_t multiplier = 1;
815
+ int next = 1;
816
+
817
+ switch (str[0]) {
818
+ case 'B': { multiplier = 1; } break;
819
+ case 'k': { multiplier = 1000; } break;
820
+ case 'M': { multiplier = 1000000; } break;
821
+ case 'G': { multiplier = 1000000000; } break;
822
+ case 'T': { multiplier = 1000000000000; } break;
823
+ default: { next = 0; } break;
824
+ }
825
+
826
+ if ((flags & (int)ParseFlag::End) && str.len > next) [[unlikely]] {
827
+ if (flags & (int)ParseFlag::Log) {
828
+ LogError("Unknown size unit '%1'", str[0]);
829
+ }
830
+ return false;
831
+ }
832
+ str = str.Take(next, str.len - next);
833
+
834
+ uint64_t total = size * multiplier;
835
+ if ((size && total / size != multiplier) || total > INT64_MAX) [[unlikely]]
836
+ goto overflow;
837
+ size = total;
838
+ }
839
+
840
+ *out_size = (int64_t)size;
841
+ if (out_remaining) {
842
+ *out_remaining = str;
843
+ }
844
+ return true;
845
+
846
+ overflow:
847
+ if (flags & (int)ParseFlag::Log) {
848
+ LogError("Size value is too high");
849
+ }
850
+ return false;
851
+ }
852
+
853
+ bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags, Span<const char> *out_remaining)
854
+ {
855
+ uint64_t duration = 0;
856
+
857
+ if (!ParseInt(str, &duration, flags & ~(int)ParseFlag::End, &str))
858
+ return false;
859
+ if (duration > INT64_MAX) [[unlikely]]
860
+ goto overflow;
861
+
862
+ if (str.len) {
863
+ uint64_t multiplier = 1;
864
+ int next = 1;
865
+
866
+ switch (str[0]) {
867
+ case 's': { multiplier = 1000; } break;
868
+ case 'm': { multiplier = 60000; } break;
869
+ case 'h': { multiplier = 3600000; } break;
870
+ case 'd': { multiplier = 86400000; } break;
871
+ default: { next = 0; } break;
872
+ }
873
+
874
+ if ((flags & (int)ParseFlag::End) && str.len > next) [[unlikely]] {
875
+ if (flags & (int)ParseFlag::Log) {
876
+ LogError("Unknown duration unit '%1'", str[0]);
877
+ }
878
+ return false;
879
+ }
880
+ str = str.Take(next, str.len - next);
881
+
882
+ uint64_t total = duration * multiplier;
883
+ if ((duration && total / duration != multiplier) || total > INT64_MAX) [[unlikely]]
884
+ goto overflow;
885
+ duration = total;
886
+ } else {
887
+ uint64_t total = duration * 1000;
888
+ if ((duration && total / duration != 1000) || total > INT64_MAX) [[unlikely]]
889
+ goto overflow;
890
+ duration = total;
891
+ }
892
+
893
+ *out_duration = (int64_t)duration;
894
+ if (out_remaining) {
895
+ *out_remaining = str;
896
+ }
897
+ return true;
898
+
899
+ overflow:
900
+ if (flags & (int)ParseFlag::Log) {
901
+ LogError("Duration value is too high");
902
+ }
903
+ return false;
904
+ }
905
+
804
906
  // ------------------------------------------------------------------------
805
907
  // Format
806
908
  // ------------------------------------------------------------------------
@@ -6760,6 +6862,16 @@ bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer)
6760
6862
  return true;
6761
6863
  }
6762
6864
 
6865
+ bool IsCompressorAvailable(CompressionType compression_type)
6866
+ {
6867
+ return CompressorFunctions[(int)compression_type];
6868
+ }
6869
+
6870
+ bool IsDecompressorAvailable(CompressionType compression_type)
6871
+ {
6872
+ return DecompressorFunctions[(int)compression_type];
6873
+ }
6874
+
6763
6875
  // ------------------------------------------------------------------------
6764
6876
  // INI
6765
6877
  // ------------------------------------------------------------------------
@@ -3315,41 +3315,38 @@ static inline int CmpStr(const char *str1, Span<const char> str2)
3315
3315
  static inline int CmpStr(const char *str1, const char *str2)
3316
3316
  { return strcmp(str1, str2); }
3317
3317
 
3318
- static inline Size StartsWith(Span<const char> str, Span<const char> prefix)
3318
+ static inline bool StartsWith(Span<const char> str, Span<const char> prefix)
3319
3319
  {
3320
3320
  Size i = 0;
3321
3321
  while (i < str.len && i < prefix.len) {
3322
3322
  if (str[i] != prefix[i])
3323
- return 0;
3324
-
3323
+ return false;
3325
3324
  i++;
3326
3325
  }
3327
3326
 
3328
- return (i == prefix.len) ? i : 0;
3327
+ return (i == prefix.len);
3329
3328
  }
3330
- static inline Size StartsWith(Span<const char> str, const char *prefix)
3329
+ static inline bool StartsWith(Span<const char> str, const char *prefix)
3331
3330
  {
3332
3331
  Size i = 0;
3333
3332
  while (i < str.len && prefix[i]) {
3334
3333
  if (str[i] != prefix[i])
3335
- return 0;
3336
-
3334
+ return false;
3337
3335
  i++;
3338
3336
  }
3339
3337
 
3340
- return !prefix[i] ? i : 0;
3338
+ return !prefix[i];
3341
3339
  }
3342
- static inline Size StartsWith(const char *str, const char *prefix)
3340
+ static inline bool StartsWith(const char *str, const char *prefix)
3343
3341
  {
3344
3342
  Size i = 0;
3345
3343
  while (str[i] && prefix[i]) {
3346
3344
  if (str[i] != prefix[i])
3347
- return 0;
3348
-
3345
+ return false;
3349
3346
  i++;
3350
3347
  }
3351
3348
 
3352
- return !prefix[i] ? i : 0;
3349
+ return !prefix[i];
3353
3350
  }
3354
3351
 
3355
3352
  static inline bool EndsWith(Span<const char> str, const char *suffix)
@@ -3703,6 +3700,31 @@ overflow:
3703
3700
  bool ParseBool(Span<const char> str, bool *out_value, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3704
3701
  Span<const char> *out_remaining = nullptr);
3705
3702
 
3703
+ bool ParseSize(Span<const char> str, int64_t *out_size, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3704
+ Span<const char> *out_remaining = nullptr);
3705
+ #if RG_SIZE_MAX < INT64_MAX
3706
+ static inline bool ParseSize(Span<const char> str, Size *out_size,
3707
+ unsigned int flags = RG_DEFAULT_PARSE_FLAGS, Span<const char> *out_remaining = nullptr)
3708
+ {
3709
+ int64_t size = 0;
3710
+ if (!ParseSize(str, &size, flags, out_remaining))
3711
+ return false;
3712
+
3713
+ if (size > RG_SIZE_MAX) [[unlikely]] {
3714
+ if (flags & (int)ParseFlag::Log) {
3715
+ LogError("Size value is too high");
3716
+ }
3717
+ return false;
3718
+ }
3719
+
3720
+ *out_size = (Size)size;
3721
+ return true;
3722
+ }
3723
+ #endif
3724
+
3725
+ bool ParseDuration(Span<const char> str, int64_t *out_duration, unsigned int flags = RG_DEFAULT_PARSE_FLAGS,
3726
+ Span<const char> *out_remaining = nullptr);
3727
+
3706
3728
  static inline Size EncodeUtf8(int32_t c, char out_buf[4])
3707
3729
  {
3708
3730
  if (c < 0x80) {
@@ -4096,11 +4118,11 @@ bool NotifySystemd();
4096
4118
  })()
4097
4119
  #endif
4098
4120
 
4121
+ void InitRG();
4122
+ int Main(int argc, char **argv);
4123
+
4099
4124
  static inline int RunApp(int argc, char **argv)
4100
4125
  {
4101
- void InitRG();
4102
- int Main(int argc, char **argv);
4103
-
4104
4126
  InitRG();
4105
4127
  return Main(argc, argv);
4106
4128
  }
@@ -4658,6 +4680,9 @@ public:
4658
4680
 
4659
4681
  bool SpliceStream(StreamReader *reader, int64_t max_len, StreamWriter *writer);
4660
4682
 
4683
+ bool IsCompressorAvailable(CompressionType compression_type);
4684
+ bool IsDecompressorAvailable(CompressionType compression_type);
4685
+
4661
4686
  // For convenience, don't close them
4662
4687
  extern StreamReader stdin_st;
4663
4688
  extern StreamWriter stdout_st;
@@ -28,7 +28,7 @@ include(CheckCXXCompilerFlag)
28
28
 
29
29
  find_package(CNoke)
30
30
 
31
- set(CMAKE_CXX_STANDARD 17)
31
+ set(CMAKE_CXX_STANDARD 20)
32
32
  if(MSVC)
33
33
  set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
34
34
 
@@ -1043,12 +1043,6 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
1043
1043
  out_kind = OutArgument::Kind::Buffer;
1044
1044
  } else if (type->ref.type->primitive == PrimitiveKind::Record ||
1045
1045
  type->ref.type->primitive == PrimitiveKind::Union) [[likely]] {
1046
- if (!type->ref.type->size) [[unlikely]] {
1047
- ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
1048
- type->ref.type != instance->void_type ? "opaque" : "ambiguous", type->name);
1049
- return false;
1050
- }
1051
-
1052
1046
  Napi::Object obj = value.As<Napi::Object>();
1053
1047
  RG_ASSERT(IsObject(value));
1054
1048
 
@@ -1108,6 +1102,22 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
1108
1102
  }
1109
1103
  } break;
1110
1104
 
1105
+ case napi_function: {
1106
+ if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
1107
+ ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
1108
+ return false;
1109
+ }
1110
+
1111
+ Napi::Function func = value.As<Napi::Function>();
1112
+
1113
+ void *ptr = ReserveTrampoline(type->ref.proto, func);
1114
+ if (!ptr) [[unlikely]]
1115
+ return false;
1116
+
1117
+ *out_ptr = (void *)ptr;
1118
+ return true;
1119
+ } break;
1120
+
1111
1121
  case napi_number: {
1112
1122
  Napi::Number number = value.As<Napi::Number>();
1113
1123
  intptr_t ptr = (intptr_t)number.Int32Value();
@@ -1775,8 +1775,9 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1775
1775
  if (!type) [[unlikely]]
1776
1776
  return env.Null();
1777
1777
  if (type->primitive != PrimitiveKind::Pointer &&
1778
+ type->primitive != PrimitiveKind::Callback &&
1778
1779
  type->primitive != PrimitiveKind::String &&
1779
- type->primitive != PrimitiveKind::String16) {
1780
+ type->primitive != PrimitiveKind::String16) [[unlikely]] {
1780
1781
  ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
1781
1782
  return env.Null();
1782
1783
  }