Suporte ao desenvolvimento de jogos!


    Workarround pra classe TCPSocket

    Compartilhe

    Cidiomar
    Semi-Experiente
    Semi-Experiente

    Mensagens : 115
    Créditos : 51

    Workarround pra classe TCPSocket

    Mensagem por Cidiomar em Dom Jan 29, 2012 2:57 am

    Este script cria a possibilidade de conexão com a internet via TCPSocket pelo RPGMaker VXAce.

    Não devo mais precisar desde script, por tanto não devo mais atualiza-lo, então resolvi postar.

    Ela possui dependências não supridas pelo RGSS3, ele inclui a extensão dl, mas não os seus arquivos .rb(com exceção do 'Win32API.rb'), então será necessário repor esses scripts:

    Código:

    #
    #      thread.rb - thread support classes
    #         by Yukihiro Matsumoto <matz@netlab.co.jp>
    #
    # Copyright (C) 2001  Yukihiro Matsumoto
    # Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
    # Copyright (C) 2000  Information-technology Promotion Agency, Japan
    #

    unless defined? Thread
      raise "Thread not available for this ruby interpreter"
    end

    unless defined? ThreadError
      class ThreadError < StandardError
      end
    end

    if $DEBUG
      Thread.abort_on_exception = true
    end

    #
    # ConditionVariable objects augment class Mutex. Using condition variables,
    # it is possible to suspend while in the middle of a critical section until a
    # resource becomes available.
    #
    # Example:
    #
    #  require 'thread'
    #
    #  mutex = Mutex.new
    #  resource = ConditionVariable.new

    #  a = Thread.new {
    #    mutex.synchronize {
    #      # Thread 'a' now needs the resource
    #      resource.wait(mutex)
    #      # 'a' can now have the resource
    #    }
    #  }

    #  b = Thread.new {
    #    mutex.synchronize {
    #      # Thread 'b' has finished using the resource
    #      resource.signal
    #    }
    #  }
    #
    class ConditionVariable
      #
      # Creates a new ConditionVariable
      #
      def initialize
        @waiters = []
        @waiters_mutex = Mutex.new
      end
     
      #
      # Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
      #
      def wait(mutex)
        begin
          # TODO: mutex should not be used
          @waiters_mutex.synchronize do
            @waiters.push(Thread.current)
          end
          mutex.sleep
        end
      end
     
      #
      # Wakes up the first thread in line waiting for this lock.
      #
      def signal
        begin
          t = @waiters_mutex.synchronize { @waiters.shift }
          t.run if t
        rescue ThreadError
          retry
        end
      end
       
      #
      # Wakes up all threads waiting for this lock.
      #
      def broadcast
        # TODO: imcomplete
        waiters0 = nil
        @waiters_mutex.synchronize do
          waiters0 = @waiters.dup
          @waiters.clear
        end
        for t in waiters0
          begin
       t.run
          rescue ThreadError
          end
        end
      end
    end

    #
    # This class provides a way to synchronize communication between threads.
    #
    # Example:
    #
    #  require 'thread'

    #  queue = Queue.new

    #  producer = Thread.new do
    #    5.times do |i|
    #      sleep rand(i) # simulate expense
    #      queue << i
    #      puts "#{i} produced"
    #    end
    #  end

    #  consumer = Thread.new do
    #    5.times do |i|
    #      value = queue.pop
    #      sleep rand(i/2) # simulate expense
    #      puts "consumed #{value}"
    #    end
    #  end

    #  consumer.join
    #
    class Queue
      #
      # Creates a new queue.
      #
      def initialize
        @que = []
        @waiting = []
        @que.taint      # enable tainted comunication
        @waiting.taint
        self.taint
        @mutex = Mutex.new
      end

      #
      # Pushes +obj+ to the queue.
      #
      def push(obj)
        t = nil
        @mutex.synchronize{
          @que.push obj
          begin
            t = @waiting.shift
            t.wakeup if t
          rescue ThreadError
            retry
          end
        }
        begin
          t.run if t
        rescue ThreadError
        end
      end

      #
      # Alias of push
      #
      alias << push

      #
      # Alias of push
      #
      alias enq push

      #
      # Retrieves data from the queue.  If the queue is empty, the calling thread is
      # suspended until data is pushed onto the queue.  If +non_block+ is true, the
      # thread isn't suspended, and an exception is raised.
      #
      def pop(non_block=false)
        while true
          @mutex.synchronize{
            if @que.empty?
              raise ThreadError, "queue empty" if non_block
              @waiting.push Thread.current
              @mutex.sleep
            else
              return @que.shift
            end
          }
        end
      end

      #
      # Alias of pop
      #
      alias shift pop

      #
      # Alias of pop
      #
      alias deq pop

      #
      # Returns +true+ if the queue is empty.
      #
      def empty?
        @que.empty?
      end

      #
      # Removes all objects from the queue.
      #
      def clear
        @que.clear
      end

      #
      # Returns the length of the queue.
      #
      def length
        @que.length
      end

      #
      # Alias of length.
      #
      alias size length

      #
      # Returns the number of threads waiting on the queue.
      #
      def num_waiting
        @waiting.size
      end
    end

    #
    # This class represents queues of specified size capacity.  The push operation
    # may be blocked if the capacity is full.
    #
    # See Queue for an example of how a SizedQueue works.
    #
    class SizedQueue < Queue
      #
      # Creates a fixed-length queue with a maximum size of +max+.
      #
      def initialize(max)
        raise ArgumentError, "queue size must be positive" unless max > 0
        @max = max
        @queue_wait = []
        @queue_wait.taint      # enable tainted comunication
        super()
      end

      #
      # Returns the maximum size of the queue.
      #
      def max
        @max
      end

      #
      # Sets the maximum size of the queue.
      #
      def max=(max)
        diff = nil
        @mutex.synchronize {
          if max <= @max
            @max = max
          else
            diff = max - @max
            @max = max
          end
        }
        if diff
          diff.times do
       begin
         t = @queue_wait.shift
         t.run if t
       rescue ThreadError
         retry
       end
          end
        end
        max
      end

      #
      # Pushes +obj+ to the queue.  If there is no space left in the queue, waits
      # until space becomes available.
      #
      def push(obj)
        t = nil
        @mutex.synchronize{
          while true
            break if @que.length < @max
            @queue_wait.push Thread.current
            @mutex.sleep
          end
       
          @que.push obj
          begin
            t = @waiting.shift
            t.wakeup if t
          rescue ThreadError
            retry
          end
        }
       
        begin
          t.run if t
        rescue ThreadError
        end
      end

      #
      # Alias of push
      #
      alias << push

      #
      # Alias of push
      #
      alias enq push

      #
      # Retrieves data from the queue and runs a waiting thread, if any.
      #
      def pop(*args)
        retval = super
        t = nil
        @mutex.synchronize {
          if @que.length < @max
            begin
              t = @queue_wait.shift
              t.wakeup if t
            rescue ThreadError
              retry
            end
          end
        }
        begin
          t.run if t
        rescue ThreadError
        end
        retval
      end

      #
      # Alias of pop
      #
      alias shift pop

      #
      # Alias of pop
      #
      alias deq pop

      #
      # Returns the number of threads waiting on the queue.
      #
      def num_waiting
        @waiting.size + @queue_wait.size
      end
    end

    # Documentation comments:
    #  - How do you make RDoc inherit documentation from superclass?
    #require 'dl'
    #require 'thread'

    module DL
      SEM = Mutex.new

      def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp)
        if( argc < 0 )
          raise(ArgumentError, "arity should not be less than 0.")
        end
        addr = nil
        SEM.synchronize{
          ary = proc_entry[ty]
          (0...MAX_CALLBACK).each{|n|
            idx = (n * DLSTACK_SIZE) + argc
            if( ary[idx].nil? )
              ary[idx] = cbp
              addr = addr_entry[ty][idx]
              break
            end
          }
        }
        addr
      end

      def set_cdecl_callback(ty, argc, &cbp)
        set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp)
      end

      def set_stdcall_callback(ty, argc, &cbp)
        set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
      end

      def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
        index = nil
        if( ctype )
          addr_entry[ctype].each_with_index{|xaddr, idx|
            if( xaddr == addr )
              index = idx
            end
          }
        else
          addr_entry.each{|ty,entry|
            entry.each_with_index{|xaddr, idx|
              if( xaddr == addr )
                index = idx
              end
            }
          }
        end
        if( index and proc_entry[ctype][index] )
          proc_entry[ctype][index] = nil
          return true
        else
          return false
        end
      end

      def remove_cdecl_callback(addr, ctype = nil)
        remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype)
      end

      def remove_stdcall_callback(addr, ctype = nil)
        remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype)
      end

      alias set_callback set_cdecl_callback
      alias remove_callback remove_cdecl_callback
    end
    module DL
      module CParser
        def parse_struct_signature(signature, tymap=nil)
          if( signature.is_a?(String) )
            signature = signature.split(/\s*,\s*/)
          end
          mems = []
          tys  = []
          signature.each{|msig|
            tks = msig.split(/\s+(\*)?/)
            ty = tks[0..-2].join(" ")
            member = tks[-1]

            case ty
            when /\[(\d+)\]/
              n = $1.to_i
              ty.gsub!(/\s*\[\d+\]/,"")
              ty = [ty, n]
            when /\[\]/
              ty.gsub!(/\s*\[\]/, "*")
            end

            case member
            when /\[(\d+)\]/
              ty = [ty, $1.to_i]
              member.gsub!(/\s*\[\d+\]/,"")
            when /\[\]/
              ty = ty + "*"
              member.gsub!(/\s*\[\]/, "")
            end

            mems.push(member)
            tys.push(parse_ctype(ty,tymap))
          }
          return tys, mems
        end

        def parse_signature(signature, tymap=nil)
          tymap ||= {}
          signature = signature.gsub(/\s+/, " ").strip
          case signature
          when /^([\d\w@\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
            ret = $1
            (args = $2).strip!
            ret = ret.split(/\s+/)
            args = args.split(/\s*,\s*/)
            func = ret.pop
            if( func =~ /^\*/ )
              func.gsub!(/^\*+/,"")
              ret.push("*")
            end
            ret  = ret.join(" ")
            return [func, parse_ctype(ret, tymap), args.collect{|arg| parse_ctype(arg, tymap)}]
          else
            raise(RuntimeError,"can't parse the function prototype: #{proto}")
          end
        end

        def parse_ctype(ty, tymap=nil)
          tymap ||= {}
          case ty
          when Array
            return [parse_ctype(ty[0], tymap), ty[1]]
          when "void"
            return TYPE_VOID
          when "char"
            return TYPE_CHAR
          when "unsigned char"
            return  -TYPE_CHAR
          when "short"
            return TYPE_SHORT
          when "unsigned short"
            return -TYPE_SHORT
          when "int"
            return TYPE_INT
          when "unsigned int"
            return -TYPE_INT
          when "long"
            return TYPE_LONG
          when "unsigned long"
            return -TYPE_LONG
          when "long long"
            if( defined?(TYPE_LONG_LONG) )
              return TYPE_LONG_LONG
            else
              raise(RuntimeError, "unsupported type: #{ty}")
            end
          when "unsigned long long"
            if( defined?(TYPE_LONG_LONG) )
              return -TYPE_LONG_LONG
            else
              raise(RuntimeError, "unsupported type: #{ty}")
            end
          when "float"
            return TYPE_FLOAT
          when "double"
            return TYPE_DOUBLE
          when /\*/, /\[\s*\]/
            return TYPE_VOIDP
          else
            if( tymap[ty] )
              return parse_ctype(tymap[ty], tymap)
            else
              raise(DLError, "unknown type: #{ty}", caller(1))
            end
          end
        end
      end
    end
    #require 'dl'

    module DL
      module PackInfo
        if( defined?(TYPE_LONG_LONG) )
        ALIGN_MAP = {
          TYPE_VOIDP => ALIGN_VOIDP,
          TYPE_CHAR  => ALIGN_CHAR,
          TYPE_SHORT => ALIGN_SHORT,
          TYPE_INT  => ALIGN_INT,
          TYPE_LONG  => ALIGN_LONG,
          TYPE_LONG_LONG => ALIGN_LONG_LONG,
          TYPE_FLOAT => ALIGN_FLOAT,
          TYPE_DOUBLE => ALIGN_DOUBLE,
          -TYPE_CHAR  => ALIGN_CHAR,
          -TYPE_SHORT => ALIGN_SHORT,
          -TYPE_INT  => ALIGN_INT,
          -TYPE_LONG  => ALIGN_LONG,
          -TYPE_LONG_LONG => ALIGN_LONG_LONG,
        }

        PACK_MAP = {
          TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
          TYPE_CHAR  => "c",
          TYPE_SHORT => "s!",
          TYPE_INT  => "i!",
          TYPE_LONG  => "l!",
          TYPE_LONG_LONG => "q",
          TYPE_FLOAT => "f",
          TYPE_DOUBLE => "d",
          -TYPE_CHAR  => "c",
          -TYPE_SHORT => "s!",
          -TYPE_INT  => "i!",
          -TYPE_LONG  => "l!",
          -TYPE_LONG_LONG => "q",
        }

        SIZE_MAP = {
          TYPE_VOIDP => SIZEOF_VOIDP,
          TYPE_CHAR  => SIZEOF_CHAR,
          TYPE_SHORT => SIZEOF_SHORT,
          TYPE_INT  => SIZEOF_INT,
          TYPE_LONG  => SIZEOF_LONG,
          TYPE_LONG_LONG => SIZEOF_LONG_LONG,
          TYPE_FLOAT => SIZEOF_FLOAT,
          TYPE_DOUBLE => SIZEOF_DOUBLE,
          -TYPE_CHAR  => SIZEOF_CHAR,
          -TYPE_SHORT => SIZEOF_SHORT,
          -TYPE_INT  => SIZEOF_INT,
          -TYPE_LONG  => SIZEOF_LONG,
          -TYPE_LONG_LONG => SIZEOF_LONG_LONG,
        }
        else
        ALIGN_MAP = {
          TYPE_VOIDP => ALIGN_VOIDP,
          TYPE_CHAR  => ALIGN_CHAR,
          TYPE_SHORT => ALIGN_SHORT,
          TYPE_INT  => ALIGN_INT,
          TYPE_LONG  => ALIGN_LONG,
          TYPE_FLOAT => ALIGN_FLOAT,
          TYPE_DOUBLE => ALIGN_DOUBLE,
          -TYPE_CHAR  => ALIGN_CHAR,
          -TYPE_SHORT => ALIGN_SHORT,
          -TYPE_INT  => ALIGN_INT,
          -TYPE_LONG  => ALIGN_LONG,
        }

        PACK_MAP = {
          TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
          TYPE_CHAR  => "c",
          TYPE_SHORT => "s!",
          TYPE_INT  => "i!",
          TYPE_LONG  => "l!",
          TYPE_FLOAT => "f",
          TYPE_DOUBLE => "d",
          -TYPE_CHAR  => "c",
          -TYPE_SHORT => "s!",
          -TYPE_INT  => "i!",
          -TYPE_LONG  => "l!",
        }

        SIZE_MAP = {
          TYPE_VOIDP => SIZEOF_VOIDP,
          TYPE_CHAR  => SIZEOF_CHAR,
          TYPE_SHORT => SIZEOF_SHORT,
          TYPE_INT  => SIZEOF_INT,
          TYPE_LONG  => SIZEOF_LONG,
          TYPE_FLOAT => SIZEOF_FLOAT,
          TYPE_DOUBLE => SIZEOF_DOUBLE,
          -TYPE_CHAR  => SIZEOF_CHAR,
          -TYPE_SHORT => SIZEOF_SHORT,
          -TYPE_INT  => SIZEOF_INT,
          -TYPE_LONG  => SIZEOF_LONG,
        }
        end

        def align(addr, align)
          d = addr % align
          if( d == 0 )
            addr
          else
            addr + (align - d)
          end
        end
        module_function :align
      end

      class Packer
        include PackInfo

        def Packer.[](*types)
          Packer.new(types)
        end

        def initialize(types)
          parse_types(types)
        end

        def size()
          @size
        end
       
        def pack(ary)
          case SIZEOF_VOIDP
          when SIZEOF_LONG
            ary.pack(@template)
          when SIZEOF_LONG
            ary.pack(@template)
          else
            raise(RuntimeError, "sizeof(void*)?")
          end
        end

        def unpack(ary)
          case SIZEOF_VOIDP
          when SIZEOF_LONG
            ary.join().unpack(@template)
          when SIZEOF_LONG_LONG
            ary.join().unpack(@template)
          else
            raise(RuntimeError, "sizeof(void*)?")
          end
        end
       
        private
       
        def parse_types(types)
          @template = ""
          addr    = 0
          types.each{|t|
            orig_addr = addr
            if( t.is_a?(Array) )
              addr = align(orig_addr, ALIGN_MAP[TYPE_VOIDP])
            else
              addr = align(orig_addr, ALIGN_MAP[t])
            end
            d = addr - orig_addr
            if( d > 0 )
              @template << "x#{d}"
            end
            if( t.is_a?(Array) )
              @template << (PACK_MAP[t[0]] * t[1])
              addr += (SIZE_MAP[t[0]] * t[1])
            else
              @template << PACK_MAP[t]
              addr += SIZE_MAP[t]
            end
          }
          addr = align(addr, ALIGN_MAP[TYPE_VOIDP])
          @size = addr
        end
      end
    end
    #require 'dl'

    module DL
      class Stack
        def Stack.[](*types)
          Stack.new(types)
        end

        def initialize(types)
          parse_types(types)
        end

        def size()
          @size
        end

        def types()
          @types
        end

        def pack(ary)
          case SIZEOF_VOIDP
          when SIZEOF_LONG
            ary.pack(@template).unpack('l!*')
          when SIZEOF_LONG_LONG
            ary.pack(@template).unpack('q*')
          else
            raise(RuntimeError, "sizeof(void*)?")
          end
        end

        def unpack(ary)
          case SIZEOF_VOIDP
          when SIZEOF_LONG
            ary.pack('l!*').unpack(@template)
          when SIZEOF_LONG_LONG
            ary.pack('q*').unpack(@template)
          else
            raise(RuntimeError, "sizeof(void*)?")
          end
        end
       
        private
       
        def align(addr, align)
          d = addr % align
          if( d == 0 )
            addr
          else
            addr + (align - d)
          end
        end

    if( defined?(TYPE_LONG_LONG) )
        ALIGN_MAP = {
          TYPE_VOIDP => ALIGN_VOIDP,
          TYPE_CHAR  => ALIGN_VOIDP,
          TYPE_SHORT => ALIGN_VOIDP,
          TYPE_INT  => ALIGN_VOIDP,
          TYPE_LONG  => ALIGN_VOIDP,
          TYPE_LONG_LONG => ALIGN_LONG_LONG,
          TYPE_FLOAT => ALIGN_FLOAT,
          TYPE_DOUBLE => ALIGN_DOUBLE,
        }

        PACK_MAP = {
          TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
          TYPE_CHAR  => "c",
          TYPE_SHORT => "s!",
          TYPE_INT  => "i!",
          TYPE_LONG  => "l!",
          TYPE_LONG_LONG => "q",
          TYPE_FLOAT => "f",
          TYPE_DOUBLE => "d",
        }

        SIZE_MAP = {
          TYPE_VOIDP => SIZEOF_VOIDP,
          TYPE_CHAR  => SIZEOF_CHAR,
          TYPE_SHORT => SIZEOF_SHORT,
          TYPE_INT  => SIZEOF_INT,
          TYPE_LONG  => SIZEOF_LONG,
          TYPE_LONG_LONG => SIZEOF_LONG_LONG,
          TYPE_FLOAT => SIZEOF_FLOAT,
          TYPE_DOUBLE => SIZEOF_DOUBLE,
        }
    else
        ALIGN_MAP = {
          TYPE_VOIDP => ALIGN_VOIDP,
          TYPE_CHAR  => ALIGN_VOIDP,
          TYPE_SHORT => ALIGN_VOIDP,
          TYPE_INT  => ALIGN_VOIDP,
          TYPE_LONG  => ALIGN_VOIDP,
          TYPE_FLOAT => ALIGN_FLOAT,
          TYPE_DOUBLE => ALIGN_DOUBLE,
        }

        PACK_MAP = {
          TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
          TYPE_CHAR  => "c",
          TYPE_SHORT => "s!",
          TYPE_INT  => "i!",
          TYPE_LONG  => "l!",
          TYPE_FLOAT => "f",
          TYPE_DOUBLE => "d",
        }

        SIZE_MAP = {
          TYPE_VOIDP => SIZEOF_VOIDP,
          TYPE_CHAR  => SIZEOF_CHAR,
          TYPE_SHORT => SIZEOF_SHORT,
          TYPE_INT  => SIZEOF_INT,
          TYPE_LONG  => SIZEOF_LONG,
          TYPE_FLOAT => SIZEOF_FLOAT,
          TYPE_DOUBLE => SIZEOF_DOUBLE,
        }
    end

        def parse_types(types)
          @types = types
          @template = ""
          addr      = 0
          types.each{|t|
            addr = add_padding(addr, ALIGN_MAP[t])
            @template << PACK_MAP[t]
            addr += SIZE_MAP[t]
          }
          addr = add_padding(addr, ALIGN_MAP[SIZEOF_VOIDP])
          if( addr % SIZEOF_VOIDP == 0 )
            @size = addr / SIZEOF_VOIDP
          else
            @size = (addr / SIZEOF_VOIDP) + 1
          end
        end

        def add_padding(addr, align)
          orig_addr = addr
          addr = align(orig_addr, align)
          d = addr - orig_addr
          if( d > 0 )
            @template << "x#{d}"
          end
          addr
        end
      end
    end
    #require 'dl'

    module DL
      module ValueUtil
        def unsigned_value(val, ty)
          case ty.abs
          when TYPE_CHAR
            [val].pack("c").unpack("C")[0]
          when TYPE_SHORT
            [val].pack("s!").unpack("S!")[0]
          when TYPE_INT
            [val].pack("i!").unpack("I!")[0]
          when TYPE_LONG
            [val].pack("l!").unpack("L!")[0]
          when TYPE_LONG_LONG
            [val].pack("q!").unpack("Q!")[0]
          else
            val
          end
        end

        def signed_value(val, ty)
          case ty.abs
          when TYPE_CHAR
            [val].pack("C").unpack("c")[0]
          when TYPE_SHORT
            [val].pack("S!").unpack("s!")[0]
          when TYPE_INT
            [val].pack("I!").unpack("i!")[0]
          when TYPE_LONG
            [val].pack("L!").unpack("l!")[0]
          when TYPE_LONG_LONG
            [val].pack("Q!").unpack("q!")[0]
          else
            val
          end
        end

        def wrap_args(args, tys, funcs, &block)
          result = []
          tys ||= []
          args.each_with_index{|arg, idx|
            result.push(wrap_arg(arg, tys[idx], funcs, &block))
          }
          result
        end

        def wrap_arg(arg, ty, funcs, &block)
            funcs ||= []
            case arg
            when nil
              return 0
            when CPtr
              return arg.to_i
            when IO
              case ty
              when TYPE_VOIDP
                return CPtr[arg].to_i
              else
                return arg.to_i
              end
            when Function
              if( block )
                arg.bind_at_call(&block)
                funcs.push(arg)
              elsif !arg.bound?
                raise(RuntimeError, "block must be given.")
              end
              return arg.to_i
            when String
              if( ty.is_a?(Array) )
                return arg.unpack('C*')
              else
                case SIZEOF_VOIDP
                when SIZEOF_LONG
                  return [arg].pack("p").unpack("l!")[0]
                when SIZEOF_LONG_LONG
                  return [arg].pack("p").unpack("q")[0]
                else
                  raise(RuntimeError, "sizeof(void*)?")
                end
              end
            when Float, Integer
              return arg
            when Array
              if( ty.is_a?(Array) ) # used only by struct
                case ty[0]
                when TYPE_VOIDP
                  return arg.collect{|v| Integer(v)}
                when TYPE_CHAR
                  if( arg.is_a?(String) )
                    return val.unpack('C*')
                  end
                end
                return arg
              else
                return arg
              end
            else
              if( arg.respond_to?(:to_ptr) )
                return arg.to_ptr.to_i
              else
                begin
                  return Integer(arg)
                rescue
                  raise(ArgumentError, "unknown argument type: #{arg.class}")
                end
              end
            end
        end
      end
    end
    #require 'dl'
    #require 'dl/pack.rb'

    module DL
      class CStruct
        def CStruct.entity_class()
          CStructEntity
        end
      end

      class CUnion
        def CUnion.entity_class()
          CUnionEntity
        end
      end

      module CStructBuilder
        def create(klass, types, members)
          new_class = Class.new(klass){
            define_method(:initialize){|addr|
              @entity = klass.entity_class.new(addr, types)
              @entity.assign_names(members)
            }
            define_method(:to_ptr){ @entity }
            define_method(:to_i){ @entity.to_i }
            members.each{|name|
              define_method(name){ @entity[name] }
              define_method(name + "="){|val| @entity[name] = val }
            }
          }
          size = klass.entity_class.size(types)
          new_class.module_eval(<<-EOS)
            def new_class.size()
              #{size}
            end
            def new_class.malloc()
              addr = DL.malloc(#{size})
              new(addr)
            end
          EOS
          return new_class
        end
        module_function :create
      end
     
      class CStructEntity < CPtr
        include PackInfo
        include ValueUtil

        def CStructEntity.malloc(types, func = nil)
          addr = DL.malloc(CStructEntity.size(types))
          CStructEntity.new(addr, types, func)
        end

        def CStructEntity.size(types)
          offset = 0
          max_align = 0
          types.each_with_index{|t,i|
            orig_offset = offset
            if( t.is_a?(Array) )
              align = PackInfo::ALIGN_MAP[t[0]]
              offset = PackInfo.align(orig_offset, align)
              size = offset - orig_offset
              offset += (PackInfo::SIZE_MAP[t[0]] * t[1])
            else
              align = PackInfo::ALIGN_MAP[t]
              offset = PackInfo.align(orig_offset, align)
              size = offset - orig_offset
              offset += PackInfo::SIZE_MAP[t]
            end
            if (max_align < align)
              max_align = align
            end
          }
          offset = PackInfo.align(offset, max_align)
          offset
        end

        def initialize(addr, types, func = nil)
          set_ctypes(types)
          super(addr, @size, func)
        end

        def assign_names(members)
          @members = members
        end

        def set_ctypes(types)
          @ctypes = types
          @offset = []
          offset = 0
          max_align = 0
          types.each_with_index{|t,i|
            orig_offset = offset
            if( t.is_a?(Array) )
              align = ALIGN_MAP[t[0]]
            else
              align = ALIGN_MAP[t]
            end
            offset = PackInfo.align(orig_offset, align)
            size = offset - orig_offset
            @offset[i] = offset
            if( t.is_a?(Array) )
              offset += (SIZE_MAP[t[0]] * t[1])
            else
              offset += SIZE_MAP[t]
            end
            if (max_align < align)
              max_align = align
            end
          }
          offset = PackInfo.align(offset, max_align)
          @size = offset
        end

        def [](name)
          idx = @members.index(name)
          if( idx.nil? )
            raise(ArgumentError, "no such member: #{name}")
          end
          ty = @ctypes[idx]
          if( ty.is_a?(Array) )
            r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
          else
            r = super(@offset[idx], SIZE_MAP[ty.abs])
          end
          packer = Packer.new([ty])
          val = packer.unpack([r])
          case ty
          when Array
            case ty[0]
            when TYPE_VOIDP
              val = val.collect{|v| CPtr.new(v)}
            end
          when TYPE_VOIDP
            val = CPtr.new(val[0])
          else
            val = val[0]
          end
          if( ty.is_a?(Integer) && (ty < 0) )
            return unsigned_value(val, ty)
          elsif( ty.is_a?(Array) && (ty[0] < 0) )
            return val.collect{|v| unsigned_value(v,ty[0])}
          else
            return val
          end
        end

        def []=(name, val)
          idx = @members.index(name)
          if( idx.nil? )
            raise(ArgumentError, "no such member: #{name}")
          end
          ty  = @ctypes[idx]
          packer = Packer.new([ty])
          val = wrap_arg(val, ty, [])
          buff = packer.pack([val].flatten())
          super(@offset[idx], buff.size, buff)
          if( ty.is_a?(Integer) && (ty < 0) )
            return unsigned_value(val, ty)
          elsif( ty.is_a?(Array) && (ty[0] < 0) )
            return val.collect{|v| unsigned_value(v,ty[0])}
          else
            return val
          end
        end

        def to_s()
          super(@size)
        end
      end

      class CUnionEntity < CStructEntity
        include PackInfo

        def CUnionEntity.malloc(types, func=nil)
          addr = DL.malloc(CUnionEntity.size(types))
          CUnionEntity.new(addr, types, func)
        end

        def CUnionEntity.size(types)
          size  = 0
          types.each_with_index{|t,i|
            if( t.is_a?(Array) )
              tsize = PackInfo::SIZE_MAP[t[0]] * t[1]
            else
              tsize = PackInfo::SIZE_MAP[t]
            end
            if( tsize > size )
              size = tsize
            end
          }
        end

        def set_ctypes(types)
          @ctypes = types
          @offset = []
          @size  = 0
          types.each_with_index{|t,i|
            @offset[i] = 0
            if( t.is_a?(Array) )
              size = SIZE_MAP[t[0]] * t[1]
            else
              size = SIZE_MAP[t]
            end
            if( size > @size )
              @size = size
            end
          }
        end
      end
    end

    module DL
      module Win32Types
        def included(m)
          m.module_eval{
            typealias "DWORD", "unsigned long"
            typealias "PDWORD", "unsigned long *"
            typealias "WORD", "unsigned short"
            typealias "PWORD", "unsigned short *"
            typealias "BOOL", "int"
            typealias "ATOM", "int"
            typealias "BYTE", "unsigned char"
            typealias "PBYTE", "unsigned char *"
            typealias "UINT", "unsigned int"
            typealias "ULONG", "unsigned long"
            typealias "UCHAR", "unsigned char"
            typealias "HANDLE", "unsigned long"
            typealias "PHANDLE", "void*"
            typealias "PVOID", "void*"
            typealias "LPCSTR", "char*"
            typealias "LPSTR", "char*"
            typealias "HINSTANCE", "unsigned int"
            typealias "HDC", "unsigned int"
            typealias "HWND", "unsigned int"
          }
        end
        module_function :included
      end

      module BasicTypes
        def included(m)
          m.module_eval{
            typealias "uint", "unsigned int"
            typealias "u_int", "unsigned int"
            typealias "ulong", "unsigned long"
            typealias "u_long", "unsigned long"
          }
        end
        module_function :included
      end
    end
    #require 'dl'
    #require 'dl/callback'
    #require 'dl/stack'
    #require 'dl/value'
    #require 'thread'

    module DL
      class Function
        include DL
        include ValueUtil

        def initialize(cfunc, argtypes, &proc)
          @cfunc = cfunc
          @stack = Stack.new(argtypes.collect{|ty| ty.abs})
          if( @cfunc.ctype < 0 )
            @cfunc.ctype = @cfunc.ctype.abs
            @unsigned = true
          end
          if( proc )
            bind(&proc)
          end
        end

        def to_i()
          @cfunc.to_i
        end

        def check_safe_obj(val)
          if $SAFE > 0 and val.tainted?
            raise SecurityError, 'Insecure operation'
          end
        end

        def call(*args, &block)
          funcs = []
          args.each{|e| check_safe_obj(e) }
          check_safe_obj(block)
          args = wrap_args(args, @stack.types, funcs, &block)
          r = @cfunc.call(@stack.pack(args))
          funcs.each{|f| f.unbind_at_call()}
          return wrap_result(r)
        end

        def wrap_result(r)
          case @cfunc.ctype
          when TYPE_VOIDP
            r = CPtr.new(r)
          else
            if( @unsigned )
              r = unsigned_value(r, @cfunc.ctype)
            end
          end
          r
        end

        def bind(&block)
          if( !block )
            raise(RuntimeError, "block must be given.")
          end
          if( @cfunc.ptr == 0 )
            cb = Proc.new{|*args|
              ary = @stack.unpack(args)
              @stack.types.each_with_index{|ty, idx|
                case ty
                when TYPE_VOIDP
                  ary[idx] = CPtr.new(ary[idx])
                end
              }
              r = block.call(*ary)
              wrap_arg(r, @cfunc.ctype, [])
            }
            case @cfunc.calltype
            when :cdecl
              @cfunc.ptr = set_cdecl_callback(@cfunc.ctype, @stack.size, &cb)
            when :stdcall
              @cfunc.ptr = set_stdcall_callback(@cfunc.ctype, @stack.size, &cb)
            else
              raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
            end
            if( @cfunc.ptr == 0 )
              raise(RuntimeException, "can't bind C function.")
            end
          end
        end

        def unbind()
          if( @cfunc.ptr != 0 )
            case @cfunc.calltype
            when :cdecl
              remove_cdecl_callback(@cfunc.ptr, @cfunc.ctype)
            when :stdcall
              remove_stdcall_callback(@cfunc.ptr, @cfunc.ctype)
            else
              raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
            end
            @cfunc.ptr = 0
          end
        end

        def bound?()
          @cfunc.ptr != 0
        end

        def bind_at_call(&block)
          bind(&block)
        end

        def unbind_at_call()
        end
      end

      class TempFunction < Function
        def bind_at_call(&block)
          bind(&block)
        end

        def unbind_at_call()
          unbind()
        end
      end

      class CarriedFunction < Function
        def initialize(cfunc, argtypes, n)
          super(cfunc, argtypes)
          @carrier = []
          @index = n
          @mutex = Mutex.new
        end

        def create_carrier(data)
          ary = []
          userdata = [ary, data]
          @mutex.lock()
          @carrier.push(userdata)
          return dlwrap(userdata)
        end

        def bind_at_call(&block)
          userdata = @carrier[-1]
          userdata[0].push(block)
          bind{|*args|
            ptr = args[@index]
            if( !ptr )
              raise(RuntimeError, "The index of userdata should be lower than #{args.size}.")
            end
            userdata = dlunwrap(Integer(ptr))
            args[@index] = userdata[1]
            userdata[0][0].call(*args)
          }
          @mutex.unlock()
        end
      end
    end
    #require 'dl'
    #require 'dl/func.rb'
    #require 'dl/struct.rb'
    #require 'dl/cparser.rb'

    module DL
      class CompositeHandler
        def initialize(handlers)
          @handlers = handlers
        end

        def handlers()
          @handlers
        end

        def sym(symbol)
          @handlers.each{|handle|
            if( handle )
              begin
                addr = handle.sym(symbol)
                return addr
              rescue DLError
              end
            end
          }
          return nil
        end

        def [](symbol)
          sym(symbol)
        end
      end

      module Importer
        include DL
        include CParser
        extend Importer

        def dlload(*libs)
          handles = libs.collect{|lib|
            case lib
            when nil
              nil
            when Handle
              lib
            when Importer
              lib.handlers
            else
              begin
                DL.dlopen(lib)
              rescue DLError
                raise(DLError, "can't load #{lib}")
              end
            end
          }.flatten()
          @handler = CompositeHandler.new(handles)
          @func_map = {}
          @type_alias = {}
        end

        def typealias(alias_type, orig_type)
          @type_alias[alias_type] = orig_type
        end

        def sizeof(ty)
          case ty
          when String
            ty = parse_ctype(ty, @type_alias).abs()
            case ty
            when TYPE_CHAR
              return SIZEOF_CHAR
            when TYPE_SHORT
              return SIZEOF_SHORT
            when TYPE_INT
              return SIZEOF_INT
            when TYPE_LONG
              return SIZEOF_LONG
            when TYPE_LONG_LONG
              return SIZEOF_LONG_LON
            when TYPE_FLOAT
              return SIZEOF_FLOAT
            when TYPE_DOUBLE
              return SIZEOF_DOUBLE
            when TYPE_VOIDP
              return SIZEOF_VOIDP
            else
              raise(DLError, "unknown type: #{ty}")
            end
          when Class
            if( ty.instance_methods().include?(:to_ptr) )
              return ty.size()
            end
          end
          return CPtr[ty].size()
        end

        def parse_bind_options(opts)
          h = {}
          prekey = nil
          while( opt = opts.shift() )
            case opt
            when :stdcall, :cdecl
              h[:call_type] = opt
            when :carried, :temp, :temporal, :bind
              h[:callback_type] = opt
              h[:carrier] = opts.shift()
            else
              h[opt] = true
            end
          end
          h
        end
        private :parse_bind_options

        def extern(signature, *opts)
          symname, ctype, argtype = parse_signature(signature, @type_alias)
          opt = parse_bind_options(opts)
          f = import_function(symname, ctype, argtype, opt[:call_type])
          name = symname.gsub(/@.+/,'')
          @func_map[name] = f
          # define_method(name){|*args,&block| f.call(*args,&block)}
          module_eval(<<-EOS)
            def #{name}(*args, &block)
              @func_map['#{name}'].call(*args,&block)
            end
          EOS
          module_function(name)
          f
        end

        def bind(signature, *opts, &blk)
          name, ctype, argtype = parse_signature(signature, @type_alias)
          h = parse_bind_options(opts)
          case h[:callback_type]
          when :bind, nil
            f = bind_function(name, ctype, argtype, h[:call_type], &blk)
          when :temp, :temporal
            f = create_temp_function(name, ctype, argtype, h[:call_type])
          when :carried
            f = create_carried_function(name, ctype, argtype, h[:call_type], h[:carrier])
          else
            raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
          end
          @func_map[name] = f
          #define_method(name){|*args,&block| f.call(*args,&block)}
          module_eval(<<-EOS)
            def #{name}(*args,&block)
              @func_map['#{name}'].call(*args,&block)
            end
          EOS
          module_function(name)
          f
        end

        def struct(signature)
          tys, mems = parse_struct_signature(signature, @type_alias)
          DL::CStructBuilder.create(CStruct, tys, mems)
        end

        def union(signature)
          tys, mems = parse_struct_signature(signature, @type_alias)
          DL::CStructBuilder.create(CUnion, tys, mems)
        end

        def [](name)
          @func_map[name]
        end

        def create_value(ty, val=nil)
          s = struct([ty + " value"])
          ptr = s.malloc()
          if( val )
            ptr.value = val
          end
          return ptr
        end
        alias value create_value

        def import_value(ty, addr)
          s = struct([ty + " value"])
          ptr = s.new(addr)
          return ptr
        end

        def import_symbol(name)
          addr = @handler.sym(name)
          if( !addr )
            raise(DLError, "cannot find the symbol: #{name}")
          end
          CPtr.new(addr)
        end

        def import_function(name, ctype, argtype, call_type = nil)
          addr = @handler.sym(name)
          if( !addr )
            raise(DLError, "cannot find the function: #{name}()")
          end
          Function.new(CFunc.new(addr, ctype, name, call_type || :cdecl), argtype)
        end

        def bind_function(name, ctype, argtype, call_type = nil, &block)
          f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
          f.bind(&block)
          f
        end

        def create_temp_function(name, ctype, argtype, call_type = nil)
          TempFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
        end

        def create_carried_function(name, ctype, argtype, call_type = nil, n = 0)
          CarriedFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype, n)
        end
      end
    end


    Nessa grande código há 10 scripts diferentes, o thread.rb foi criado por Yukihiro Matsumoto (criador do Ruby e é licenciado pela Ruby License (Compatível com GPL))
    Os outros não possuem header com os autores, apenas tem algumas RCS IDs com nomes que prefiro não citar aqui, mas de qualquer mode estão sob a Ruby License do mesmo modo.


    E por fim, as funções de socket:
    Código:

    #--------------------
    #require "dl"
    #require "dl/import"
    #require "dl/struct"
    #--------------------
    # Created by Cidiomar
    #--------------------
    module DL::Importer
      #----------
      def typedef(string)
        args = string.split(' ')
        alias_type = args.pop
        typealias(alias_type, args.join(' '))
      end
      #-----
      module_function :typedef
      #----------
    end
    #---------------
    module CIDI_DK
      #---------------
      Timeval = DL::Importer.struct [
        "long tv_sec",
        "long tv_usec",
      ]
      #---------------
      module Winsock2
        #----------
        extend DL::Importer
        #----------
        dlload 'ws2_32.dll'
        #----------
        SOCK_STREAM  = 1
        AF_INET      = 2
        IPPROTO_TCP  = 6
        INADDR_NONE     = 0xffffffff
        #----------
        typedef 'unsigned char   u_char'
        typedef 'unsigned short   u_short'
        typedef 'unsigned int     u_int'
        typedef 'unsigned long   u_long'
        #-----
        typedef 'u_int           SOCKET'
        #----------
        Fd_set = struct [
          'u_int  fd_count',
          'SOCKET  fd_array[2]'
        ]
        #----------
        Fd_set1 = struct [
          'u_int  fd_count',
          'SOCKET  fd_array'
        ]
        #----------
        Sockaddr = struct [
          'u_short sa_family',
          'char     sa_data[14]'
        ]
        #----------
        Sockaddr2 = struct [
          'u_short sa_family',
          'u_short s_port',
          'u_long  s_host',
          'char     sa_data[8]'
        ]
        #----------
        Hostent = struct [
          'char     *  h_name',
          'char     **  h_aliases',
          'short       h_addrtype',
          'short      h_length',
          'char     **  h_addr_list',
        ]
        #----------
        extern 'int closesocket(SOCKET)'
        extern 'int connect(SOCKET,const struct sockaddr*,int)'
        extern 'hostent *  gethostbyname(const char*)'
        extern 'int recv(SOCKET,char*,int,int)'
        extern 'int send(SOCKET,const char*,int,int)'
        extern 'SOCKET socket(int,int,int)'
        extern 'int select(int,fd_set*,fd_set*,fd_set*,const struct timeval*)'
        extern 'int WSAGetLastError()'
        #----------
      end
      #---------------
      class TCPSocket
        #----------
        attr_reader :host, :port
        #----------
        def initialize(host, port)
          @host, @port      = host, port
          @recv_back_buffer = ""
          connect
        end
        #----------
        def connect
          #-----
          @sock_io_id = Winsock2.socket(Winsock2::AF_INET, Winsock2::SOCK_STREAM, Winsock2::IPPROTO_TCP)
          #-----
          unless (_host = Winsock2.gethostbyname(@host)).null?
            hostent    = Winsock2::Hostent.new(Winsock2.gethostbyname(@host))
          else
            SocketError.raise_no_assoc_host
          end
          #-----
          zeros = i = 0
          ip_addr = []
          loop do
            now = hostent.h_addr_list[i]
            if zeros == 5
              now += 256 if now < 0
              ip_addr << now
              break if ip_addr.size == 4
            elsif now == 0
              zeros += 1
            else
              zeros = 0
            end
            i += 1
          end
          #-----
          sock_addr          = Winsock2::Sockaddr2.malloc
          sock_addr.sa_family = Winsock2::AF_INET
          sock_addr.s_port    = [@port].pack("n").unpack("S")[0]
          sock_addr.s_host    = ip_addr.pack("C4").unpack("L")[0]
          #-----
          if Winsock2.connect(@sock_io_id, sock_addr, Winsock2::Sockaddr2.size) == -1 or sock_addr.s_host == 0
            SocketError.raise
          end
          #-----
          nil
        end
        #----------
        def close
          SocketError.raise if Winsock2.closesocket(@sock_io_id) == -1
          nil
        end
        #----------
        def recv(len)
          if @recv_back_buffer.size != 0
            if @recv_back_buffer.size > len
              buffer = @recv_back_buffer[0 ... len]
              @recv_back_buffer[0 ... len] = ''
            elsif @recv_back_buffer.size == len
              buffer = @recv_back_buffer
              @recv_back_buffer = ""
            else
              len -= @recv_back_buffer.size
              buffer    = "\0" * len
              SocketError.raise if (recv_size = Winsock2.recv(@sock_io_id, buffer, len, 0)) == -1
              buffer = @recv_back_buffer + buffer[0 ... recv_size]
              @recv_back_buffer = ""
            end
          else
            buffer    = "\0" * len
            SocketError.raise if (recv_size = Winsock2.recv(@sock_io_id, buffer, len, 0)) == -1
            buffer = buffer[0 ... recv_size]
          end
          return buffer
        end
        #----------
        def gets(end_sequence = "\n")
          end_sequence_size = end_sequence.size
          return nil if end_sequence_size == 0
          ret_buffer = ""
          buffer    = "\0"
          result    = -1
          #-----
          while not ret_buffer[ret_buffer.size - end_sequence_size ... ret_buffer.size] == end_sequence
            if @recv_back_buffer.size != 0
              buffer = @recv_back_buffer[0]
              @recv_back_buffer[0] = ''
            else
              SocketError.raise if (result = Winsock2.recv(@sock_io_id, buffer, 1, 0)) == -1
            end
            ret_buffer << buffer unless result == 0
          end
          #-----
          return ret_buffer
        end
        #----------
        def send(*args)
          string = args.join
          SocketError.raise if Winsock2.send(@sock_io_id, string, string.size, 0) == -1
          string
        end
        #----------
        def eof?
          #-----
          timeval = Timeval.malloc
          timeval.tv_sec  = 0
          timeval.tv_usec = 0
          #-----
          readfds          = Winsock2::Fd_set1.malloc
          readfds.fd_count  = 1
          readfds.fd_array  = @sock_io_id
          #-----
          result = Winsock2.select(2, readfds, 0, 0, timeval)
          #-----
          if result == 1
            buffer = "\0"
            if Winsock2.recv(@sock_io_id, buffer, 1, 0) == 0
              result = 0
            else
              @recv_back_buffer << buffer
            end
          end
          #-----
          SocketError.raise if result == -1
          return !(result > 0)
        end
        #----------
        protected :connect
        #----------
      end
      #---------------
      class SocketError < StandardError
        #----------
        ENOASSOCHOST = 'getaddrinfo: no address associated with hostname.'
        #----------
        def self.raise(errno = Winsock2.WSAGetLastError)
          _caller = caller()
          _caller.pop
          Kernel.raise Errno.const_get(Errno.constants.detect { |c| Errno.const_get(c).new.errno == errno }), '', _caller
        end
        #----------
        def self.raise_no_assoc_host
          _caller = caller()
          _caller.pop
          Kernel.raise 'getaddrinfo: no address associated with hostname.', '', _caller
        end
        #----------
      end
    end
    #--------------------
    TCPSocket = CIDI_DK::TCPSocket






    Pergunta: Por que não usar Win32API ao invés de dl?o código ficaria 36.5KB mais leve!
    Resposta: Prefiro usar dl, Win32API não deve mais ser usada, esta em ativa apenas por compatibilidade, será removida do Ruby em breve.
    avatar
    Komuro Takashi
    Moderador Local
    Moderador Local

    Mensagens : 1049
    Créditos : 131

    Re: Workarround pra classe TCPSocket

    Mensagem por Komuro Takashi em Sex Fev 15, 2013 10:57 pm

    Sei que tópico é antigo mais não poderia deixar de agradecer...eu estava desesperado por isso e estava aqui á mais de 1 ano e eu não havia visto....já consegui conectar com os server de NP existentes, o seu em Ruby o em Java o do Master para RMXP e RMVX o script é totalmente funcional, só que peguei ele de outro site e lá vc falou que era nescessário inportar as funcões em .rb e foi o que fiz direcionei para minha lib dl e deu certo.....Obrigado novamente.

    Atenciosamente : KOmuro Takashi


    _________________

      Data/hora atual: Ter Maio 22, 2018 2:45 pm