Class: BitGirder::Io::BinaryConverter

Inherits:
BitGirderClass
  • Object
show all
Defined in:
lib/bitgirder/io.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*argv) ⇒ BinaryConverter

Set @plat_order as an instance variable instead of as a class constant. We could theoretically set plat order as a class constant, but don’t for 2 reasons. One is that, in the event there is a bug in our detection, we don’t want to fail any class requiring this file, since some code may never touch the BinaryConverter class anyway. Two is that we can use reflection during testing to simulate a different platform byte ordering on a test-by-test basis, rather than having to change a global constant



513
514
515
516
517
518
# File 'lib/bitgirder/io.rb', line 513

def initialize( *argv )
    
    super( *argv )

    @plat_order = BinaryConverter.detect_platform_order
end

Class Method Details

.detect_platform_orderObject



725
726
727
728
729
730
731
732
# File 'lib/bitgirder/io.rb', line 725

def self.detect_platform_order

    case test = [ 1 ].pack( 's' )
        when "\x01\x00" then ORDER_LITTLE_ENDIAN
        when "\x00\x01" then ORDER_BIG_ENDIAN
        else raise "Undetected byte order: #{test.inspect}"
    end
end

Instance Method Details

#read_bigdec(s) ⇒ Object



721
722
723
# File 'lib/bitgirder/io.rb', line 721

def read_bigdec( s )
    read_bigdec_with_info( s )[ 0 ]
end

#read_bigdec_with_info(s) ⇒ Object



700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
# File 'lib/bitgirder/io.rb', line 700

def read_bigdec_with_info( s )
    
    not_nil( s, :s )

    unscaled, info1 = read_bignum_with_info( s )
    unscaled_len = has_key( info1, :total_len )

    scale = read_int32( s[ unscaled_len, 4 ] )

    info2 = { 
        :total_len => unscaled_len + 4, 
        :unscaled_len => unscaled_len, 
        :scale_len => 4
    }

    num_str = unscaled.to_s( 10 ) + "e" + ( scale ).to_s

    [ BigDecimal.new( num_str ), info2 ]
end

#read_bignum(s) ⇒ Object



648
649
650
# File 'lib/bitgirder/io.rb', line 648

def read_bignum( s )
    read_bignum_with_info( s )[ 0 ]
end

#read_bignum_with_info(s) ⇒ Object



653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
# File 'lib/bitgirder/io.rb', line 653

def read_bignum_with_info( s )

    not_nil( s, :s )
    
    if ( len = s.size ) < 4
        raise "Input does not have a size (input len: #{len})"
    elsif len == 4
        raise "Input has no integer data (input len: #{len})"
    end

    sz = read_int32( s[ 0, 4 ] )
    rem = [ len - 4, len - sz ].min

    if ( rem = s.size - 4 ) < sz
        raise "Input specifies size #{sz} but actually is only of " \
               "length #{rem}"
    end

    info = { :total_len => 4 + sz, :hdr_len => 4, :num_len => sz }
    [ inflate_bignum( s[ 4, sz ] ), info ]
end

#read_float32(s) ⇒ Object



608
609
610
# File 'lib/bitgirder/io.rb', line 608

def read_float32( s )
    impl_read_float( s, :s, false )
end

#read_float64(s) ⇒ Object



613
614
615
# File 'lib/bitgirder/io.rb', line 613

def read_float64( s )
    impl_read_float( s, :s, true )
end

#write_bigdec(n) ⇒ Object



681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
# File 'lib/bitgirder/io.rb', line 681

def write_bigdec( n )
 
    not_nil( n, :n )
    raise "Not a BigDecimal" unless n.is_a?( BigDecimal )

    sign, unscaled, base, exp = n.split
    raise "Unexpected base: #{base}" unless base == 10
    raise "NaN not supported" if sign == 0

    if ( unscaled_i = unscaled.to_i ) == 0
        write_bignum( 0 ) + write_int32( 0 )
    else
        # sci_exp is the exponent we'd get using scientific notation
        sci_exp = -unscaled.size + exp
        write_bignum( unscaled_i * sign ) + write_int32( sci_exp )
    end
end

#write_bignum(i) ⇒ Object



618
619
620
621
622
623
624
625
626
627
628
629
# File 'lib/bitgirder/io.rb', line 618

def write_bignum( i )
    
    not_nil( i, :i )

    arr = Io.int_to_byte_array( i )
    arr.reverse! if @order == ORDER_BIG_ENDIAN

    res = write_int32( arr.size )
    arr.each { |b| res << b.chr }

    res
end

#write_float32(f) ⇒ Object



589
590
591
# File 'lib/bitgirder/io.rb', line 589

def write_float32( f )
    impl_write_float( f, :f, false )
end

#write_float64(d) ⇒ Object



594
595
596
# File 'lib/bitgirder/io.rb', line 594

def write_float64( d )
    impl_write_float( d, :d, true )
end