idn-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|