idn-ruby 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.
- data/CHANGES +17 -0
- data/LICENSE +247 -0
- data/NOTICE +5 -0
- data/README +193 -0
- data/Rakefile +60 -0
- data/ext/extconf.rb +56 -0
- data/ext/idn.c +59 -0
- data/ext/idn.h +59 -0
- data/ext/idna.c +164 -0
- data/ext/punycode.c +160 -0
- data/ext/stringprep.c +183 -0
- data/test/tc_Idna.rb +273 -0
- data/test/tc_Punycode.rb +188 -0
- data/test/tc_Stringprep.rb +81 -0
- data/test/ts_IDN.rb +31 -0
- metadata +83 -0
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rake/extensiontask'
|
7
|
+
|
8
|
+
CLEAN << FileList[ 'ext/Makefile', 'ext/*.so', 'ext/*.o' ]
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'jeweler'
|
12
|
+
rescue LoadError
|
13
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
14
|
+
end
|
15
|
+
|
16
|
+
Jeweler::Tasks.new do |gem|
|
17
|
+
gem.name = 'idn-ruby'
|
18
|
+
gem.summary = 'LibIDN Ruby Bindings.'
|
19
|
+
gem.description = %q{
|
20
|
+
Ruby Bindings for the GNU LibIDN library, an implementation of the
|
21
|
+
Stringprep, Punycode and IDNA specifications defined by the IETF
|
22
|
+
Internationalized Domain Names (IDN) working group.
|
23
|
+
|
24
|
+
Included are the most important parts of the Stringprep, Punycode
|
25
|
+
and IDNA APIs like performing Stringprep processings, encoding to
|
26
|
+
and decoding from Punycode strings and converting entire domain names
|
27
|
+
to and from the ACE encoded form.
|
28
|
+
}
|
29
|
+
gem.email = 'deepfryed@gmail.com'
|
30
|
+
gem.homepage = 'http://github.com/deepfryed/idn-ruby'
|
31
|
+
gem.authors = ['Erik Abele', 'Bharanee Rathna']
|
32
|
+
gem.files = FileList['CHANGES', 'LICENSE', 'NOTICE', 'Rakefile', 'README', 'ext/*.{c,h}']
|
33
|
+
gem.extensions = FileList[ 'ext/**/extconf.rb' ]
|
34
|
+
gem.test_files = FileList[ 'test/*.rb' ]
|
35
|
+
end
|
36
|
+
|
37
|
+
Jeweler::GemcutterTasks.new
|
38
|
+
|
39
|
+
Rake::ExtensionTask.new do |ext|
|
40
|
+
ext.name = 'idn'
|
41
|
+
ext.ext_dir = 'ext'
|
42
|
+
ext.lib_dir = 'ext'
|
43
|
+
end
|
44
|
+
|
45
|
+
Rake::RDocTask.new do |rdoc|
|
46
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "idn-ruby #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
52
|
+
|
53
|
+
Rake::TestTask.new(:test) do |test|
|
54
|
+
test.libs << 'ext'
|
55
|
+
test.pattern = 'test/*.rb'
|
56
|
+
test.verbose = true
|
57
|
+
end
|
58
|
+
|
59
|
+
task :test => [ :compile, :check_dependencies ]
|
60
|
+
task :default => :test
|
data/ext/extconf.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# Makefile configuration for LibIDN Ruby Bindings.
|
2
|
+
#
|
3
|
+
# Copyright (c) 2005 Erik Abele. All rights reserved.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# Please see the file called LICENSE for further details.
|
8
|
+
#
|
9
|
+
# You may also obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# * http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
# This software is OSI Certified Open Source Software.
|
20
|
+
# OSI Certified is a certification mark of the Open Source Initiative.
|
21
|
+
|
22
|
+
require 'mkmf'
|
23
|
+
|
24
|
+
@libs = ['idn']
|
25
|
+
@headers = ['idna.h', 'punycode.h', 'stringprep.h']
|
26
|
+
|
27
|
+
INFO_NOTE = <<EOL
|
28
|
+
Please install the GNU IDN library or alternatively specify at least one
|
29
|
+
of the following options if the library can only be found in a non-standard
|
30
|
+
location:
|
31
|
+
--with-idn-dir=/path/to/non/standard/location
|
32
|
+
or
|
33
|
+
--with-idn-lib=/path/to/non/standard/location/lib
|
34
|
+
--with-idn-include=/path/to/non/standard/location/include
|
35
|
+
EOL
|
36
|
+
|
37
|
+
dir_config('idn')
|
38
|
+
|
39
|
+
@libs.each do |lib|
|
40
|
+
unless have_library(lib)
|
41
|
+
STDERR.puts "ERROR: could not find #{lib} library!\n" +
|
42
|
+
"\n#{INFO_NOTE}\n"
|
43
|
+
exit 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
@headers.each do |header|
|
48
|
+
unless have_header(header)
|
49
|
+
STDERR.puts "ERROR: could not find #{header} header file!\n" +
|
50
|
+
"\n#{INFO_NOTE}\n"
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
$CFLAGS += ' -Wall' unless $CFLAGS.split.include? '-Wall'
|
56
|
+
create_makefile('idn')
|
data/ext/idn.c
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2005 Erik Abele. All rights reserved.
|
3
|
+
* Portions Copyright (c) 2005 Yuki Mitsui. All rights reserved.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* Please see the file called LICENSE for further details.
|
8
|
+
*
|
9
|
+
* You may also obtain a copy of the License at
|
10
|
+
*
|
11
|
+
* * http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
*
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
* See the License for the specific language governing permissions and
|
17
|
+
* limitations under the License.
|
18
|
+
*
|
19
|
+
* This software is OSI Certified Open Source Software.
|
20
|
+
* OSI Certified is a certification mark of the Open Source Initiative.
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <ruby.h>
|
24
|
+
#include "idn.h"
|
25
|
+
|
26
|
+
/*
|
27
|
+
* Document-class: IDN
|
28
|
+
* The main module of LibIDN Ruby Bindings.
|
29
|
+
*
|
30
|
+
* === Example usage
|
31
|
+
*
|
32
|
+
* require 'idn'
|
33
|
+
* include IDN
|
34
|
+
*
|
35
|
+
* ...
|
36
|
+
*/
|
37
|
+
|
38
|
+
VALUE mIDN;
|
39
|
+
|
40
|
+
/*
|
41
|
+
* Document-class: IDN::IDNError
|
42
|
+
* The superclass for all exceptions raised by the IDN extension.
|
43
|
+
*/
|
44
|
+
|
45
|
+
VALUE eIDNError;
|
46
|
+
|
47
|
+
/*
|
48
|
+
* Module Initialization.
|
49
|
+
*/
|
50
|
+
|
51
|
+
void Init_idn(void)
|
52
|
+
{
|
53
|
+
mIDN = rb_define_module("IDN");
|
54
|
+
eIDNError = rb_define_class_under(mIDN, "IDNError", rb_eStandardError);
|
55
|
+
|
56
|
+
init_idna();
|
57
|
+
init_punycode();
|
58
|
+
init_stringprep();
|
59
|
+
}
|
data/ext/idn.h
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2005 Erik Abele. All rights reserved.
|
3
|
+
* Portions Copyright (c) 2005 Yuki Mitsui. All rights reserved.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* Please see the file called LICENSE for further details.
|
8
|
+
*
|
9
|
+
* You may also obtain a copy of the License at
|
10
|
+
*
|
11
|
+
* * http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
*
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
* See the License for the specific language governing permissions and
|
17
|
+
* limitations under the License.
|
18
|
+
*
|
19
|
+
* This software is OSI Certified Open Source Software.
|
20
|
+
* OSI Certified is a certification mark of the Open Source Initiative.
|
21
|
+
*/
|
22
|
+
|
23
|
+
#ifndef ___IDN_IDN_H_
|
24
|
+
#define ___IDN_IDN_H_
|
25
|
+
|
26
|
+
#include <ruby.h>
|
27
|
+
#include <ruby/encoding.h>
|
28
|
+
|
29
|
+
/*
|
30
|
+
* idn.c
|
31
|
+
*/
|
32
|
+
extern VALUE mIDN;
|
33
|
+
extern VALUE eIDNError;
|
34
|
+
|
35
|
+
/*
|
36
|
+
* idna.c
|
37
|
+
*/
|
38
|
+
extern VALUE mIdna;
|
39
|
+
extern VALUE eIdnaError;
|
40
|
+
|
41
|
+
void init_idna(void);
|
42
|
+
|
43
|
+
/*
|
44
|
+
* punycode.c
|
45
|
+
*/
|
46
|
+
extern VALUE mPunycode;
|
47
|
+
extern VALUE ePunycodeError;
|
48
|
+
|
49
|
+
void init_punycode(void);
|
50
|
+
|
51
|
+
/*
|
52
|
+
* stringprep.c
|
53
|
+
*/
|
54
|
+
extern VALUE mStringprep;
|
55
|
+
extern VALUE eStringprepError;
|
56
|
+
|
57
|
+
void init_stringprep(void);
|
58
|
+
|
59
|
+
#endif /* ___IDN_IDN_H_ */
|
data/ext/idna.c
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2005 Erik Abele. All rights reserved.
|
3
|
+
*
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
* you may not use this file except in compliance with the License.
|
6
|
+
* Please see the file called LICENSE for further details.
|
7
|
+
*
|
8
|
+
* You may also obtain a copy of the License at
|
9
|
+
*
|
10
|
+
* * http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
*
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
* See the License for the specific language governing permissions and
|
16
|
+
* limitations under the License.
|
17
|
+
*
|
18
|
+
* This software is OSI Certified Open Source Software.
|
19
|
+
* OSI Certified is a certification mark of the Open Source Initiative.
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include <stdlib.h>
|
23
|
+
#include <ruby.h>
|
24
|
+
#include <idna.h>
|
25
|
+
#include "idn.h"
|
26
|
+
|
27
|
+
/*
|
28
|
+
* Document-class: IDN::Idna
|
29
|
+
* The Idna module of LibIDN Ruby Bindings.
|
30
|
+
*
|
31
|
+
* === Example usage
|
32
|
+
*
|
33
|
+
* require 'idn'
|
34
|
+
* include IDN
|
35
|
+
*
|
36
|
+
* puts 'ACE-Prefix: ' + Idna::ACE_PREFIX
|
37
|
+
*
|
38
|
+
* domain = Idna.toUnicode('xn--rksmrgs-5wao1o.josefsson.org',
|
39
|
+
* Idna::USE_STD3_ASCII_RULES | Idna::ALLOW_UNASSIGNED)
|
40
|
+
*
|
41
|
+
* === Constants
|
42
|
+
*
|
43
|
+
* <b>ACE_PREFIX</b>
|
44
|
+
* - The ACE prefix: 'xn--'.
|
45
|
+
*
|
46
|
+
* <b>ALLOW_UNASSIGNED</b>
|
47
|
+
* - Used as flag for toASCII/toUnicode.
|
48
|
+
*
|
49
|
+
* <b>USE_STD3_ASCII_RULES</b>
|
50
|
+
* - Used as flag for toASCII/toUnicode.
|
51
|
+
*/
|
52
|
+
|
53
|
+
VALUE mIdna;
|
54
|
+
|
55
|
+
/*
|
56
|
+
* Document-class: IDN::Idna::IdnaError
|
57
|
+
* The base class for all exceptions raised by the IDN::Idna module.
|
58
|
+
*/
|
59
|
+
|
60
|
+
VALUE eIdnaError;
|
61
|
+
|
62
|
+
/*
|
63
|
+
* call-seq:
|
64
|
+
* IDN::Idna.toASCII(string, flags=nil) => string
|
65
|
+
*
|
66
|
+
* Converts a domain name in UTF-8 format into an ASCII string. The domain
|
67
|
+
* name may contain several labels, separated by dots.
|
68
|
+
*
|
69
|
+
* Raises IDN::Idna::IdnaError on failure.
|
70
|
+
*/
|
71
|
+
|
72
|
+
static VALUE toASCII(int argc, VALUE argv[], VALUE self)
|
73
|
+
{
|
74
|
+
int rc;
|
75
|
+
char *buf;
|
76
|
+
VALUE str, flags, retv;
|
77
|
+
|
78
|
+
rb_scan_args(argc, argv, "11", &str, &flags);
|
79
|
+
str = rb_check_convert_type(str, T_STRING, "String", "to_s");
|
80
|
+
|
81
|
+
if (flags != Qnil) {
|
82
|
+
Check_Type(flags, T_FIXNUM);
|
83
|
+
flags = FIX2INT(flags);
|
84
|
+
} else {
|
85
|
+
flags = 0x0000;
|
86
|
+
}
|
87
|
+
|
88
|
+
rc = idna_to_ascii_8z(RSTRING_PTR(str), &buf, flags);
|
89
|
+
|
90
|
+
if (rc != IDNA_SUCCESS) {
|
91
|
+
xfree(buf);
|
92
|
+
rb_raise(eIdnaError, "%s (%d)", idna_strerror(rc), rc);
|
93
|
+
return Qnil;
|
94
|
+
}
|
95
|
+
|
96
|
+
retv = rb_str_new2(buf);
|
97
|
+
xfree(buf);
|
98
|
+
return retv;
|
99
|
+
}
|
100
|
+
|
101
|
+
/*
|
102
|
+
* call-seq:
|
103
|
+
* IDN::Idna.toUnicode(string, flags=nil) => string
|
104
|
+
*
|
105
|
+
* Converts a possibly ACE encoded domain name in UTF-8 format into an
|
106
|
+
* UTF-8 string. The domain name may contain several labels, separated
|
107
|
+
* by dots.
|
108
|
+
*
|
109
|
+
* Raises IDN::Idna::IdnaError on failure.
|
110
|
+
*/
|
111
|
+
|
112
|
+
static VALUE toUnicode(int argc, VALUE argv[], VALUE self)
|
113
|
+
{
|
114
|
+
int rc;
|
115
|
+
char *buf;
|
116
|
+
VALUE str, flags, retv;
|
117
|
+
|
118
|
+
rb_scan_args(argc, argv, "11", &str, &flags);
|
119
|
+
str = rb_check_convert_type(str, T_STRING, "String", "to_s");
|
120
|
+
|
121
|
+
if (flags != Qnil) {
|
122
|
+
Check_Type(flags, T_FIXNUM);
|
123
|
+
flags = FIX2INT(flags);
|
124
|
+
} else {
|
125
|
+
flags = 0x0000;
|
126
|
+
}
|
127
|
+
|
128
|
+
rc = idna_to_unicode_8z8z(RSTRING_PTR(str), &buf, flags);
|
129
|
+
|
130
|
+
if (rc != IDNA_SUCCESS) {
|
131
|
+
xfree(buf);
|
132
|
+
rb_raise(eIdnaError, "%s (%d)", idna_strerror(rc), rc);
|
133
|
+
return Qnil;
|
134
|
+
}
|
135
|
+
|
136
|
+
retv = rb_enc_str_new(buf, strlen(buf), rb_utf8_encoding());
|
137
|
+
xfree(buf);
|
138
|
+
return retv;
|
139
|
+
}
|
140
|
+
|
141
|
+
/*
|
142
|
+
* Module Initialization.
|
143
|
+
*/
|
144
|
+
|
145
|
+
void init_idna(void)
|
146
|
+
{
|
147
|
+
#ifdef mIDN_RDOC_HACK
|
148
|
+
mIDN = rb_define_module("IDN");
|
149
|
+
eIDNError = rb_define_class_under(mIDN, "IDNError", rb_eStandardError);
|
150
|
+
#endif
|
151
|
+
|
152
|
+
mIdna = rb_define_module_under(mIDN, "Idna");
|
153
|
+
eIdnaError = rb_define_class_under(mIdna, "IdnaError", eIDNError);
|
154
|
+
|
155
|
+
rb_define_const(mIdna, "ACE_PREFIX",
|
156
|
+
rb_str_new2(IDNA_ACE_PREFIX));
|
157
|
+
rb_define_const(mIdna, "ALLOW_UNASSIGNED",
|
158
|
+
INT2FIX(IDNA_ALLOW_UNASSIGNED));
|
159
|
+
rb_define_const(mIdna, "USE_STD3_ASCII_RULES",
|
160
|
+
INT2FIX(IDNA_USE_STD3_ASCII_RULES));
|
161
|
+
|
162
|
+
rb_define_singleton_method(mIdna, "toASCII", toASCII, -1);
|
163
|
+
rb_define_singleton_method(mIdna, "toUnicode", toUnicode, -1);
|
164
|
+
}
|
data/ext/punycode.c
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2005 Erik Abele. All rights reserved.
|
3
|
+
* Portions Copyright (c) 2005 Yuki Mitsui. All rights reserved.
|
4
|
+
*
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
* you may not use this file except in compliance with the License.
|
7
|
+
* Please see the file called LICENSE for further details.
|
8
|
+
*
|
9
|
+
* You may also obtain a copy of the License at
|
10
|
+
*
|
11
|
+
* * http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
*
|
13
|
+
* Unless required by applicable law or agreed to in writing, software
|
14
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
* See the License for the specific language governing permissions and
|
17
|
+
* limitations under the License.
|
18
|
+
*
|
19
|
+
* This software is OSI Certified Open Source Software.
|
20
|
+
* OSI Certified is a certification mark of the Open Source Initiative.
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <stdlib.h>
|
24
|
+
#include <ruby.h>
|
25
|
+
#include <stringprep.h>
|
26
|
+
#include <punycode.h>
|
27
|
+
#include "idn.h"
|
28
|
+
|
29
|
+
/*
|
30
|
+
* Document-class: IDN::Punycode
|
31
|
+
* The Punycode module of LibIDN Ruby Bindings.
|
32
|
+
*
|
33
|
+
* === Example usage
|
34
|
+
*
|
35
|
+
* require 'idn'
|
36
|
+
* include IDN
|
37
|
+
*
|
38
|
+
* str = Punycode.decode('egbpdaj6bu4bxfgehfvwxn')
|
39
|
+
*/
|
40
|
+
|
41
|
+
VALUE mPunycode;
|
42
|
+
|
43
|
+
/*
|
44
|
+
* Document-class: IDN::Punycode::PunycodeError
|
45
|
+
* The base class for all exceptions raised by the IDN::Punycode module.
|
46
|
+
*/
|
47
|
+
|
48
|
+
VALUE ePunycodeError;
|
49
|
+
|
50
|
+
/*
|
51
|
+
* call-seq:
|
52
|
+
* IDN::Punycode.encode(string) => string
|
53
|
+
*
|
54
|
+
* Converts a string in UTF-8 format to Punycode.
|
55
|
+
*
|
56
|
+
* Raises IDN::Punycode::PunycodeError on failure.
|
57
|
+
*/
|
58
|
+
|
59
|
+
static VALUE encode(VALUE self, VALUE str)
|
60
|
+
{
|
61
|
+
int rc;
|
62
|
+
punycode_uint *ustr;
|
63
|
+
size_t len;
|
64
|
+
size_t buflen = 0x100;
|
65
|
+
char *buf = NULL;
|
66
|
+
VALUE retv;
|
67
|
+
|
68
|
+
str = rb_check_convert_type(str, T_STRING, "String", "to_s");
|
69
|
+
ustr = stringprep_utf8_to_ucs4(RSTRING_PTR(str), RSTRING_LEN(str), &len);
|
70
|
+
|
71
|
+
while (1) {
|
72
|
+
buf = realloc(buf, buflen);
|
73
|
+
|
74
|
+
if (buf == NULL) {
|
75
|
+
xfree(ustr);
|
76
|
+
rb_raise(rb_eNoMemError, "cannot allocate memory (%d bytes)", (uint32_t)buflen);
|
77
|
+
return Qnil;
|
78
|
+
}
|
79
|
+
|
80
|
+
rc = punycode_encode(len, ustr, NULL, &buflen, buf);
|
81
|
+
|
82
|
+
if (rc == PUNYCODE_SUCCESS) {
|
83
|
+
break;
|
84
|
+
} else if (rc == PUNYCODE_BIG_OUTPUT) {
|
85
|
+
buflen += 0x100;
|
86
|
+
} else {
|
87
|
+
xfree(ustr);
|
88
|
+
xfree(buf);
|
89
|
+
rb_raise(ePunycodeError, "%s (%d)", punycode_strerror(rc), rc);
|
90
|
+
return Qnil;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
retv = rb_str_new(buf, buflen);
|
95
|
+
xfree(ustr);
|
96
|
+
xfree(buf);
|
97
|
+
return retv;
|
98
|
+
}
|
99
|
+
|
100
|
+
/*
|
101
|
+
* call-seq:
|
102
|
+
* IDN::Punycode.decode(string) => string
|
103
|
+
*
|
104
|
+
* Converts Punycode to a string in UTF-8 format.
|
105
|
+
*
|
106
|
+
* Raises IDN::Punycode::PunycodeError on failure.
|
107
|
+
*/
|
108
|
+
|
109
|
+
static VALUE decode(VALUE self, VALUE str)
|
110
|
+
{
|
111
|
+
int rc;
|
112
|
+
punycode_uint *ustr;
|
113
|
+
size_t len;
|
114
|
+
char *buf = NULL;
|
115
|
+
VALUE retv;
|
116
|
+
|
117
|
+
str = rb_check_convert_type(str, T_STRING, "String", "to_s");
|
118
|
+
|
119
|
+
len = RSTRING_LEN(str);
|
120
|
+
ustr = malloc(len * sizeof(punycode_uint));
|
121
|
+
|
122
|
+
if (ustr == NULL) {
|
123
|
+
rb_raise(rb_eNoMemError, "cannot allocate memory (%d bytes)", (uint32_t)len);
|
124
|
+
return Qnil;
|
125
|
+
}
|
126
|
+
|
127
|
+
rc = punycode_decode(RSTRING_LEN(str), RSTRING_PTR(str),
|
128
|
+
&len, ustr, NULL);
|
129
|
+
|
130
|
+
if (rc != PUNYCODE_SUCCESS) {
|
131
|
+
xfree(ustr);
|
132
|
+
rb_raise(ePunycodeError, "%s (%d)", punycode_strerror(rc), rc);
|
133
|
+
return Qnil;
|
134
|
+
}
|
135
|
+
|
136
|
+
buf = stringprep_ucs4_to_utf8(ustr, len, NULL, &len);
|
137
|
+
retv = rb_enc_str_new(buf, len, rb_utf8_encoding());
|
138
|
+
xfree(ustr);
|
139
|
+
xfree(buf);
|
140
|
+
return retv;
|
141
|
+
}
|
142
|
+
|
143
|
+
/*
|
144
|
+
* Module Initialization.
|
145
|
+
*/
|
146
|
+
|
147
|
+
void init_punycode(void)
|
148
|
+
{
|
149
|
+
#ifdef mIDN_RDOC_HACK
|
150
|
+
mIDN = rb_define_module("IDN");
|
151
|
+
eIDNError = rb_define_class_under(mIDN, "IDNError", rb_eStandardError);
|
152
|
+
#endif
|
153
|
+
|
154
|
+
mPunycode = rb_define_module_under(mIDN, "Punycode");
|
155
|
+
ePunycodeError = rb_define_class_under(mPunycode, "PunycodeError",
|
156
|
+
eIDNError);
|
157
|
+
|
158
|
+
rb_define_singleton_method(mPunycode, "encode", encode, 1);
|
159
|
+
rb_define_singleton_method(mPunycode, "decode", decode, 1);
|
160
|
+
}
|