Class: RightScale::Platform::PlatformHelperBase

Inherits:
Object
  • Object
show all
Defined in:
lib/right_agent/platform.rb,
lib/right_agent/platform/windows/platform.rb,
lib/right_agent/platform/windows/mingw/platform.rb,
lib/right_agent/platform/windows/mswin/platform.rb

Overview

helpers

Constant Summary collapse

SIZEOF_DWORD =

constants

4
SIZEOF_QWORD =

double-word

8
WIDE =

_W (i.e. ‘wide’) Windows APIs all use little-endian unicode.

_A doesn’t correspond to any particular single/multi-byte encoding (even though n00bs get confused and think in means ASCII). _A actually means ‘use the current codepage’ for which you would need to make another API call to discover what the current thread thinks is the current codepage.

::Encoding::UTF_16LE
API_NULL =
0
API_FALSE =
0
API_TRUE =
1

Instance Method Summary collapse

Instance Method Details

#copy_to_string_buffer(source_buffer, target_buffer, options = {}) ⇒ Integer

Performs a bytewise copy to given target buffer with respect for the encoding of the source and target buffers. Assumes a NUL terminator appears in the string to be copied per normal Windows API behavor.

Parameters:

  • source_buffer (String)

    encoded source

  • target_buffer (String)

    encoded target

  • options (Hash) (defaults to: {})

    for copy

Options Hash (options):

  • :truncate (TrueClass|FalseClass)

    is true to allow trunction of string to fit buffer, false to return required buffer size if copy would exceed buffer

Returns:

  • (Integer)

    length of encoded target or else buffer length needed for full copy



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/right_agent/platform/windows/mingw/platform.rb', line 104

def copy_to_string_buffer(source_buffer, target_buffer, options = {})
  options = { :truncate => false }.merge(options)

  # note that a buffer of NULs will default to ASCII encoding in
  # ruby 1.9 so change to use default encoding automagically. this makes
  # it easier to support the default codepage in 1.9 but be oblivious to
  # it in 1.8, which does not support these encoding methods. if the
  # caller wants any other codepage (in 1.9) then it should be specified
  # on the target.
  if target_buffer.encoding == Encoding::ASCII
    # we can force encoding only if the default encoding is ASCII
    # compatible. we are going to clobber the bytes so the old bytes are
    # irrelevant unless the bytesize of the buffer would differ.
    if ::Encoding.default_external.ascii_compatible?
      # note that force_encoding modifies self even though it's not a
      # banged! method.
      target_buffer.force_encoding(::Encoding.default_external)
    else
      target_buffer.encode!(::Encoding.default_external)
    end
  end

  # reencode the source buffer, changing any characters that cannot be
  # encoded to the default replacement character, which is usually '?'
  target_encoding = target_buffer.encoding
  reencoded_source_buffer = source_buffer.encode(
    target_encoding, :invalid => :replace, :undef => :replace)

  # determine if sufficient buffer exists.
  result = nil
  nul_char = 0.chr.encode(target_encoding)
  reencoded_source_length = reencoded_source_buffer.index(nul_char) ||
    reencoded_source_buffer.length
  if reencoded_source_length <= target_buffer.length || options[:truncate]
    # bytewise replacement (to reuse caller's buffer instead of
    # reallocating the string's buffer).
    copy_length = [reencoded_source_length, target_buffer.length - 1].min
    copy_byte_count = nul_char.bytesize * copy_length
    reencoded_source_buffer.bytes.each_with_index do |b, b_index|
      break if b_index >= copy_byte_count
      target_buffer.setbyte(b_index, b)
    end
    target_buffer[copy_length] = nul_char
    result = copy_length
  else
    result = reencoded_source_length
  end
  result
end

#with_unicode_buffer(buffer, copy_options = {}) {|buffer| ... } ⇒ String

We favor the _W APIs to ensure proper marshalling of Unicode characters to/from the ruby interpreter’s default codepage. This method facilitates API calls that fill a Unicode buffer and need to marshal the buffered data to a multi-byte (default encoding) buffer.

Parameters:

  • buffer (String)

    to receive marshalled data from Unicode API or nil to query required buffer.

  • copy_options (Hash) (defaults to: {})

    for copy_to_string_buffer

Yields:

  • (buffer)

    yields the buffer at current size for API call

Yield Parameters:

  • buffer (String)

    to use for API call (get size from buffer) or nil to query required buffer size.

Returns:

  • (String)

    buffered data length or zero for failure



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/right_agent/platform/windows/mingw/platform.rb', line 61

def with_unicode_buffer(buffer, copy_options = {})
  # note that _W methods always expect UTF-16 LE (Little Endian) due to
  # the Intel chipset representing word values as LE. Windows runs on
  # other chipsets but LE is always used by API calls.
  if buffer && buffer.encoding != WIDE
    unicode_buffer = 0.chr.encode(WIDE) * buffer.size
    unicode_length_or_buffer_count = yield(unicode_buffer)

    if unicode_length_or_buffer_count > 0 &&
       unicode_length_or_buffer_count < unicode_buffer.size

      # reencode to non-Unicode buffer, including trailing NUL character.
      #
      # note that reencoding may exceed given (Unicode) buffer size
      # because of two-byte chars expanded from single unicode chars.
      # in this case the required multi-byte buffer size will be returned
      # and then promoted to a 'doubled' Unicode buffer size on next call.
      result = copy_to_string_buffer(
        unicode_buffer[0, unicode_length_or_buffer_count + 1],
        buffer,
        copy_options)
    else
      result = unicode_length_or_buffer_count
    end
  else
    # buffer is already UTF-16LE or else nil
    result = yield(buffer)
  end
  result
end