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