1#
2# tk/encodedstr.rb : Tk::EncodedString class
3#
4require 'tk'
5
6###########################################
7#  string with Tcl's encoding
8###########################################
9module Tk
10  class EncodedString < String
11    Encoding = nil
12
13    def self.subst_utf_backslash(str)
14      # str.gsub(/\\u([0-9A-Fa-f]{1,4})/){[$1.hex].pack('U')}
15      TclTkLib._subst_UTF_backslash(str)
16    end
17    def self.utf_backslash(str)
18      self.subst_utf_backslash(str)
19    end
20
21    def self.subst_tk_backslash(str)
22      TclTkLib._subst_Tcl_backslash(str)
23    end
24
25    def self.utf_to_backslash_sequence(str)
26      str.unpack('U*').collect{|c|
27        if c <= 0xFF  # ascii character
28          c.chr
29        else
30          format('\u%X', c)
31        end
32      }.join('')
33    end
34    def self.utf_to_backslash(str)
35      self.utf_to_backslash_sequence(str)
36    end
37
38    def self.to_backslash_sequence(str)
39      str.unpack('U*').collect{|c|
40        if c <= 0x1F  # control character
41          case c
42          when 0x07; '\a'
43          when 0x08; '\b'
44          when 0x09; '\t'
45          when 0x0a; '\n'
46          when 0x0b; '\v'
47          when 0x0c; '\f'
48          when 0x0d; '\r'
49          else
50            format('\x%02X', c)
51          end
52        elsif c <= 0xFF  # ascii character
53          c.chr
54        else
55          format('\u%X', c)
56        end
57      }.join('')
58    end
59
60    def self.new_with_utf_backslash(str, enc = nil)
61      self.new('', enc).replace(self.subst_utf_backslash(str))
62    end
63
64    def self.new_without_utf_backslash(str, enc = nil)
65      self.new('', enc).replace(str)
66    end
67
68    def initialize(str, enc = nil)
69      super(str)
70      # @encoding = ( enc ||
71      #              ((self.class::Encoding)?
72      #                  self.class::Encoding : Tk.encoding_system) )
73      enc ||= (self.class::Encoding)?
74                         self.class::Encoding :
75                         ((Tk.encoding)? Tk.encoding : Tk.encoding_system)
76      if TkCore::WITH_ENCODING
77        unless encobj = Tk::Encoding::ENCODING_TABLE.get_obj(enc)
78          fail ArgumentError, "unsupported Tk encoding '#{enc}'"
79        end
80        self.force_encoding(encobj)
81      else
82        @encoding = enc
83      end
84    end
85
86    if TkCore::WITH_ENCODING
87      alias encoding_obj encoding
88      alias __encoding   encoding
89      def encoding
90        Tk::Encoding::ENCODING_TABLE.get_name(super())
91      end
92    else
93      def encoding
94        @encoding
95      end
96      alias encoding_obj encoding
97    end
98
99    if TkCore::WITH_ENCODING
100      # wrapper methods for compatibility
101      alias __instance_variable_get instance_variable_get
102      alias __instance_variable_set instance_variable_set
103      alias __instance_eval         instance_eval
104      alias __instance_variables    instance_variables
105
106      def instance_variable_get(key)
107        if (key.to_s == '@encoding')
108          self.encoding
109        else
110          super(key)
111        end
112      end
113
114      def instance_variable_set(key, value)
115        if (key.to_s == '@encoding')
116          if value
117            self.force_encoding(value)
118          else
119            self.force_encoding(Tk::Encoding::UNKNOWN)
120          end
121          value
122        else
123          super(key, value)
124        end
125      end
126
127      def instance_eval(*args, &b)
128        old_enc = @encoding = self.encoding
129
130        ret = super(*args, &b)
131
132        if @encoding
133          if @encoding != old_enc
134            # modified by user
135            self.force_encoding(@encoding)
136          end
137          remove_instance_variable(:@encoding)
138        else
139          begin
140            remove_instance_variable(:@encoding)
141            # user sets to nil -> use current default
142            self.force_encoding(Tk.encoding)
143          rescue NameError
144            # removed by user -> ignore, because user don't use @encoding
145          end
146        end
147        ret
148      end
149    end
150
151    def instance_variables
152      ret = super()
153      ret << :@encoding  # fake !!
154      ret
155    end
156  end
157  # def Tk.EncodedString(str, enc = nil)
158  #   Tk::EncodedString.new(str, enc)
159  # end
160
161  ##################################
162
163  class BinaryString < EncodedString
164    Encoding = 'binary'.freeze
165  end
166  # def Tk.BinaryString(str)
167  #   Tk::BinaryString.new(str)
168  # end
169
170  ##################################
171
172  class UTF8_String < EncodedString
173    Encoding = 'utf-8'.freeze
174    def self.new(str)
175      super(self.subst_utf_backslash(str))
176    end
177
178    def to_backslash_sequence
179      Tk::EncodedString.utf_to_backslash_sequence(self)
180    end
181    alias to_backslash to_backslash_sequence
182  end
183  # def Tk.UTF8_String(str)
184  #   Tk::UTF8_String.new(str)
185  # end
186
187end
188