rex-text 0.2.43 → 0.2.44

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: e65388b19aabaf76461efffee8b8b0b5c23265a5eff2f9adee5300a5664210c6
4
- data.tar.gz: 4d697d31bf0464783450ff70494bb08f5d00e9186cea660e426e693bc6d025b6
3
+ metadata.gz: b88966aea3c2991faabd788caf7b9141968550554530da585e6cb46207c33d64
4
+ data.tar.gz: 233562b44e969d9a210695571a3aa84fcd4c4d84a6b0d22846696f84ff67a1d5
5
5
  SHA512:
6
- metadata.gz: ef32b2087d8fd1016e69a7584baf2a44999d661d8261468b5e8a462ee42523336b32b5e6dad59b6308b7fdac2b006d848e71bdb3b9c81798c7c70364f0d15ec6
7
- data.tar.gz: 14edb8ce455acae1c6caaca90ee259dbc0d29df0b539440f8242c29e919ebc6ad8954d398c00166f74f7bf14b08e9ddb03b0a886e674447cb8b1c98ec30245a4
6
+ metadata.gz: 6cd18682c4ffcaedc3c3177f27c42e93b4009cce7316090d3a64f84207895af48393f8cd431bd062fcc5c14f10241ad5537b464e2c5484bc1c513a4ed7d76502
7
+ data.tar.gz: 29cc99e565a56b899e43f8f9312ab9520abb3838ee68d8d3702de6ee13f080bc1929401837a0a32df3e00e29f673ae3d5aeee880e765fcf2f1b5727f60dfea76
checksums.yaml.gz.sig CHANGED
@@ -1,3 +1,2 @@
1
- _<) ��# xg�+'4�%g+?e�-�$����lV7��/��C���lT��&�rK�`�e?��3yf������
2
- PAl*���9�r�\a��u��>L�܃�!r�,����'r�@�vv��y���Д
3
- �_XN�z��$Uk��,~������-��{�u�م(��m-�������O���Ȑ��)�>i{�o ���,I!M��7�"�p���leȣ��+
1
+ >�ni����u-�t76�5w�8��X�Nt���k�ܘ\$$�W;��_����i�j2H����|��(�i���m���E��k���xtR��@ĝ
2
+ �L�W��@Q2&�պ�(
@@ -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
  {
@@ -1,5 +1,5 @@
1
1
  module Rex
2
2
  module Text
3
- VERSION = "0.2.43"
3
+ VERSION = "0.2.44"
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.43
4
+ version: 0.2.44
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-02 00:00:00.000000000 Z
97
97
  dependencies:
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: rake
metadata.gz.sig CHANGED
Binary file