1 # depends on: module.rb class.rb
4 def to_marshal(ms, strip_ivars = false)
5 out = ms.serialize_extended_object self
6 out << Marshal::TYPE_OBJECT
7 out << ms.serialize(self.class.name.to_sym)
8 out << ms.serialize_instance_variables_suffix(self, true, strip_ivars)
38 raise TypeError, "can't dump anonymous class #{self}" if self.name == ''
39 Marshal::TYPE_CLASS + ms.serialize_integer(name.length) + name
45 raise TypeError, "can't dump anonymous module #{self}" if self.name == ''
46 Marshal::TYPE_MODULE + ms.serialize_integer(name.length) + name
52 if idx = ms.find_symlink(self) then
53 Marshal::TYPE_SYMLINK + ms.serialize_integer(idx)
58 Marshal::TYPE_SYMBOL + ms.serialize_integer(str.length) + str
65 out = ms.serialize_instance_variables_prefix(self)
66 out << ms.serialize_extended_object(self)
67 out << ms.serialize_user_class(self, String)
68 out << Marshal::TYPE_STRING
69 out << ms.serialize_integer(self.length) << self
70 out << ms.serialize_instance_variables_suffix(self)
76 Marshal::TYPE_FIXNUM + ms.serialize_integer(self)
82 str = Marshal::TYPE_BIGNUM + (self < 0 ? '-' : '+')
87 str << ms.to_byte(num)
97 str[0..1] + ms.serialize_integer(cnt / 2) + str[2..-1]
104 out = ms.serialize_instance_variables_prefix(self)
105 out << ms.serialize_extended_object(self)
106 out << ms.serialize_user_class(self, Regexp)
107 out << Marshal::TYPE_REGEXP
108 out << ms.serialize_integer(str.length) + str
109 out << ms.to_byte(options & 0x7)
110 out << ms.serialize_instance_variables_suffix(self)
116 out = ms.serialize_instance_variables_prefix(self)
117 out << ms.serialize_extended_object(self)
119 out << Marshal::TYPE_STRUCT
121 out << ms.serialize(self.class.name.to_sym)
122 out << ms.serialize_integer(self.length)
124 self.each_pair do |name, value|
125 out << ms.serialize(name)
126 out << ms.serialize(value)
129 out << ms.serialize_instance_variables_suffix(self)
136 out = ms.serialize_instance_variables_prefix(self)
137 out << ms.serialize_extended_object(self)
138 out << ms.serialize_user_class(self, Array)
139 out << Marshal::TYPE_ARRAY
140 out << ms.serialize_integer(self.length)
143 out << ms.serialize(element)
146 out << ms.serialize_instance_variables_suffix(self)
152 raise TypeError, "can't dump hash with default proc" if default_proc
153 out = ms.serialize_instance_variables_prefix(self)
154 out << ms.serialize_extended_object(self)
155 out << ms.serialize_user_class(self, Hash)
156 out << (self.default ? Marshal::TYPE_HASH_DEF : Marshal::TYPE_HASH)
157 out << ms.serialize_integer(length)
159 each_pair do |(key, val)|
160 out << ms.serialize(key)
161 out << ms.serialize(val)
164 out << (default ? ms.serialize(default) : '')
165 out << ms.serialize_instance_variables_suffix(self)
174 (1.0 / self) < 0 ? '-0' : '0'
176 self < 0 ? "-inf" : "inf"
178 "%.*g" % [17, self] + ms.serialize_float_thing(self)
180 Marshal::TYPE_FLOAT + ms.serialize_integer(str.length) + str
189 VERSION_STRING = "\x04\x08"
199 TYPE_DATA = 'd' # no specs
201 TYPE_USRMARSHAL = 'U'
210 TYPE_MODULE_OLD = 'M' # no specs
222 def initialize(stream, depth, proc)
245 return if obj.kind_of?(ImmediateValue)
248 @links[obj.object_id] = sz
254 @symlinks[obj.object_id] = sz
258 @proc.call obj if @proc and @call
261 def construct(ivar_index = nil, call_proc = true)
270 when TYPE_CLASS, TYPE_MODULE
271 name = construct_symbol
272 obj = Object.const_lookup name
274 store_unique_object obj
291 when TYPE_HASH, TYPE_HASH_DEF
298 construct_user_defined ivar_index
300 construct_user_marshal
302 num = construct_integer
305 raise ArgumentError, "dump format error (unlinked)" if obj.nil?
309 num = construct_integer
312 raise ArgumentError, "bad symbol" if sym.nil?
319 @modules << Object.const_lookup(name)
321 obj = construct nil, false
333 ivar_index = @has_ivar.length
336 obj = construct ivar_index, false
338 set_instance_variables obj if @has_ivar.pop
342 raise ArgumentError, "load error, unknown type #{type}"
345 call obj if call_proc
351 obj = @user_class ? get_user_class.new : []
352 store_unique_object obj
354 construct_integer.times do
362 sign = consume == '-' ? -1 : 1
363 size = construct_integer * 2
368 (0...size).each do |exp|
369 result += (data[exp] * 2**(exp*8))
374 store_unique_object obj
378 s = get_byte_sequence
390 store_unique_object obj
395 def construct_hash(type)
396 obj = @user_class ? get_user_class.new : {}
397 store_unique_object obj
399 construct_integer.times do
405 obj.default = construct if type == TYPE_HASH_DEF
410 def construct_integer
413 if (n > 0 and n < 5) or n > 251
414 size, signed = n > 251 ? [256 - n, 2**((256 - n)*8)] : [n, 0]
419 (0...size).each do |exp|
420 result += (data[exp] * 2**(exp*8))
435 klass = Object.const_lookup name
438 raise TypeError, 'dump format error' unless Object === obj
440 store_unique_object obj
441 set_instance_variables obj
447 s = get_byte_sequence
449 obj = get_user_class.new s, consume[0]
451 obj = Regexp.new s, consume[0]
454 store_unique_object obj
458 obj = get_byte_sequence
459 obj = get_user_class.new obj if @user_class
461 store_unique_object obj
469 store_unique_object name
471 klass = Object.const_lookup name
472 members = klass.members
475 store_unique_object obj
477 construct_integer.times do |i|
479 unless members[i].intern == slot then
480 raise TypeError, "struct %s is not compatible (%p for %p)" %
481 [klass, slot, members[i]]
484 obj.instance_variable_set "@#{slot}", construct
491 obj = get_byte_sequence.to_sym
492 store_unique_object obj
497 def construct_user_defined(ivar_index)
499 klass = Module.const_lookup name
501 data = get_byte_sequence
503 if ivar_index and @has_ivar[ivar_index] then
504 set_instance_variables data
505 @has_ivar[ivar_index] = false
508 obj = klass._load data
510 store_unique_object obj
515 def construct_user_marshal
517 store_unique_object name
519 klass = Module.const_lookup name
522 extend_object obj if @modules
524 unless obj.respond_to? :marshal_load then
525 raise TypeError, "instance of #{klass} needs to have method `marshal_load'"
528 store_unique_object obj
531 obj.marshal_load data
536 def consume(bytes = 1)
537 data = @stream[@consumed, bytes]
542 def extend_object(obj)
543 obj.extend(@modules.pop) until @modules.empty?
547 @links[obj.object_id]
550 def find_symlink(obj)
551 @symlinks[obj.object_id]
555 ptr = MemoryPointer.new :int
556 return Platform::Float.frexp(flt, ptr)
561 def get_byte_sequence
562 size = construct_integer
566 def get_module_names(obj)
568 sup = obj.metaclass.superclass
570 while sup and [Module, IncludedModule].include? sup.class do
579 cls = Module.const_lookup @user_class
588 when TYPE_SYMBOL then
590 obj = construct_symbol
593 when TYPE_SYMLINK then
594 num = construct_integer
597 raise ArgumentError, "expected TYPE_SYMBOL or TYPE_SYMLINK, got #{type.inspect}"
602 Platform::Float.ldexp flt, exp
606 ptr = MemoryPointer.new :double
608 flt = Platform::Float.modf flt, ptr
616 def prepare_ivar(ivar)
617 ivar.to_s =~ /\A@/ ? ivar : "@#{ivar}".to_sym
621 raise ArgumentError, "exceed depth limit" if @depth == 0
623 # How much depth we have left.
626 if link = find_link(obj)
627 str = TYPE_LINK + serialize_integer(link)
631 if obj.respond_to? :_dump then
632 str = serialize_user_defined obj
633 elsif obj.respond_to? :marshal_dump then
634 str = serialize_user_marshal obj
636 str = obj.to_marshal self
645 def serialize_extended_object(obj)
647 get_module_names(obj).each do |mod_name|
648 str << TYPE_EXTENDED + serialize(mod_name.to_sym)
653 def serialize_float_thing(flt)
655 (flt, ) = modf(ldexp(frexp(flt.abs), 37));
656 str << "\0" if flt > 0
658 (flt, n) = modf(ldexp(flt, 32))
660 str << to_byte(n >> 24)
661 str << to_byte(n >> 16)
662 str << to_byte(n >> 8)
665 str.chomp!("\0") while str[-1] == 0
669 def serialize_instance_variables_prefix(obj)
670 if obj.instance_variables.length > 0
677 def serialize_instance_variables_suffix(obj, force = false, strip_ivars = false)
678 if force or obj.instance_variables.length > 0
679 str = serialize_integer(obj.instance_variables.length)
680 obj.instance_variables.each do |ivar|
682 val = obj.instance_variable_get(sym)
683 unless strip_ivars then
684 str << serialize(sym)
686 str << serialize(ivar[1..-1].to_sym)
688 str << serialize(val)
696 def serialize_integer(n)
699 elsif n > 0 and n < 123
701 elsif n < 0 and n > -124
702 s = to_byte(256 + (n - 5))
710 break if n == 0 or n == -1
712 s[0] = to_byte(n < 0 ? 256 - cnt : cnt)
717 def serialize_user_class(obj, cls)
719 TYPE_UCLASS + serialize(obj.class.name.to_sym)
725 def serialize_user_defined(obj)
726 str = obj._dump @depth
727 raise TypeError, "_dump() must return string" if str.class != String
728 out = serialize_instance_variables_prefix(str)
729 out << TYPE_USERDEF + serialize(obj.class.name.to_sym)
730 out << serialize_integer(str.length) + str
731 out << serialize_instance_variables_suffix(str)
734 def serialize_user_marshal(obj)
735 val = obj.marshal_dump
739 out = TYPE_USRMARSHAL + serialize(obj.class.name.to_sym)
740 out << val.to_marshal(self)
743 def set_instance_variables(obj)
744 construct_integer.times do
747 obj.instance_variable_set prepare_ivar(ivar), value
751 def store_unique_object(obj)
752 if obj.kind_of? Symbol
766 def self.dump(obj, an_io=nil, limit=nil)
768 if an_io.kind_of? Fixnum
776 depth = Type.coerce_to limit, Fixnum, :to_int
777 ms = State.new nil, depth, nil
779 if an_io and !an_io.respond_to? :write
780 raise TypeError, "output must respond to write"
783 str = VERSION_STRING + ms.serialize(obj)
793 def self.load(obj, proc = nil)
794 if obj.respond_to? :to_str
796 elsif obj.respond_to? :read
799 raise EOFError, "end of file reached"
801 elsif obj.respond_to? :getc # FIXME - don't read all of it upfront
803 data << c while (c = obj.getc.chr)
805 raise TypeError, "instance of IO needed"
811 if major != MAJOR_VERSION or minor > MINOR_VERSION then
812 raise TypeError, "incompatible marshal file format (can't be read)\n\tformat version #{MAJOR_VERSION}.#{MINOR_VERSION} required; #{major}.#{minor} given"
815 ms = State.new data, nil, proc