idn2_wrap 0.1.0
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.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/Rakefile +12 -0
- data/idn2_wrap.gemspec +24 -0
- data/lib/idn2_wrap/ffi.rb +102 -0
- data/lib/idn2_wrap/version.rb +5 -0
- data/lib/idn2_wrap.rb +4 -0
- metadata +81 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f6393803ea2a8301848ea439a8149786dc2374f3e8a81241d55eb5e11a2d96eb
|
|
4
|
+
data.tar.gz: a6b1ea77c0239796b8c33901ad3c91c282f92d02af86a8611a4959b8880e9b95
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c20f49a55e11dbaaad8c0915c73596a297ab5632c5fc667d7a35ed36d6ce017aa8a4a15e7ad906cc86a1a87669c5144e800ae838cfa247cfbeb32266de6013b8
|
|
7
|
+
data.tar.gz: 8e25e81052d24c426384b430636bd8cf568096b8ee6b250c6db2a13ca1e6574bbfed2f0015ea460220f92479775f57dd3f6b38134ecf3eab0580c1c7945f8d64
|
data/Gemfile
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require "rspec/core/rake_task"
|
|
7
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
8
|
+
task default: :spec
|
|
9
|
+
#rescue LoadError
|
|
10
|
+
# If rspec isn't installed yet, keep a build fallback:
|
|
11
|
+
# task default: :build
|
|
12
|
+
end
|
data/idn2_wrap.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |spec|
|
|
4
|
+
spec.name = "idn2_wrap"
|
|
5
|
+
spec.version = File.read(File.expand_path("lib/idn2_wrap/version.rb", __dir__)).match(/VERSION\s*=\s*["'](.+)["']/)[1]
|
|
6
|
+
spec.authors = ["Alexey Makhotkin / ChatGPT"]
|
|
7
|
+
spec.email = ["squadette@gmail.com"]
|
|
8
|
+
|
|
9
|
+
spec.summary = "Minimal FFI wrapper for libidn2: to_ascii / to_unicode"
|
|
10
|
+
spec.description = "A tiny Ruby FFI wrapper exposing libidn2's to_ascii and to_unicode functions."
|
|
11
|
+
spec.homepage = "https://github.com/squadette/idn2_wrap"
|
|
12
|
+
spec.license = "MIT"
|
|
13
|
+
|
|
14
|
+
spec.files = Dir["lib/**/*", "README.md", "Rakefile", "Gemfile", "idn2_wrap.gemspec"]
|
|
15
|
+
spec.require_paths = ["lib"]
|
|
16
|
+
|
|
17
|
+
spec.add_dependency "ffi", ">= 1.15", "< 2.0"
|
|
18
|
+
|
|
19
|
+
spec.add_development_dependency "rspec", "~> 3.12"
|
|
20
|
+
|
|
21
|
+
spec.metadata = {
|
|
22
|
+
"source_code_uri" => spec.homepage
|
|
23
|
+
}
|
|
24
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "ffi"
|
|
4
|
+
|
|
5
|
+
module Idn2Wrap
|
|
6
|
+
module LibC
|
|
7
|
+
extend FFI::Library
|
|
8
|
+
ffi_lib FFI::Library::LIBC
|
|
9
|
+
attach_function :free, [:pointer], :void
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module IDN2
|
|
13
|
+
extend FFI::Library
|
|
14
|
+
# On most systems this will resolve correctly as "idn2".
|
|
15
|
+
# If needed, set ENV["IDN2_LIB"] to an explicit path or library name.
|
|
16
|
+
ffi_lib(ENV["IDN2_LIB"] || "idn2")
|
|
17
|
+
|
|
18
|
+
# int idn2_to_ascii_8z(const char *input, char **output, int flags);
|
|
19
|
+
attach_function :idn2_to_ascii_8z, [:string, :pointer, :int], :int
|
|
20
|
+
|
|
21
|
+
# int idn2_to_unicode_8z8z(const char *input, char **output, int flags);
|
|
22
|
+
attach_function :idn2_to_unicode_8z8z, [:string, :pointer, :int], :int
|
|
23
|
+
|
|
24
|
+
# const char *idn2_strerror(int rc);
|
|
25
|
+
attach_function :idn2_strerror, [:int], :string
|
|
26
|
+
|
|
27
|
+
# const char *idn2_check_version(const char *req_version);
|
|
28
|
+
attach_function :idn2_check_version, [:string], :string
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Raised on non-zero libidn2 return codes.
|
|
32
|
+
class Error < StandardError
|
|
33
|
+
attr_reader :code
|
|
34
|
+
def initialize(code, message)
|
|
35
|
+
@code = code
|
|
36
|
+
super("[libidn2 #{code}] #{message}")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Common flags people often want (values are stable in libidn2,
|
|
41
|
+
# but we keep them optional to avoid drift; pass integers if you prefer).
|
|
42
|
+
# If you know specific flags you want, pass them via `flags:`.
|
|
43
|
+
module Flags
|
|
44
|
+
# These values match libidn2 headers as of typical distributions.
|
|
45
|
+
# They are provided for convenience; you can omit and keep flags=0.
|
|
46
|
+
NFC_INPUT = 0x0001 # IDN2_NFC_INPUT
|
|
47
|
+
ALLOW_UNASSIGNED = 0x0002 # IDN2_ALLOW_UNASSIGNED
|
|
48
|
+
USE_STD3_ASCII = 0x0004 # IDN2_USE_STD3_ASCII_RULES
|
|
49
|
+
TRANSITIONAL = 0x0008 # IDN2_TRANSITIONAL
|
|
50
|
+
NONTRANSITIONAL = 0x0010 # IDN2_NONTRANSITIONAL
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
module_function
|
|
54
|
+
|
|
55
|
+
# Convert a Unicode domain (e.g., "münich.example") to ASCII/Punycode ("xn--mnich-kva.example").
|
|
56
|
+
#
|
|
57
|
+
# @param input [String] Unicode domain or label
|
|
58
|
+
# @param flags [Integer] Optional libidn2 flags (default 0)
|
|
59
|
+
# @return [String] ASCII/Punycode domain
|
|
60
|
+
# @raise [Idn2Wrap::Error] on libidn2 failure
|
|
61
|
+
def to_ascii(input, flags: 0)
|
|
62
|
+
out_pp = FFI::MemoryPointer.new(:pointer)
|
|
63
|
+
rc = IDN2.idn2_to_ascii_8z(input, out_pp, flags)
|
|
64
|
+
raise Error.new(rc, IDN2.idn2_strerror(rc)) unless rc == 0
|
|
65
|
+
|
|
66
|
+
out_p = out_pp.read_pointer
|
|
67
|
+
begin
|
|
68
|
+
out_p.read_string
|
|
69
|
+
ensure
|
|
70
|
+
LibC.free(out_p)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Convert an ASCII/Punycode domain (e.g., "xn--mnich-kva.example") to Unicode ("münich.example").
|
|
75
|
+
#
|
|
76
|
+
# @param input [String] ASCII/Punycode domain or label
|
|
77
|
+
# @param flags [Integer] Optional libidn2 flags (default 0)
|
|
78
|
+
# @return [String] Unicode domain
|
|
79
|
+
# @raise [Idn2Wrap::Error] on libidn2 failure
|
|
80
|
+
def to_unicode(input, flags: 0)
|
|
81
|
+
out_pp = FFI::MemoryPointer.new(:pointer)
|
|
82
|
+
rc = IDN2.idn2_to_unicode_8z8z(input, out_pp, flags)
|
|
83
|
+
raise Error.new(rc, IDN2.idn2_strerror(rc)) unless rc == 0
|
|
84
|
+
|
|
85
|
+
out_p = out_pp.read_pointer
|
|
86
|
+
begin
|
|
87
|
+
out_p.read_string.force_encoding("UTF-8").encode("UTF-8", invalid: :replace, undef: :replace)
|
|
88
|
+
ensure
|
|
89
|
+
LibC.free(out_p)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Return the libidn2 version string, or nil if the runtime version is
|
|
94
|
+
# older than the given minimum.
|
|
95
|
+
#
|
|
96
|
+
# @param req_version [String, nil] Minimum version required (e.g., "2.3.0"), or nil
|
|
97
|
+
# @return [String, nil] Actual version string, or nil if requirement not met
|
|
98
|
+
def check_version(req_version = nil)
|
|
99
|
+
v = IDN2.idn2_check_version(req_version)
|
|
100
|
+
v.nil? ? nil : v.dup.force_encoding("UTF-8")
|
|
101
|
+
end
|
|
102
|
+
end
|
data/lib/idn2_wrap.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: idn2_wrap
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Alexey Makhotkin / ChatGPT
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ffi
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.15'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '2.0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '1.15'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '2.0'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: rspec
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - "~>"
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '3.12'
|
|
39
|
+
type: :development
|
|
40
|
+
prerelease: false
|
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - "~>"
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '3.12'
|
|
46
|
+
description: A tiny Ruby FFI wrapper exposing libidn2's to_ascii and to_unicode functions.
|
|
47
|
+
email:
|
|
48
|
+
- squadette@gmail.com
|
|
49
|
+
executables: []
|
|
50
|
+
extensions: []
|
|
51
|
+
extra_rdoc_files: []
|
|
52
|
+
files:
|
|
53
|
+
- Gemfile
|
|
54
|
+
- Rakefile
|
|
55
|
+
- idn2_wrap.gemspec
|
|
56
|
+
- lib/idn2_wrap.rb
|
|
57
|
+
- lib/idn2_wrap/ffi.rb
|
|
58
|
+
- lib/idn2_wrap/version.rb
|
|
59
|
+
homepage: https://github.com/squadette/idn2_wrap
|
|
60
|
+
licenses:
|
|
61
|
+
- MIT
|
|
62
|
+
metadata:
|
|
63
|
+
source_code_uri: https://github.com/squadette/idn2_wrap
|
|
64
|
+
rdoc_options: []
|
|
65
|
+
require_paths:
|
|
66
|
+
- lib
|
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
|
+
requirements:
|
|
69
|
+
- - ">="
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '0'
|
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
requirements: []
|
|
78
|
+
rubygems_version: 3.6.9
|
|
79
|
+
specification_version: 4
|
|
80
|
+
summary: 'Minimal FFI wrapper for libidn2: to_ascii / to_unicode'
|
|
81
|
+
test_files: []
|