# $Id: serialize_for_php.rb 876 2007-01-25 07:15:51Z j $

class Fixnum
  def serialize_for_php
    "i:#{self};"
  end
end

class Bignum
  def serialize_for_php
    raise "Overflow" unless self.between?(-0x80000000, 0x7fffffff)
    "i:#{self};"
  end
end

class Float
  def serialize_for_php
    "d:#{self};"
  end
end

class NilClass
  def serialize_for_php
    "N;"
  end
end

class FalseClass
  def serialize_for_php
    "b:0;"
  end
end

class TrueClass
  def serialize_for_php
    "b:1;"
  end
end

class String
  def serialize_for_php
    "s:#{self.size}:\"#{self}\";"
  end
end

class Symbol
  def serialize_for_php
    str = self.to_s
    "s:#{str.size}:\"#{str}\";"
  end
end

class Array
  def serialize_for_php
    serialized = "a:#{self.size}:{"
    self.each_with_index do |e, i|
      serialized += "#{i.serialize_for_php}#{e.serialize_for_php}"
    end
    serialized + "}"
  end
end

class Hash
  def serialize_for_php
    serialized = "a:#{self.size}:{"
    self.each_pair do |k, e|
      serialized += "#{k.serialize_for_php}#{e.serialize_for_php}"
    end
    serialized + "}"
  end
end

class String
  require "strscan"
  
  def unserialize_from_php(params = {})
    return self.do_unserialize_from_php(params)[0]
  end
  
  protected
  def do_unserialize_from_php(params)
    symbols = params[:symbols].nil? ? true : params[:symbols]
    s = StringScanner.new(self)
    s.scan(/(\w):(\d+)/m)
    case s[1]
    when "a"
      nb = s[2].to_i
      s.scan(/:\{/m)
      ret = { }
      nb.times do
        key, len = s.rest.do_unserialize_from_php(params)
        s.pos += len
        value, len = s.rest.do_unserialize_from_php(params)
        s.pos += len
        key = key.to_sym if symbols && key.is_a?(String)
        ret[key] = value
      end
      s.scan(/\}/m)
    when "i"
      ret = s[2].to_i
      s.scan(/;/m)
    when "b"
      ret = s[2] == "1" ? true : false
      s.scan(/;/m)
    when "s"
      len = s[2].to_s
      s.scan(/:"(.{#{len}})";/m)
      ret = s[1]
    else
      raise "Unable to unserialize: [#{s[1]}]"
    end
    [ ret, s.pos ]
  end
end
