1require "rss/utils"
2
3module RSS
4
5  class Converter
6
7    include Utils
8
9    def initialize(to_enc, from_enc=nil)
10      if "".respond_to?(:encode)
11        @to_encoding = to_enc
12        return
13      end
14      normalized_to_enc = to_enc.downcase.gsub(/-/, '_')
15      from_enc ||= 'utf-8'
16      normalized_from_enc = from_enc.downcase.gsub(/-/, '_')
17      if normalized_to_enc == normalized_from_enc
18        def_same_enc()
19      else
20        def_diff_enc = "def_to_#{normalized_to_enc}_from_#{normalized_from_enc}"
21        if respond_to?(def_diff_enc)
22          __send__(def_diff_enc)
23        else
24          def_else_enc(to_enc, from_enc)
25        end
26      end
27    end
28
29    def convert(value)
30      if value.is_a?(String) and value.respond_to?(:encode)
31        value.encode(@to_encoding)
32      else
33        value
34      end
35    end
36
37    def def_convert(depth=0)
38      instance_eval(<<-EOC, *get_file_and_line_from_caller(depth))
39      def convert(value)
40        if value.kind_of?(String)
41          #{yield('value')}
42        else
43          value
44        end
45      end
46      EOC
47    end
48
49    def def_iconv_convert(to_enc, from_enc, depth=0)
50      begin
51        require "iconv"
52        @iconv = Iconv.new(to_enc, from_enc)
53        def_convert(depth+1) do |value|
54          <<-EOC
55          begin
56            @iconv.iconv(#{value})
57          rescue Iconv::Failure
58            raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}")
59          end
60          EOC
61        end
62      rescue LoadError, ArgumentError, SystemCallError
63        raise UnknownConversionMethodError.new(to_enc, from_enc)
64      end
65    end
66
67    def def_else_enc(to_enc, from_enc)
68      def_iconv_convert(to_enc, from_enc, 0)
69    end
70
71    def def_same_enc()
72      def_convert do |value|
73        value
74      end
75    end
76
77    def def_uconv_convert_if_can(meth, to_enc, from_enc, nkf_arg)
78      begin
79        require "uconv"
80        def_convert(1) do |value|
81          <<-EOC
82          begin
83            Uconv.#{meth}(#{value})
84          rescue Uconv::Error
85            raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}")
86          end
87          EOC
88        end
89      rescue LoadError
90        require 'nkf'
91        if NKF.const_defined?(:UTF8)
92          def_convert(1) do |value|
93            "NKF.nkf(#{nkf_arg.dump}, #{value})"
94          end
95        else
96          def_iconv_convert(to_enc, from_enc, 1)
97        end
98      end
99    end
100
101    def def_to_euc_jp_from_utf_8
102      def_uconv_convert_if_can('u8toeuc', 'EUC-JP', 'UTF-8', '-We')
103    end
104
105    def def_to_utf_8_from_euc_jp
106      def_uconv_convert_if_can('euctou8', 'UTF-8', 'EUC-JP', '-Ew')
107    end
108
109    def def_to_shift_jis_from_utf_8
110      def_uconv_convert_if_can('u8tosjis', 'Shift_JIS', 'UTF-8', '-Ws')
111    end
112
113    def def_to_utf_8_from_shift_jis
114      def_uconv_convert_if_can('sjistou8', 'UTF-8', 'Shift_JIS', '-Sw')
115    end
116
117    def def_to_euc_jp_from_shift_jis
118      require "nkf"
119      def_convert do |value|
120        "NKF.nkf('-Se', #{value})"
121      end
122    end
123
124    def def_to_shift_jis_from_euc_jp
125      require "nkf"
126      def_convert do |value|
127        "NKF.nkf('-Es', #{value})"
128      end
129    end
130
131    def def_to_euc_jp_from_iso_2022_jp
132      require "nkf"
133      def_convert do |value|
134        "NKF.nkf('-Je', #{value})"
135      end
136    end
137
138    def def_to_iso_2022_jp_from_euc_jp
139      require "nkf"
140      def_convert do |value|
141        "NKF.nkf('-Ej', #{value})"
142      end
143    end
144
145    def def_to_utf_8_from_iso_8859_1
146      def_convert do |value|
147        "#{value}.unpack('C*').pack('U*')"
148      end
149    end
150
151    def def_to_iso_8859_1_from_utf_8
152      def_convert do |value|
153        <<-EOC
154        array_utf8 = #{value}.unpack('U*')
155        array_enc = []
156        array_utf8.each do |num|
157          if num <= 0xFF
158            array_enc << num
159          else
160            array_enc.concat "&\#\#{num};".unpack('C*')
161          end
162        end
163        array_enc.pack('C*')
164        EOC
165      end
166    end
167
168  end
169
170end
171