#
# Copyright (C) 2008, 2009 Wayne Meissner
# Copyright (c) 2007, 2008 Evan Phoenix
#
# This file is part of ruby-ffi.
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the Ruby FFI project nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
require 'ffi/platform'
# NOTE: all method definitions in this file are conditional on
# whether they are not already defined. This is needed because
# some Ruby implementations (e.g., TruffleRuby) might already
# provide these methods due to using FFI internally, and we
# should not override them to avoid warnings.
module FFI
class Pointer
# Pointer size
SIZE = Platform::ADDRESS_SIZE / 8 unless const_defined?(:SIZE)
# Return the size of a pointer on the current platform, in bytes
# @return [Integer]
def self.size
SIZE
end unless respond_to?(:size)
# @param [nil,Integer] len length of string to return
# @return [String]
# Read pointer's contents as a string, or the first +len+ bytes of the
# equivalent string if +len+ is not +nil+.
def read_string(len=nil)
if len
return ''.b if len == 0
get_bytes(0, len)
else
get_string(0)
end
end unless method_defined?(:read_string)
# @param [Integer] len length of string to return
# @return [String]
# Read the first +len+ bytes of pointer's contents as a string.
#
# Same as:
# ptr.read_string(len) # with len not nil
def read_string_length(len)
get_bytes(0, len)
end unless method_defined?(:read_string_length)
# @return [String]
# Read pointer's contents as a string.
#
# Same as:
# ptr.read_string # with no len
def read_string_to_null
get_string(0)
end unless method_defined?(:read_string_to_null)
# @param [String] str string to write
# @param [Integer] len length of string to return
# @return [self]
# Write +len+ first bytes of +str+ in pointer's contents.
#
# Same as:
# ptr.write_string(str, len) # with len not nil
def write_string_length(str, len)
put_bytes(0, str, 0, len)
end unless method_defined?(:write_string_length)
# @param [String] str string to write
# @param [Integer] len length of string to return
# @return [self]
# Write +str+ in pointer's contents, or first +len+ bytes if
# +len+ is not +nil+.
def write_string(str, len=nil)
len = str.bytesize unless len
# Write the string data without NUL termination
put_bytes(0, str, 0, len)
end unless method_defined?(:write_string)
# @param [Type] type type of data to read from pointer's contents
# @param [Symbol] reader method to send to +self+ to read +type+
# @param [Integer] length
# @return [Array]
# Read an array of +type+ of length +length+.
# @example
# ptr.read_array_of_type(TYPE_UINT8, :read_uint8, 4) # -> [1, 2, 3, 4]
def read_array_of_type(type, reader, length)
ary = []
size = FFI.type_size(type)
tmp = self
length.times { |j|
ary << tmp.send(reader)
tmp += size unless j == length-1 # avoid OOB
}
ary
end unless method_defined?(:read_array_of_type)
# @param [Type] type type of data to write to pointer's contents
# @param [Symbol] writer method to send to +self+ to write +type+
# @param [Array] ary
# @return [self]
# Write +ary+ in pointer's contents as +type+.
# @example
# ptr.write_array_of_type(TYPE_UINT8, :put_uint8, [1, 2, 3 ,4])
def write_array_of_type(type, writer, ary)
size = FFI.type_size(type)
ary.each_with_index { |val, i|
break unless i < self.size
self.send(writer, i * size, val)
}
self
end unless method_defined?(:write_array_of_type)
# @return [self]
def to_ptr
self
end unless method_defined?(:to_ptr)
# @param [Symbol,Type] type of data to read
# @return [Object]
# Read pointer's contents as +type+
#
# Same as:
# ptr.get(type, 0)
def read(type)
get(type, 0)
end unless method_defined?(:read)
# @param [Symbol,Type] type of data to read
# @param [Object] value to write
# @return [nil]
# Write +value+ of type +type+ to pointer's content
#
# Same as:
# ptr.put(type, 0)
def write(type, value)
put(type, 0, value)
end unless method_defined?(:write)
end
end