• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-yast2 / 13440235285

20 Feb 2025 04:40PM UTC coverage: 41.869% (-0.02%) from 41.889%
13440235285

push

github

web-flow
Merge pull request #1316 from yast/agama_kernel_conf

Respect Agama kernel parameters

2 of 4 new or added lines in 1 file covered. (50.0%)

265 existing lines in 40 files now uncovered.

12605 of 30106 relevant lines covered (41.87%)

10.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.49
/library/types/src/modules/Punycode.rb
1
# ***************************************************************************
2
#
3
# Copyright (c) 2002 - 2012 Novell, Inc.
4
# All Rights Reserved.
5
#
6
# This program is free software; you can redistribute it and/or
7
# modify it under the terms of version 2 of the GNU General Public License as
8
# published by the Free Software Foundation.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, contact Novell, Inc.
17
#
18
# To contact Novell about this file by physical or electronic mail,
19
# you may find current contact information at www.novell.com
20
#
21
# ***************************************************************************
22
# File:  modules/Punycode.ycp
23
# Package:  Main yast package
24
# Summary:  DNS Punycode Handling
25
# Authors:  Lukas Ocilka <lukas.ocilka@suse.cz>
26
# Tags:  Unstable
27
#
28
# $Id$
29
#
30
require "yast"
1✔
31
require "simpleidn"
1✔
32

33
module Yast
1✔
34
  class PunycodeClass < Module
1✔
35
    # string, matching this regexp, is not cached
36
    NOT_CACHED_REGEXP = /^[0123456789.]*$/.freeze
1✔
37

38
    def main
1✔
39
      textdomain "base"
12✔
40

41
      @tmp_dir = nil
12✔
42

43
      #
44
      # Encoded string in cache has the same index
45
      # as its Decoded format in the second list.
46
      #
47

48
      # list of encoded strings to be cached (Punycode or Unicode)
49
      @cache_encoded = []
12✔
50
      # list of decoded strings to be cached (Unicode or Punycode)
51
      @cache_decoded = []
12✔
52

53
      @current_cache_index = 0
12✔
54

55
      # cached amount of data should be controled
56
      @current_cache_size = 0
12✔
57
      @maximum_cache_size = 32_768
12✔
58
    end
59

60
    # Returns the maximum cache size (sum of already converted
61
    # strings).
62
    #
63
    # @return [Fixnum] maximum_cache_size
64
    # @see #SetMaximumCacheSize()
65
    def GetMaximumCacheSize
1✔
66
      @maximum_cache_size
×
67
    end
68

69
    # Offers to set the maximum cache size (sum of already
70
    # converted strings).
71
    #
72
    # @param [Fixnum] new_max_size
73
    # @see #GetMaximumCacheSize()
74
    def SetMaximumCacheSize(new_max_size)
1✔
75
      if new_max_size.nil?
×
76
        Builtins.y2error("Cannot set MaximumCacheSize to nil!")
×
77
      else
78
        @maximum_cache_size = new_max_size
×
79
      end
80

UNCOV
81
      nil
×
82
    end
83

84
    # Adds new cache records for encoded and decoded strings.
85
    #
86
    # @param [String] decoded
87
    # @param [String] encoded
88
    def CreateNewCacheRecord(decoded, encoded)
1✔
89
      # Erroneous cache record
90
      return if decoded.nil? || encoded.nil?
4✔
91

92
      # Already cached
93
      return if Builtins.contains(@cache_decoded, decoded)
4✔
94

95
      decoded_size = Builtins.size(decoded)
4✔
96
      encoded_size = Builtins.size(encoded)
4✔
97

98
      # Do not store this record if the cache would exceed maximum
99
      if Ops.greater_than(
4✔
100
        Ops.add(Ops.add(@current_cache_size, decoded_size), encoded_size),
101
        @maximum_cache_size
102
      )
103
        return
×
104
      end
105

106
      @current_cache_size = Ops.add(
4✔
107
        Ops.add(@current_cache_size, decoded_size),
108
        encoded_size
109
      )
110
      Ops.set(@cache_decoded, @current_cache_index, decoded)
4✔
111
      Ops.set(@cache_encoded, @current_cache_index, encoded)
4✔
112
      @current_cache_index = Ops.add(@current_cache_index, 1)
4✔
113

114
      nil
4✔
115
    end
116

117
    # Returns string encoded in Punycode if it has been
118
    # already cached. Returns nil if not found.
119
    #
120
    # @param [String] decoded_string (Unicode)
121
    # @return [String] encoded_string (Punycode)
122
    def GetEncodedCachedString(decoded_string)
1✔
123
      ret = nil
3✔
124

125
      # numbers and empty strings are not converted
126
      return decoded_string if NOT_CACHED_REGEXP.match?(decoded_string)
3✔
127

128
      counter = -1
3✔
129
      # searching through decoded strings to find the index
130
      Builtins.foreach(@cache_decoded) do |cached_string|
3✔
131
        counter = Ops.add(counter, 1)
×
132
        if cached_string == decoded_string
×
133
          # returning encoded representation
134
          ret = Ops.get(@cache_encoded, counter)
×
135
          raise Break
×
136
        end
137
      end
138

139
      ret
3✔
140
    end
141

142
    # Returns string encoded in Punycode if it has been
143
    # already cached. Returns nil if not found.
144
    #
145
    # @param [String] encoded_string (Punycode)
146
    # @return [String] decoded_string (Unicode)
147
    def GetDecodedCachedString(encoded_string)
1✔
148
      ret = nil
3✔
149

150
      # numbers and empty strings are not converted
151
      return encoded_string if NOT_CACHED_REGEXP.match?(encoded_string)
3✔
152

153
      counter = -1
3✔
154
      # searching through encoded strings to find the index
155
      Builtins.foreach(@cache_encoded) do |cached_string|
3✔
156
        counter = Ops.add(counter, 1)
×
157
        if cached_string == encoded_string
×
158
          # returning decoded representation
159
          ret = Ops.get(@cache_decoded, counter)
×
160
          raise Break
×
161
        end
162
      end
163

164
      ret
3✔
165
    end
166

167
    # Returns the current temporary directory.
168
    # Lazy loading for the initialization is used.
169
    def GetTmpDirectory
1✔
170
      @tmp_dir = Convert.to_string(SCR.Read(path(".target.tmpdir"))) if @tmp_dir.nil?
×
171

172
      @tmp_dir
×
173
    end
174

175
    # Function takes the list of strings and returns them in the converted
176
    # format. Unicode to Punycode or Punycode to Unicode (param to_punycode).
177
    # It uses a cache of already-converted strings.
178
    def ConvertBackAndForth(strings_in, to_punycode)
1✔
179
      # Some (or maybe all) strings needn't be cached
180
      not_cached = []
11✔
181

182
      # Check the cache for already entered strings
183
      test_cached = strings_in.each_with_object({}) do |string_in, all|
11✔
184
        # Numbers, IPs and empty strings are not converted
185
        string_out =
186
          if NOT_CACHED_REGEXP.match?(string_in)
17✔
187
            string_in
9✔
188
          elsif to_punycode
8✔
189
            GetEncodedCachedString(string_in)
4✔
190
          else
191
            GetDecodedCachedString(string_in)
4✔
192
          end
193

194
        not_cached << string_in if string_out.nil?
17✔
195
        all[string_in] = string_out
17✔
196
      end
197

198
      converted_not_cached = []
11✔
199

200
      # There is something not cached, converting them at once
201
      if !not_cached.empty?
11✔
202
        meth = to_punycode ? :to_ascii : :to_unicode
6✔
203
        converted_not_cached = not_cached.map { |v| SimpleIDN.public_send(meth, v) }
12✔
204
      end
205

206
      # Listing through the given list and adjusting the return list
207
      found_index = -1
11✔
208
      strings_in.each_with_object([]) do |string_in, all|
11✔
209
        # Already cached string
210
        if test_cached[string_in]
17✔
211
          all << test_cached[string_in]
11✔
212
        else # Recently converted strings
213
          found_index += 1
6✔
214
          (all << converted_not_cached[found_index]) || ""
6✔
215

216
          # Adding converted strings to cache
217
          if to_punycode
6✔
218
            CreateNewCacheRecord(string_in, converted_not_cached[found_index] || "")
3✔
219
          else
220
            CreateNewCacheRecord(converted_not_cached[found_index] || "", string_in)
3✔
221
          end
222
        end
223
      end
224
    end
225

226
    # Converts list of UTF-8 strings into their Punycode
227
    # ASCII repserentation.
228
    #
229
    # @param [Array<String>] punycode_strings
230
    # @return [Array<String>] encoded_strings
231
    def EncodePunycodes(punycode_strings)
1✔
232
      punycode_strings = deep_copy(punycode_strings)
1✔
233
      ConvertBackAndForth(punycode_strings, true)
1✔
234
    end
235

236
    # Converts list of Punycode strings into their UTF-8
237
    # representation.
238
    #
239
    # @param [Array<String>] punycode_strings
240
    # @return [Array<String>] decoded_strings
241
    def DecodePunycodes(punycode_strings)
1✔
242
      punycode_strings = deep_copy(punycode_strings)
1✔
243
      ConvertBackAndForth(punycode_strings, false)
1✔
244
    end
245

246
    # Encodes the domain name (relative or FQDN) to the Punycode.
247
    #
248
    # @param string decoded domain_name
249
    # @return [String] encoded domain_name
250
    #
251
    # @example
252
    #  EncodeDomainName("žížala.jůlinka.go.home")
253
    #    -> "xn--ala-qma83eb.xn--jlinka-3mb.go.home"
254
    def EncodeDomainName(decoded_domain_name)
1✔
255
      Builtins.mergestring(
×
256
        EncodePunycodes(Builtins.splitstring(decoded_domain_name, ".")),
257
        "."
258
      )
259
    end
260

261
    # Decodes the domain name (relative or FQDN) from the Punycode.
262
    #
263
    # @param [String] encoded_domain_name
264
    # @return [String] decoded domain_name
265
    #
266
    # @example
267
    #  DecodeDomainName("xn--ala-qma83eb.xn--jlinka-3mb.go.home")
268
    #    -> "žížala.jůlinka.go.home"
269
    def DecodeDomainName(encoded_domain_name)
1✔
270
      Builtins.mergestring(
×
271
        DecodePunycodes(Builtins.splitstring(encoded_domain_name, ".")),
272
        "."
273
      )
274
    end
275

276
    # Decodes the list of domain names to their Unicode representation.
277
    # This function is similar to DecodePunycodes but it works with every
278
    # string as a domain name (that means every domain name is parsed
279
    # by dots and separately evaluated).
280
    #
281
    # @param [Array<String>] encoded_domain_names
282
    # @return [Array<String>] decoded_domain_names
283
    #
284
    # @example
285
    #   DocodeDomainNames(["mx1.example.org", "xp3.example.org.", "xn--ala-qma83eb.org.example."])
286
    #    -> ["mx1.example.org", "xp3.example.org.", "žížala.org.example."]
287
    def DocodeDomainNames(encoded_domain_names)
1✔
288
      encoded_domain_names = deep_copy(encoded_domain_names)
×
289
      decoded_domain_names = []
×
290
      strings_to_decode = []
×
291

292
      # $[0 : [0, 2], 1 : [3, 5]]
293
      backward_map_of_conversion = {}
×
294

295
      current_domain_index = -1
×
296
      current_domain_item = 0
×
297

298
      # parsing all domain names one by one
299
      Builtins.foreach(encoded_domain_names) do |one_domain_name|
×
300
        current_domain_index = Ops.add(current_domain_index, 1)
×
301
        start = current_domain_item
×
302
        # parsing the domain name by dots
303
        Builtins.foreach(Builtins.splitstring(one_domain_name, ".")) do |domain_item|
×
304
          Ops.set(strings_to_decode, current_domain_item, domain_item)
×
305
          current_domain_item = Ops.add(current_domain_item, 1)
×
306
        end
307
        # creating backward index
308
        Ops.set(
×
309
          backward_map_of_conversion,
310
          current_domain_index,
311
          [start, Ops.subtract(current_domain_item, 1)]
312
        )
313
      end
314

315
      # Transformating strings to the decoded format
316
      strings_to_decode = DecodePunycodes(strings_to_decode)
×
317

318
      current_domain_index = -1
×
319
      Builtins.foreach(encoded_domain_names) do |one_encoded|
×
320
        current_domain_index = Ops.add(current_domain_index, 1)
×
321
        # Where the current string starts and ends
322
        current = Ops.get(backward_map_of_conversion, [current_domain_index, 0])
×
323
        end_ = Ops.get(backward_map_of_conversion, [current_domain_index, 1])
×
324
        # error?
325
        if current.nil? || end_.nil?
×
326
          Builtins.y2error(
×
327
            "Cannot find start/end for %1 in %2",
328
            one_encoded,
329
            Ops.get(backward_map_of_conversion, current_domain_index)
330
          )
331
          Ops.set(decoded_domain_names, current_domain_index, one_encoded)
×
332
        else
333
          # create a list of items of the current domain (translated)
334
          decoded_domain = []
×
335
          while Ops.less_or_equal(current, end_)
×
336
            decoded_domain = Builtins.add(
×
337
              decoded_domain,
338
              Ops.get(strings_to_decode, current, "")
339
            )
340
            current = Ops.add(current, 1)
×
341
          end
342
          # create a domain name from these strings
343
          Ops.set(
×
344
            decoded_domain_names,
345
            current_domain_index,
346
            Builtins.mergestring(decoded_domain, ".")
347
          )
348
        end
349
      end
350

351
      deep_copy(decoded_domain_names)
×
352
    end
353

354
    publish function: :GetMaximumCacheSize, type: "integer ()"
1✔
355
    publish function: :SetMaximumCacheSize, type: "void (integer)"
1✔
356
    publish function: :EncodePunycodes, type: "list <string> (list <string>)"
1✔
357
    publish function: :DecodePunycodes, type: "list <string> (list <string>)"
1✔
358
    publish function: :EncodeDomainName, type: "string (string)"
1✔
359
    publish function: :DecodeDomainName, type: "string (string)"
1✔
360
    publish function: :DocodeDomainNames, type: "list <string> (list <string>)"
1✔
361
  end
362

363
  Punycode = PunycodeClass.new
1✔
364
  Punycode.main
1✔
365
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc