ffi_wide_char 1.0.2 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19b32012cde9e95923464d15b12c156176c51c97e02a9d4d8aeed19d6a886839
4
- data.tar.gz: '0772497956c010ad1be1d6cea9eaa586de0256f1c6b7bf303ea5ff13095f2dbc'
3
+ metadata.gz: f13487162d031d2b591d6e7ef446edce77c9b4e635499944448a1f374d735240
4
+ data.tar.gz: 83e493aa9e66d21f8738ed895e2b55b4bcd1cc25ce291440ce9ada8454a340cc
5
5
  SHA512:
6
- metadata.gz: ecd7aa2746e6ba7e3ae41d13c0237971a15aa156f2ad2489c6e2fd2bc9366195c2a4f0cbfdb18e536e828b85ff6bdfbacfa5511ae3032720265cdbadd77600d7
7
- data.tar.gz: bafdddf658523047680c82d129fead2899cfcc1d3b98bb8e4f9c877cd8b8de8f89b74fc87c4c67ab50df78379330088fe688d1694f43337b5fcf20a981913a41
6
+ metadata.gz: a9d0de60039102974f50dcc2a8648d12a03afe67c0653304cac26217b57e8a067dd7289f00eae86f86cfe09c82148e0fd95dd2ef4dce36474fd8ed8d42a1489a
7
+ data.tar.gz: 75b9169991423761bdd3ba66119a41e41867798f19fa5696733a57ce7cc157ca83578d4b9b0836617df9312ce6f4d86e3df03fc8c228da17d7f66c53b53c9c1b
@@ -0,0 +1,64 @@
1
+ # FfiWideChar [![Build Status](https://travis-ci.org/nthachus/ffi_wide_char.svg?branch=master)](https://travis-ci.org/nthachus/ffi_wide_char)
2
+
3
+ A Ruby gem helper for FFI binding libraries to convert from/to C native `wchar_t` wide-string.
4
+
5
+ It provides 2 methods: `read_wide_string` and `to_wide_string` for converting.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'ffi_wide_char'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install ffi_wide_char
22
+
23
+ ## Usage
24
+
25
+ Example of calling native library functions using `wide-string` type:
26
+
27
+ ```ruby
28
+ require 'ffi_wide_char'
29
+
30
+ # Unicode Popup Dialog
31
+ module Win
32
+ extend FFI::Library
33
+
34
+ ffi_lib 'user32'
35
+ ffi_convention :stdcall
36
+
37
+ attach_function :message_box, :MessageBoxW, %i[pointer buffer_in buffer_in int], :int
38
+ end
39
+
40
+ msg = FfiWideChar.to_wide_string('a中Я')
41
+ Win.message_box(nil, msg, msg, 0)
42
+
43
+ # Convert multibyte to wide-string
44
+ ptr = FFI::MemoryPointer.new(:char, 16)
45
+ FfiWideChar::LibC.mbstowcs(ptr, '©Ðõ'.encode('filesystem'), 4)
46
+
47
+ str = FfiWideChar.read_wide_string ptr
48
+ puts str.encode('UTF-8')
49
+ ```
50
+
51
+ ## Development
52
+
53
+ After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake` to run the tests.
54
+ You can also run `irb -r bundler/setup -r ffi_wide_char` for an interactive prompt that will allow you to experiment.
55
+
56
+ To install this gem onto your local machine, run `bundle exec rake install`.
57
+
58
+ ## Contributing
59
+
60
+ Bug reports and pull requests are welcome on GitHub at https://github.com/nthachus/ffi_wide_char.
61
+
62
+ ## License
63
+
64
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,89 +1,70 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ffi'
4
-
5
- require 'ffi_wide_char/api'
6
3
  require 'ffi_wide_char/version'
4
+ require 'ffi_wide_char/api'
7
5
 
8
6
  module FfiWideChar
9
- class InvalidMultibyteCharError < StandardError; end
10
- class UnsupportedWCharEncodingError < StandardError; end
7
+ class Error < StandardError; end
11
8
 
12
- DEFAULT_ENC = 'UTF-16LE'
13
- ENCODINGS = {
14
- "!\x00@\x00\x00\x00" => DEFAULT_ENC,
15
- "\x00!\x00@\x00\x00" => 'UTF-16BE',
16
- "!\x00\x00\x00@\x00" => 'UTF-32LE',
17
- "\x00\x00\x00!\x00\x00" => 'UTF-32BE'
9
+ ENCODINGS = {
10
+ 'UTF-16LE' => "!\x00@\x00\x00\x00",
11
+ 'UTF-16BE' => "\x00!\x00@\x00\x00",
12
+ 'UTF-32LE' => "!\x00\x00\x00@\x00",
13
+ 'UTF-32BE' => "\x00\x00\x00!\x00\x00"
18
14
  }.freeze
19
15
 
20
- W_CHAR_ENC = nil
21
- W_CHAR_SIZE = 2
22
- W_CHAR_FUNC = :get_uint16
23
-
24
16
  # All methods in this block are static
25
17
  class << self
26
18
  # Detect `wchar_t` encoding.
27
- # @return [String] Name of the wide-string encoding.
28
- def detect_encoding
29
- return W_CHAR_ENC if W_CHAR_ENC
30
-
31
- ptr = FFI::MemoryPointer.new(:uint8, 6)
32
- ret = LibC.mbstowcs(ptr, '!@', 3)
33
- raise InvalidMultibyteCharError unless ret.is_a?(Numeric) && ret >= 0
34
-
35
- enc = ENCODINGS[str = ptr.get_bytes(0, 6)]
36
- raise UnsupportedWCharEncodingError, str.inspect unless enc
37
-
38
- redefine_consts enc
19
+ # @return [String] Encoding name of the wide-string .
20
+ def encoding
21
+ @encoding ||=
22
+ begin
23
+ ptr = FFI::MemoryPointer.new(:char, 12)
24
+ rc = LibC.mbstowcs(ptr, '!@', 3)
25
+ raise Error, 'Invalid multibyte character' unless rc.is_a?(Integer) && rc >= 0
26
+
27
+ str = ptr.get_bytes(0, 6)
28
+ enc = ENCODINGS.key(str)
29
+ raise Error, "Unsupported wide-character encoding #{str.inspect}" unless enc
30
+
31
+ enc
32
+ end
39
33
  end
40
34
 
41
- # Look for a null terminating characters; if found, read up to that null (exclusive)
42
- # @param ptr [Pointer] A wide-string pointer.
35
+ alias detect_encoding encoding
36
+
37
+ # Look for a null-terminated characters; if found, read up to that null (exclusive)
38
+ # @param ptr [FFI::Pointer] A wide-string pointer.
43
39
  # @return [String] Decoded wide-string.
44
40
  def read_wide_string(ptr)
45
- return nil unless ptr && (get_object_attr(ptr, :address) || 0) != 0
41
+ return nil if !ptr.respond_to?(:null?) || ptr.null?
42
+
43
+ @size ||= encoding.include?('32') ? 4 : 2
44
+ @func ||= @size == 4 ? :get_int32 : :get_int16
46
45
 
47
46
  len = get_wide_string_len ptr
48
- ptr.get_bytes(0, len).force_encoding(W_CHAR_ENC || DEFAULT_ENC)
47
+ ptr.get_bytes(0, len).force_encoding(encoding)
49
48
  end
50
49
 
51
50
  # Convert a Ruby string into a C native wide-string.
52
51
  # @param str [String] A Ruby string.
53
52
  # @return [String] C native wide-string.
54
53
  def to_wide_string(str)
55
- str ? str.encode(W_CHAR_ENC || DEFAULT_ENC) : str
54
+ str ? str.encode(encoding) : str
56
55
  end
57
56
 
58
57
  private
59
58
 
60
- # @param enc [String]
61
- # @return [String]
62
- def redefine_consts(enc)
63
- [:W_CHAR_ENC, :W_CHAR_SIZE, :W_CHAR_FUNC].each { |name| send :remove_const, name }
64
-
65
- const_set :W_CHAR_ENC, enc
66
- const_set :W_CHAR_SIZE, enc.include?('32') ? 4 : 2
67
- const_set :W_CHAR_FUNC, W_CHAR_SIZE == 4 ? :get_int32 : :get_uint16
68
-
69
- enc
70
- end
71
-
72
- # @param obj [Object]
73
- # @param name [Symbol]
74
- # @return [Object]
75
- def get_object_attr(obj, name)
76
- obj.respond_to?(name) ? obj.send(name) : nil
77
- end
78
-
79
- # @param ptr [Pointer]
59
+ # Detect wide-string length in bytes
60
+ # @param ptr [FFI::Pointer]
80
61
  # @return [Integer]
81
62
  def get_wide_string_len(ptr)
82
- sz = get_object_attr(ptr, :size)
83
- sz -= W_CHAR_SIZE if sz
63
+ sz = ptr.size
64
+ sz -= @size if sz
84
65
 
85
66
  len = 0
86
- len += W_CHAR_SIZE while (!sz || len < sz) && ptr.send(W_CHAR_FUNC, len) != 0
67
+ len += @size while (!sz || len < sz) && ptr.send(@func, len) != 0
87
68
 
88
69
  len
89
70
  end
@@ -1,12 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ffi'
4
+
3
5
  module FfiWideChar
4
6
  module LibC
5
7
  extend FFI::Library
6
8
  ffi_lib FFI::Library::LIBC
7
9
 
8
- # Converts a string of multibyte characters to a wide character array
9
- # size_t mbstowcs (wchar_t *wstring, const char *string, size_t size)
10
+ # @!scope class
11
+ # @!method mbstowcs(dest, src, size)
12
+ # Converts a string of multibyte characters to a wide character array
13
+ # @param dest [FFI::Pointer] of wchar_t*
14
+ # @param src [String]
15
+ # @param size [Integer] Max number of :wchar_t characters to write to dest
16
+ # @return [Integer] Number of :wchar_t written to dest (w/o null-terminated), or -1 if error
10
17
  attach_function :mbstowcs, [:pointer, :string, :size_t], :size_t
11
18
  end
12
19
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FfiWideChar
4
- VERSION = '1.0.2'
4
+ VERSION = '1.1.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi_wide_char
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thach Nguyen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-29 00:00:00.000000000 Z
11
+ date:
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -88,6 +88,7 @@ extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
90
  - LICENSE.txt
91
+ - README.md
91
92
  - lib/ffi_wide_char/api.rb
92
93
  - lib/ffi_wide_char/version.rb
93
94
  - lib/ffi_wide_char.rb
@@ -110,8 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
111
  - !ruby/object:Gem::Version
111
112
  version: '0'
112
113
  requirements: []
113
- rubyforge_project:
114
- rubygems_version: 2.7.6.2
114
+ rubygems_version: 3.0.3
115
115
  signing_key:
116
116
  specification_version: 4
117
117
  summary: Provides methods to convert from/to FFI wide-string.