rex-text 0.2.42 → 0.2.45

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5316dd362fddbaf996e0a087a07d597caf1161d863dd0db11b21cdeabe6f46ed
4
- data.tar.gz: 57a82d23c177b15a6f8f74a2ed6e248a9af0a0c781d173d5bf2f0116f6cd4422
3
+ metadata.gz: 35b8656aec1d2bd88d707649036693d4421362967f7602e1d18de3aae6e3ea57
4
+ data.tar.gz: 974fe908dd1312fe9a0ccdaa3844b9a537e83e6f001afe5ae28dc153350e5261
5
5
  SHA512:
6
- metadata.gz: 1e88f3f3a165d96e27437bc9ccf237bd2d00c7324f4de1a7ba968ef6dda2faa74923fcdf53d4d8f656d6676d083c7cd40228c5cfcbbe3de81de4821984bfdfbb
7
- data.tar.gz: c2d1b0e804f3fcb61cbda3cb2340dacc3a9f80d4ba02d531adf9c0f5748d481d9288caf1f6cb63cd6427b3dcb0f6bcb7663444eea6f5644d373c79caaa5c7b95
6
+ metadata.gz: 7c3599bb12273e92655678f398595257fc357e0875e8c52ef109e16cb8861c226da817a901a3d884437e0ce2c051796005e297f5c2e33127e48c288e8d72f253
7
+ data.tar.gz: 1cab334469f0ed24807b4d651c87b2c677ab9a9b46616822f3715326e8917bfd0716f157e92b6ae4169c9b98b5dfc89b57bab928834c7c34ebbe7f3495284073
checksums.yaml.gz.sig CHANGED
@@ -1 +1,2 @@
1
- o�,�̵;�`�:ݗ�WyK8{���G���^� j v2yk���k��@-���$����"6������\��s���a��V
1
+ T�3�vM��r�)��T�C������S���?�f��B-�/�5���13�� ,���oܚ���<[���9BaM��ϐ n5EB@�H�o6EH�m���1[V�_*+������Z��q�"�M��Y
2
+ '=�j��"����#�C��C�6�Ԙ��3B~ߔ�4�I�T�K�{�,� �q�`��{یO���%N�8_��ԎJ��֯G>�����ာ�kU J�����ϱW�S�vP��|�R��[�_�%N
@@ -10,6 +10,7 @@ module Text
10
10
  #
11
11
  ###
12
12
  module Color
13
+ SUPPORTED_FORMAT_CODES = %w[%cya %red %grn %blu %yel %whi %mag %blk %dred %dgrn %dblu %dyel %dcya %dwhi %dmag %und %bld %clr %bgblu %bgyel %bggrn %bgmag %bgblk %bgred %bgcyn %bgwhi]
13
14
 
14
15
  AnsiAttributes =
15
16
  {
data/lib/rex/text/hex.rb CHANGED
@@ -127,51 +127,22 @@ module Rex
127
127
  # Converts a string to a hex version with wrapping support
128
128
  #
129
129
  def self.hexify(str, col = DefaultWrap, line_start = '', line_end = '', buf_start = '', buf_end = '')
130
- output = buf_start
131
- cur = 0
132
- count = 0
133
- new_line = true
134
-
135
- # Go through each byte in the string
136
- str.each_byte { |byte|
137
- count += 1
138
- append = ''
139
-
140
- # If this is a new line, prepend with the
141
- # line start text
142
- if (new_line == true)
143
- append << line_start
144
- new_line = false
145
- end
146
-
147
- # Append the hexified version of the byte
148
- append << sprintf("\\x%.2x", byte)
149
- cur += append.length
150
-
151
- # If we're about to hit the column or have gone past it,
152
- # time to finish up this line
153
- if ((cur + line_end.length >= col) or (cur + buf_end.length >= col))
154
- new_line = true
155
- cur = 0
130
+ if col < line_start.length + 4 + line_end.length
131
+ # raise an exception
132
+ raise ArgumentError.new('insufficient column width')
133
+ end
156
134
 
157
- # If this is the last byte, use the buf_end instead of
158
- # line_end
159
- if (count == str.length)
160
- append << buf_end + "\n"
161
- else
162
- append << line_end + "\n"
163
- end
135
+ ret = buf_start.dup
136
+ ret << line_start if ret.end_with?("\n")
137
+ str.each_char do |char|
138
+ # "\x##".length is 4, check if we're going over the wrap boundary
139
+ if (ret.split("\n").last || '').length + 4 + line_end.length > col
140
+ ret << "#{line_end}\n#{line_start}"
164
141
  end
165
-
166
- output << append
167
- }
168
-
169
- # If we were in the middle of a line, finish the buffer at this point
170
- if (new_line == false)
171
- output << buf_end + "\n"
142
+ ret << "\\x" << char.unpack('H*')[0]
172
143
  end
173
-
174
- return output
144
+ ret << "\n" if ret.split("\n").last.length + buf_end.length > col
145
+ ret << "#{buf_end}\n"
175
146
  end
176
147
 
177
148
  #
data/lib/rex/text/lang.rb CHANGED
@@ -29,13 +29,14 @@ module Rex
29
29
 
30
30
  def self.to_csharp(str, wrap = DefaultWrap, name = "buf")
31
31
  ret = "byte[] #{name} = new byte[#{str.length}] {"
32
- i = -1;
33
- while (i += 1) < str.length
34
- ret << "\n" if i%(wrap/4) == 0
35
- ret << "0x" << str[i].unpack("H*")[0] << ","
32
+ str.each_char do |char|
33
+ # "0x##,".length is 5, check if we're going over the wrap boundary
34
+ ret << "\n" if ret.split("\n").last.length + 5 > wrap
35
+ ret << "0x" << char.unpack('H*')[0] << ","
36
36
  end
37
- ret = ret[0..ret.length-2] #cut off last comma
38
- ret << " };\n"
37
+ ret = ret[0..ret.length - 2] unless str.empty? # cut off last comma
38
+ ret << "\n" if ret.split("\n").last.length + 2 > wrap
39
+ ret << "};\n"
39
40
  end
40
41
 
41
42
  #
@@ -43,21 +44,46 @@ module Rex
43
44
  #
44
45
  def self.to_golang(str, wrap = DefaultWrap, name = "buf")
45
46
  ret = "#{name} := []byte{"
46
- i = -1;
47
- while (i += 1) < str.length
48
- ret << "\n" if i%(wrap/4) == 0
49
- ret << "0x" << str[i].unpack("H*")[0] << ", "
47
+ str.each_char do |char|
48
+ # "0x##,".length is 5, check if we're going over the wrap boundary
49
+ ret << "\n" if ret.split("\n").last.length + 5 > wrap
50
+ ret << "0x" << char.unpack('H*')[0] << ","
50
51
  end
51
- ret = ret[0..ret.length-3] #cut off last comma
52
- ret << " }\n"
53
-
52
+ ret = ret[0..ret.length - 2] unless str.empty? # cut off last comma
53
+ ret << "\n" if ret.split("\n").last.length + 2 > wrap
54
+ ret << "};\n"
54
55
  end
55
-
56
+
56
57
  #
57
58
  # Creates a golang style comment
58
59
  #
59
60
  def self.to_golang_comment(str, wrap = DefaultWrap)
60
- return "/*\n" + wordwrap(str, 0, wrap, '', '') + "*/\n"
61
+ return "/*\n" + wordwrap(str, 0, wrap, '', '') + "*/\n"
62
+ end
63
+
64
+ #
65
+ # Converts to a nim style array of bytes
66
+ #
67
+ def self.to_nim(str, wrap = DefaultWrap, name = "buf")
68
+ raise ArgumentError.new('str can not be empty') if str.empty?
69
+
70
+ ret = "var #{name}: array[#{str.length}, byte] = [\n"
71
+ ret << "byte "
72
+ str.each_char do |char|
73
+ # "0x##,".length is 5, check if we're going over the wrap boundary
74
+ ret << "\n" if ret.split("\n").last.length + 5 > wrap
75
+ ret << "0x" << char.unpack('H*')[0] << ","
76
+ end
77
+ ret = ret[0..ret.length - 2] unless str.empty? # cut off last comma
78
+ ret << "\n" if ret.split("\n").last.length + 1 > wrap
79
+ ret << "]\n"
80
+ end
81
+
82
+ #
83
+ # Creates a nim style comment
84
+ #
85
+ def self.to_nim_comment(str, wrap = DefaultWrap)
86
+ return "#[\n" + wordwrap(str, 0, wrap, '', '') + "]#\n"
61
87
  end
62
88
 
63
89
  #
@@ -181,6 +207,5 @@ module Rex
181
207
  return wordwrap(str, 0, wrap, '', '# ')
182
208
  end
183
209
 
184
-
185
210
  end
186
211
  end
@@ -1,5 +1,5 @@
1
1
  module Rex
2
2
  module Text
3
- VERSION = "0.2.42"
3
+ VERSION = "0.2.45"
4
4
  end
5
5
  end
@@ -390,6 +390,7 @@ protected
390
390
  # Converts a row to a string.
391
391
  #
392
392
  def row_to_s(row) # :nodoc:
393
+ row = row.each_with_index.map { |cell, index| style_table_field(cell, index) }
393
394
  optimal_widths = calculate_optimal_widths
394
395
  values_as_chunks = chunk_values(row, optimal_widths)
395
396
  chunks_to_s(values_as_chunks, optimal_widths)
@@ -401,17 +402,134 @@ protected
401
402
  # widths. For now it simply returns the string's length.
402
403
  #
403
404
  def display_width(str)
404
- str.length
405
+ Rex::Text.display_width(str)
405
406
  end
406
407
 
408
+ #
409
+ # Returns a string of color/formatting codes made up of the previously stored color_state
410
+ # e.g. if a `%blu` color code spans multiple lines this will return a string of `%blu` to be appended to
411
+ # the beginning of each row
412
+ #
413
+ # @param [Hash<String, String>] color_state tracks current color/formatting codes within table row
414
+ # @returns [String] Color code string such as `%blu%grn'
415
+ def color_code_string_for(color_state)
416
+ result = ''.dup
417
+ color_state.each do |_format, value|
418
+ if value.is_a?(Array)
419
+ result << value.uniq.join
420
+ else
421
+ result << value
422
+ end
423
+ end
424
+ result
425
+ end
426
+
427
+ # @returns [Hash<String, String>] The supported color codes from {Rex::Text::Color} grouped into sections
428
+ def color_code_groups
429
+ return @color_code_groups if @color_code_groups
430
+
431
+ @color_code_groups = {
432
+ foreground: %w[
433
+ %cya %red %grn %blu %yel %whi %mag %blk
434
+ %dred %dgrn %dblu %dyel %dcya %dwhi %dmag
435
+ ],
436
+ background: %w[
437
+ %bgblu %bgyel %bggrn %bgmag %bgblk %bgred %bgcyn %bgwhi
438
+ ],
439
+ decoration: %w[
440
+ %und %bld
441
+ ],
442
+ clear: %w[
443
+ %clr
444
+ ]
445
+ }
446
+
447
+ # Developer exception raised to ensure all color codes are accounted for. Verified via tests.
448
+ missing_color_codes = (Rex::Text::Color::SUPPORTED_FORMAT_CODES - @color_code_groups.values.flatten)
449
+ raise "Unsupported color codes #{missing_color_codes.join(', ')}" if missing_color_codes.any?
450
+
451
+ @color_code_groups
452
+ end
453
+
454
+ # Find the preceding color type and value of a given string
455
+ # @param [String] string A string such as '%bgyel etc'
456
+ # @returns [Array,nil] A tuple with the color type and value, or nil
457
+ def find_color_type_and_value(string)
458
+ color_code_groups.each do |color_type, color_values|
459
+ color_value = color_values.find { |color_value| string.start_with?(color_value) }
460
+ if color_value
461
+ return [color_type, color_value]
462
+ end
463
+ end
464
+
465
+ nil
466
+ end
467
+
468
+ #
469
+ # Takes an array of row values and an integer of optimal column width, loops over array and parses
470
+ # each string to gather color/formatting tags and handles those appropriately while not increasing the column width
471
+ #
472
+ # e.g. if a formatting "%blu" spans across multiple lines it needs to be added to the beginning off every following
473
+ # line, and each line will have a "%clr" added to the end of each row
474
+ #
475
+ # @param [Array<String>] values
476
+ # @param [Integer] optimal_widths
407
477
  def chunk_values(values, optimal_widths)
408
478
  # First split long strings into an array of chunks, where each chunk size is the calculated column width
409
479
  values_as_chunks = values.each_with_index.map do |value, idx|
480
+ color_state = {}
410
481
  column_width = optimal_widths[idx]
411
- value
412
- .chars
413
- .each_slice(column_width)
414
- .map(&:join)
482
+ chunks = []
483
+ current_chunk = nil
484
+ chars = value.chars
485
+ char_index = 0
486
+
487
+ # Check if any color code(s) from previous the string need appended
488
+ while char_index < chars.length do
489
+ # If a new chunk has started, start the chunk with any previous color codes
490
+ if current_chunk.nil? && color_state.any?
491
+ current_chunk = color_code_string_for(color_state)
492
+ end
493
+ current_chunk ||= ''.dup
494
+
495
+ # Check if the remaining chars start with a color code such as %blu
496
+ color_type_and_value = chars[char_index] == '%' ? find_color_type_and_value(chars[char_index..].join) : nil
497
+ if color_type_and_value.nil?
498
+ current_chunk << chars[char_index]
499
+ char_index += 1
500
+ else
501
+ color_type, color_code = color_type_and_value
502
+
503
+ if color_type == :clear
504
+ color_state.clear
505
+ elsif color_type == :decoration
506
+ # Multiple decorations can be enabled
507
+ color_state[:decoration] ||= []
508
+ color_state[:decoration] << color_code
509
+ else
510
+ # There can only be one foreground or background color
511
+ color_state[color_type] = color_code
512
+ end
513
+
514
+ current_chunk << color_code
515
+ char_index += color_code.length
516
+ end
517
+
518
+ # If we've reached the final character of the string, or need to word wrap
519
+ # it's time to push the current chunk, and start a new row. Also discard
520
+ # any values that are purely colors and have no display_width
521
+ is_final_character = char_index >= chars.length
522
+ display_width = display_width(current_chunk)
523
+ if (is_final_character && display_width != 0) || display_width == column_width
524
+ if color_state.any? && !current_chunk.end_with?('%clr')
525
+ current_chunk << '%clr'
526
+ end
527
+ chunks.push(current_chunk)
528
+ current_chunk = nil
529
+ end
530
+ end
531
+
532
+ chunks
415
533
  end
416
534
 
417
535
  values_as_chunks
@@ -424,12 +542,13 @@ protected
424
542
  line = ""
425
543
  row_chunks.each_with_index do |chunk, idx|
426
544
  column_width = optimal_widths[idx]
545
+ chunk_length_with_padding = column_width + (chunk.to_s.length - display_width(chunk.to_s))
427
546
 
428
547
  if idx == 0
429
548
  line << ' ' * indent
430
549
  end
431
550
 
432
- line << chunk.to_s.ljust(column_width)
551
+ line << chunk.to_s.ljust(chunk_length_with_padding)
433
552
  line << ' ' * cellpad
434
553
  end
435
554
 
@@ -519,13 +638,12 @@ protected
519
638
  str_cp
520
639
  end
521
640
 
522
- def style_table_field(str, _idx)
641
+ def style_table_field(str, idx)
523
642
  str_cp = str.dup
524
643
 
525
- # Not invoking as color currently conflicts with the wrapping of tables
526
- # colprops[idx]['Stylers'].each do |s|
527
- # str_cp = s.style(str_cp)
528
- # end
644
+ colprops[idx]['Stylers'].each do |s|
645
+ str_cp = s.style(str_cp)
646
+ end
529
647
 
530
648
  str_cp
531
649
  end
data/lib/rex/text.rb CHANGED
@@ -98,6 +98,21 @@ module Rex
98
98
  end
99
99
 
100
100
 
101
+ # @return [Regexp] Matches a valid color code, i.e. "%blu,%yel,...etc"
102
+ COLOR_CODES_REGEX = /#{Regexp.union(Rex::Text::Color::SUPPORTED_FORMAT_CODES.compact).source}/
103
+ private_constant :COLOR_CODES_REGEX
104
+
105
+ #
106
+ # Function that aims to calculate the display width of the given string.
107
+ # In the future this will be aware of East Asian characters having different display
108
+ # widths. For now it simply returns the string's length ignoring color codes.
109
+ #
110
+ # @param [String] str
111
+ # @return [Integer]
112
+ def self.display_width(str)
113
+ str.gsub(COLOR_CODES_REGEX, '').length
114
+ end
115
+
101
116
  #
102
117
  # Convert 16-byte string to a GUID string
103
118
  #
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rex-text
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.42
4
+ version: 0.2.45
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -93,7 +93,7 @@ cert_chain:
93
93
  EknWpNgVhohbot1lfVAMmIhdtOVaRVcQQixWPwprDj/ydB8ryDMDosIMcw+fkoXU
94
94
  9GJsSaSRRYQ9UUkVL27b64okU8D48m8=
95
95
  -----END CERTIFICATE-----
96
- date: 2022-09-01 00:00:00.000000000 Z
96
+ date: 2022-09-06 00:00:00.000000000 Z
97
97
  dependencies:
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: rake
metadata.gz.sig CHANGED
Binary file