Module: Brick::Rails

Defined in:
lib/brick/frameworks/rails/engine.rb

Defined Under Namespace

Modules: FormBuilder, FormTags Classes: Engine

Class Method Summary collapse

Class Method Details

.display_binary(val, max_size = 100_000) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/brick/frameworks/rails/engine.rb', line 78

def display_binary(val, max_size = 100_000)
  return unless val

  @image_signatures ||= { (+"\xFF\xD8\xFF\xEE").force_encoding('ASCII-8BIT') => 'jpeg',
                          (+"\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01").force_encoding('ASCII-8BIT') => 'jpeg',
                          (+"\xFF\xD8\xFF\xDB").force_encoding('ASCII-8BIT') => 'jpeg',
                          (+"\xFF\xD8\xFF\xE1").force_encoding('ASCII-8BIT') => 'jpeg',
                          (+"\x89PNG\r\n\x1A\n").force_encoding('ASCII-8BIT') => 'png',
                          '<svg' => 'svg+xml', # %%% Not yet very good detection for SVG
                          (+'BM').force_encoding('ASCII-8BIT') => 'bmp',
                          (+'GIF87a').force_encoding('ASCII-8BIT') => 'gif',
                          (+'GIF89a').force_encoding('ASCII-8BIT') => 'gif' }

  if val[0..1] == "\x15\x1C" # One of those goofy Microsoft OLE containers?
    package_header_length = val[2..3].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
    # This will often be just FF FF FF FF
    # object_size = val[16..19].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
    friendly_and_class_names = val[20...package_header_length].split("\0")
    object_type_name_length = val[package_header_length + 8..package_header_length+11].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
    friendly_and_class_names << val[package_header_length + 12...package_header_length + 12 + object_type_name_length].strip
    # friendly_and_class_names will now be something like:  ['Bitmap Image', 'Paint.Picture', 'PBrush']
    real_object_size = val[package_header_length + 20 + object_type_name_length..package_header_length + 23 + object_type_name_length].bytes.reverse.inject(0) {|m, b| (m << 8) + b }
    object_start = package_header_length + 24 + object_type_name_length
    val = val[object_start...object_start + real_object_size]
  end

  if ((signature = @image_signatures.find { |k, _v| val[0...k.length] == k }&.last) ||
      (val[0..3] == 'RIFF' && val[8..11] == 'WEBP' && binding.local_variable_set(:signature, 'webp'))) &&
     val.length < max_size
    "<img src=\"data:image/#{signature.last};base64,#{Base64.encode64(val)}\">"
  else
    "&lt;&nbsp;#{signature ? "#{signature} image" : 'Binary'}, #{val.length} bytes&nbsp;>"
  end
end

.display_value(col_type, val, lat_lng = nil) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/brick/frameworks/rails/engine.rb', line 6

def display_value(col_type, val, lat_lng = nil)
  is_mssql_geography = nil
  # Some binary thing that really looks like a Microsoft-encoded WGS84 point?  (With the first two bytes, E6 10, indicating an EPSG code of 4326)
  if col_type == :binary && val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12]
    col_type = 'geography'
    is_mssql_geography = true
  end
  case col_type
  when 'geometry', 'geography'
    if Object.const_defined?('RGeo')
      @is_mysql = ['Mysql2', 'Trilogy'].include?(ActiveRecord::Base.connection.adapter_name) if @is_mysql.nil?
      @is_mssql = ActiveRecord::Base.connection.adapter_name == 'SQLServer' if @is_mssql.nil?
      val_err = nil

      if @is_mysql || (is_mssql_geography ||=
                        (@is_mssql ||
                          (val && val.length < 31 && (val.length - 6) % 8 == 0 && val[0..5].bytes == [230, 16, 0, 0, 1, 12])
                        )
                      )
        # MySQL's \"Internal Geometry Format\" and MSSQL's Geography are like WKB, but with an initial 4 bytes that indicates the SRID.
        if (srid = val&.[](0..3)&.unpack('I'))
          val = val.dup.force_encoding('BINARY')[4..-1].bytes

          # MSSQL spatial bitwise flags, often 0C for a point:
          # xxxx xxx1 = HasZValues
          # xxxx xx1x = HasMValues
          # xxxx x1xx = IsValid
          # xxxx 1xxx = IsSinglePoint
          # xxx1 xxxx = IsSingleLineSegment
          # xx1x xxxx = IsWholeGlobe
          # Convert Microsoft's unique geography binary to standard WKB
          # (MSSQL point usually has two doubles, lng / lat, and can also have Z)
          if is_mssql_geography
            if val[0] == 1 && (val[1] & 8 > 0) && # Single point?
               (val.length - 2) % 8 == 0 && val.length < 27 # And containing up to three 8-byte values?
              val = [0, 0, 0, 0, 1] + val[2..-1].reverse
            else
              val_err = '(Microsoft internal SQL geography type)'
            end
          end
        end
      end
      unless val_err || val.nil?
        val = if ((geometry = RGeo::WKRep::WKBParser.new.parse(val.pack('c*'))).is_a?(RGeo::Cartesian::PointImpl) ||
                  geometry.is_a?(RGeo::Geos::CAPIPointImpl)) &&
                 !(geometry.y == 0.0 && geometry.x == 0.0)
                # Create a POINT link to this style of Google maps URL:  https://www.google.com/maps/place/38.7071296+-121.2810649/@38.7071296,-121.2810649,12z
                "<a href=\"https://www.google.com/maps/place/#{geometry.y}+#{geometry.x}/@#{geometry.y},#{geometry.x},12z\" target=\"blank\">#{geometry.to_s}</a>"
              end
      end
      val_err || val
    else
      '(Add RGeo gem to parse geometry detail)'
    end
  when :binary
    ::Brick::Rails.display_binary(val)
  else
    if col_type
      if lat_lng && !(lat_lng.first.zero? && lat_lng.last.zero?)
        # Create a link to this style of Google maps URL:  https://www.google.com/maps/place/38.7071296+-121.2810649/@38.7071296,-121.2810649,12z
        "<a href=\"https://www.google.com/maps/place/#{lat_lng.first}+#{lat_lng.last}/@#{lat_lng.first},#{lat_lng.last},12z\" target=\"blank\">#{val}</a>"
      elsif val.is_a?(Numeric) && ::ActiveSupport.const_defined?(:NumberHelper)
        ::ActiveSupport::NumberHelper.number_to_delimited(val, delimiter: ',')
      else
        ::Brick::Rails::FormBuilder.hide_bcrypt(val, col_type == :xml)
      end
    else
      '?'
    end
  end
end