# frozen_string_literal: truerequire_relative"elements"moduleGemmoduleSafeMarshalclassReaderclassError<StandardErrorendclassUnsupportedVersionError<ErrorendclassUnconsumedBytesError<ErrorendclassNotImplementedError<ErrorendclassEOFError<ErrorendclassDataTooShortError<ErrorendclassNegativeLengthError<Errorenddefinitialize(io)@io=ioenddefread!read_headerroot=read_elementraiseUnconsumedBytesError,"expected EOF, got #{@io.read(10).inspect}... after top-level element #{root.class}"unless@io.eof?rootendprivateMARSHAL_VERSION=[Marshal::MAJOR_VERSION,Marshal::MINOR_VERSION].map(&:chr).join.freezeprivate_constant:MARSHAL_VERSIONdefread_headerv=@io.read(2)raiseUnsupportedVersionError,"Unsupported marshal version #{v.bytes.map(&:ord).join(".")}, expected #{Marshal::MAJOR_VERSION}.#{Marshal::MINOR_VERSION}"unlessv==MARSHAL_VERSIONenddefread_bytes(n)raiseNegativeLengthErrorifn<0str=@io.read(n)raiseEOFError,"expected #{n} bytes, got EOF"ifstr.nil?raiseDataTooShortError,"expected #{n} bytes, got #{str.inspect}"unlessstr.bytesize==nstrenddefread_byte@io.getbyte||raise(EOFError,"Unexpected EOF")enddefread_integerb=read_bytecasebwhen0x000when0x01read_bytewhen0x02read_byte|(read_byte<<8)when0x03read_byte|(read_byte<<8)|(read_byte<<16)when0x04read_byte|(read_byte<<8)|(read_byte<<16)|(read_byte<<24)when0xFCread_byte|(read_byte<<8)|(read_byte<<16)|(read_byte<<24)|-0x100000000when0xFDread_byte|(read_byte<<8)|(read_byte<<16)|-0x1000000when0xFEread_byte|(read_byte<<8)|-0x10000when0xFFread_byte|-0x100elsesigned=(b^128)-128ifb>=128signed+5elsesigned-5endendenddefread_elementtype=read_bytecasetypewhen34thenread_string# ?"when48thenread_nil# ?0when58thenread_symbol# ?:when59thenread_symbol_link# ?;when64thenread_object_link# ?@when70thenread_false# ?Fwhen73thenread_object_with_ivars# ?Iwhen84thenread_true# ?Twhen85thenread_user_marshal# ?Uwhen91thenread_array# ?[when102thenread_float# ?fwhen105thenElements::Integer.new(read_integer)# ?iwhen108thenread_bignum# ?lwhen111thenread_object# ?owhen117thenread_user_defined# ?uwhen123thenread_hash# ?{when125thenread_hash_with_default_value# ?}when101thenread_extended_object# ?ewhen99thenread_class# ?cwhen109thenread_module# ?mwhen77thenread_class_or_module# ?Mwhen100thenread_data# ?dwhen47thenread_regexp# ?/when83thenread_struct# ?Swhen67thenread_user_class# ?CelseraiseError,"Unknown marshal type discriminator #{type.chr.inspect} (#{type})"endendSTRING_E_SYMBOL=Elements::Symbol.new("E").freezeprivate_constant:STRING_E_SYMBOLdefread_symbollen=read_integeriflen==1byte=read_byteifbyte==69# ?ESTRING_E_SYMBOLelseElements::Symbol.new(byte.chr)endelsename=read_bytes(len)Elements::Symbol.new(name)endendEMPTY_STRING=Elements::String.new("".b.freeze).freezeprivate_constant:EMPTY_STRINGdefread_stringlength=read_integerreturnEMPTY_STRINGiflength==0str=read_bytes(length)Elements::String.new(str)enddefread_trueElements::True::TRUEenddefread_falseElements::False::FALSEenddefread_user_definedname=read_elementbinary_string=read_bytes(read_integer)Elements::UserDefined.new(name,binary_string)endEMPTY_ARRAY=Elements::Array.new([].freeze).freezeprivate_constant:EMPTY_ARRAYdefread_arraylength=read_integerreturnEMPTY_ARRAYiflength==0raiseNegativeLengthErroriflength<0elements=Array.new(length)doread_elementendElements::Array.new(elements)enddefread_object_with_ivarsobject=read_elementlength=read_integerraiseNegativeLengthErroriflength<0ivars=Array.new(length)do[read_element,read_element]endElements::WithIvars.new(object,ivars)enddefread_symbol_linkoffset=read_integerElements::SymbolLink.new(offset)enddefread_user_marshalname=read_elementdata=read_elementElements::UserMarshal.new(name,data)end# profiling bundle install --full-index shows that# offset 6 is by far the most common object link,# so we special case it to avoid allocating a new# object a third of the time.# the following are all the object links that# appear more than 10000 times in my profilingOBJECT_LINKS={6=>Elements::ObjectLink.new(6).freeze,30=>Elements::ObjectLink.new(30).freeze,81=>Elements::ObjectLink.new(81).freeze,34=>Elements::ObjectLink.new(34).freeze,38=>Elements::ObjectLink.new(38).freeze,50=>Elements::ObjectLink.new(50).freeze,91=>Elements::ObjectLink.new(91).freeze,42=>Elements::ObjectLink.new(42).freeze,46=>Elements::ObjectLink.new(46).freeze,150=>Elements::ObjectLink.new(150).freeze,100=>Elements::ObjectLink.new(100).freeze,104=>Elements::ObjectLink.new(104).freeze,108=>Elements::ObjectLink.new(108).freeze,242=>Elements::ObjectLink.new(242).freeze,246=>Elements::ObjectLink.new(246).freeze,139=>Elements::ObjectLink.new(139).freeze,143=>Elements::ObjectLink.new(143).freeze,114=>Elements::ObjectLink.new(114).freeze,308=>Elements::ObjectLink.new(308).freeze,200=>Elements::ObjectLink.new(200).freeze,54=>Elements::ObjectLink.new(54).freeze,62=>Elements::ObjectLink.new(62).freeze,1_286_245=>Elements::ObjectLink.new(1_286_245).freeze,}.freezeprivate_constant:OBJECT_LINKSdefread_object_linkoffset=read_integerOBJECT_LINKS[offset]||Elements::ObjectLink.new(offset)endEMPTY_HASH=Elements::Hash.new([].freeze).freezeprivate_constant:EMPTY_HASHdefread_hashlength=read_integerreturnEMPTY_HASHiflength==0pairs=Array.new(length)do[read_element,read_element]endElements::Hash.new(pairs)enddefread_hash_with_default_valuelength=read_integerraiseNegativeLengthErroriflength<0pairs=Array.new(length)do[read_element,read_element]enddefault=read_elementElements::HashWithDefaultValue.new(pairs,default)enddefread_objectname=read_elementobject=Elements::Object.new(name)length=read_integerraiseNegativeLengthErroriflength<0ivars=Array.new(length)do[read_element,read_element]endElements::WithIvars.new(object,ivars)enddefread_nilElements::Nil::NILenddefread_floatstring=read_bytes(read_integer)Elements::Float.new(string)enddefread_bignumsign=read_bytedata=read_bytes(read_integer*2)Elements::Bignum.new(sign,data)enddefread_extended_objectraiseNotImplementedError,"Reading Marshal objects of type extended_object is not implemented"enddefread_classraiseNotImplementedError,"Reading Marshal objects of type class is not implemented"enddefread_moduleraiseNotImplementedError,"Reading Marshal objects of type module is not implemented"enddefread_class_or_moduleraiseNotImplementedError,"Reading Marshal objects of type class_or_module is not implemented"enddefread_dataraiseNotImplementedError,"Reading Marshal objects of type data is not implemented"enddefread_regexpraiseNotImplementedError,"Reading Marshal objects of type regexp is not implemented"enddefread_structraiseNotImplementedError,"Reading Marshal objects of type struct is not implemented"enddefread_user_classname=read_elementwrapped_object=read_elementElements::UserClass.new(name,wrapped_object)endendendend