Skip to content

Instantly share code, notes, and snippets.

@pbevin
Created September 9, 2009 14:14
Show Gist options
  • Save pbevin/183752 to your computer and use it in GitHub Desktop.
Save pbevin/183752 to your computer and use it in GitHub Desktop.
diff --git a/kernel/common/float.rb b/kernel/common/float.rb
index bd31205..3b8d40c 100644
--- a/kernel/common/float.rb
+++ b/kernel/common/float.rb
@@ -161,6 +161,10 @@ class Float < Numeric
end
private :to_s_formatted
+ def to_packed(size)
+ Ruby.primitive :float_to_packed
+ end
+
def round
Ruby.primitive :float_round
end
diff --git a/kernel/common/pack.rb b/kernel/common/pack.rb
index f82b4a4..f728cf1 100644
--- a/kernel/common/pack.rb
+++ b/kernel/common/pack.rb
@@ -45,8 +45,13 @@ class Array::Packer
when 'M' then
# for some reason MRI responds to to_s here
item = Type.coerce_to(fetch_item(), String, :to_s)
- # 75 chars per line includes =\n
- @result << item.scan(/.{1,73}/m).map { |line|
+ line_length = 72
+ if t && t =~ /^\d/ && t.to_i >= 3
+ line_length = t.to_i
+ end
+ line_length += 1 # bug compatibility with MRI
+
+ @result << item.scan(/.{1,#{line_length}}/m).map { |line|
line.gsub(/[^ -<>-~\t\n]/) { |m| "=%02X" % m[0] } + "=\n"
}.join
when 'm' then
@@ -62,8 +67,7 @@ class Array::Packer
when 'p', 'P' then
pointer(kind, t)
when 'Q', 'q' then
- item = Type.coerce_to(fetch_item(), Fixnum, :to_int)
- raise ArgumentError, "#{kind} not implemented"
+ integer(kind, t)
when 'H', 'h' then
hex_string(kind, t)
when 'U' then
@@ -97,6 +101,13 @@ class Array::Packer
end
def parse_tail(t, kind, remaining = @source.size - @index)
+ if(t != nil && (t.include?('_') || t.include?('!')))
+ unless 'sSiIlL'.include?(kind)
+ raise ArgumentError, "#{t} allowed only after types sSiIlL"
+ end
+ t = t.delete("_!")
+ end
+
case t
when nil
1
@@ -104,11 +115,6 @@ class Array::Packer
remaining
else
m = t.match(/(\d+)/)
- if(t.include?('_') || t.include?('!'))
- unless 'sSiIlL'.include?(kind)
- raise ArgumentError, "#{t} allowed only after types sSiIlL"
- end
- end
m ? m[0].to_i : 1
end
end
@@ -227,31 +233,43 @@ class Array::Packer
end
def decimal(kind, t)
+ size = parse_tail(t, kind)
+
item = fetch_item()
item = FloatValue item
- raise ArgumentError, "not implemented"
+ want_double = case kind
+ when 'E', 'D', 'd', 'G' then true
+ when 'e', 'F', 'f', 'g' then false
+ end
+
+ little_endian = case kind
+ when 'e', 'E' then true
+ when 'g', 'G' then false
+ else endian?(:little)
+ end
+
+ size.times do
+ bytes = item.to_packed(want_double)
+ bytes.reverse! if little_endian ^ endian?(:little)
+ @result << bytes
+ end
end
- # i, s, l, n, I, S, L, V, v, N
+ # i, s, l, n, I, S, L, V, v, N, q, Q
def integer(kind, t)
size = parse_tail(t, kind)
if(t && (t.include?('_') || t.include?('!')))
- native = t
+ # Native sizes
+ bytes = case kind
+ when 'L', 'l' then Rubinius::SIZEOF_LONG
+ when 'I', 'i' then Rubinius::SIZEOF_INT
+ when 'S', 's' then Rubinius::SIZEOF_SHORT
+ end
else
- native = false
- end
-
- unsigned = (kind =~ /I|S|L/)
- little_endian = case kind
- when 'V', 'v' then true
- when 'N', 'n' then false
- else endian?(:little)
- end
-
- unless native then
bytes = case kind
+ when 'Q', 'q' then 8
when 'L', 'l' then 4
when 'I', 'i' then 4
when 'S', 's' then 2
@@ -262,46 +280,64 @@ class Array::Packer
end
end
+ unsigned = (kind =~ /I|S|L/)
+ little_endian = case kind
+ when 'V', 'v' then true
+ when 'N', 'n' then false
+ else endian?(:little)
+ end
+
raise ArgumentError, "too few array elements" if
@index + size > @source.length
size.times do |i|
item = Type.coerce_to(fetch_item(), Integer, :to_int)
- if item.abs >= 2**Rubinius::WORDSIZE
+ max_wordsize = case kind
+ when 'Q', 'q' then 64
+ else Rubinius::WORDSIZE
+ end
+
+ if item.abs >= 2**max_wordsize
raise RangeError, "bignum too big to convert into 'unsigned long'"
end
- raise ArgumentError, "unsupported - fix me" if native
-
- @result << if little_endian then
- item += 2 ** (8 * bytes) if item < 0
- (0...bytes).map { |b| ((item >> (b * 8)) & 0xFF).chr }
- else # ugly
- (0...bytes).map {n=(item & 0xFF).chr;item >>= 8; n}.reverse
- end.join
+ @result << if little_endian then
+ item += 2 ** (8 * bytes) if item < 0
+ (0...bytes).map { |b| ((item >> (b * 8)) & 0xFF).chr }
+ else # ugly
+ (0...bytes).map {n=(item & 0xFF).chr;item >>= 8; n}.reverse
+ end.join
end
end
# w
def ber_compress(kind, t)
- item = Type.coerce_to(fetch_item(), Integer, :to_int)
- raise ArgumentError, "can't compress negative numbers" if item < 0
-
- @result << (item & 0x7f)
- while (item >>= 7) > 0 do
- @result << ((item & 0x7f) | 0x80)
+ parse_tail(t, kind).times do
+ chars = ''
+ item = Type.coerce_to(fetch_item(), Integer, :to_int)
+ raise ArgumentError, "can't compress negative numbers" if item < 0
+
+ chars << (item & 0x7f)
+ while (item >>= 7) > 0 do
+ chars << ((item & 0x7f) | 0x80)
+ end
+ @result << chars.reverse
end
-
- @result.reverse! # FIX - breaks anything following BER?
end
# u, m
def encode(kind, t, type = :base64)
item = Type.coerce_to(fetch_item(), String, :to_str)
+ line_length = 45
+ if t && t =~ /^\d/ && t.to_i >= 3
+ line_length = t.to_i
+ line_length -= line_length % 3
+ end
+
# http://www.opengroup.org/onlinepubs/009695399/utilities/uuencode.html
- item.scan(/.{1,45}/m).map { |line|
+ item.scan(/.{1,#{line_length}}/m).map { |line|
encoded = line.scan(/(.)(.?)(.?)/m).map { |a,b,c|
a = a[0]
b = b[0] || 0
diff --git a/spec/tags/frozen/core/array/pack_tags.txt b/spec/tags/frozen/core/array/pack_tags.txt
index 78a882d..3ff78df 100644
--- a/spec/tags/frozen/core/array/pack_tags.txt
+++ b/spec/tags/frozen/core/array/pack_tags.txt
@@ -1,192 +1,3 @@
-fails:Array#pack with format 'n' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 'N' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 'q' returns a string containing 8 bytes for an integer
-fails:Array#pack with format 'q' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 'q' raises a RangeError when a pack argument is >= 2**64
-fails:Array#pack with format 'q' raises a RangeError when a pack argument is <= -2**64
-fails:Array#pack with format 'q' tries to convert the pack argument to an Integer using #to_int
-fails:Array#pack with format 'q' processes count number of array elements if count given
-fails:Array#pack with format 'q' returns empty string if count = 0
-fails:Array#pack with format 'q' with star parameter processes all remaining array items
-fails:Array#pack with format 'Q' returns a string containing 8 bytes for an integer
-fails:Array#pack with format 'Q' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 'Q' raises a RangeError when a pack argument is >= 2**64
-fails:Array#pack with format 'Q' raises a RangeError when a pack argument is <= -2**64
-fails:Array#pack with format 'Q' tries to convert the pack argument to an Integer using #to_int
-fails:Array#pack with format 'Q' processes count number of array elements if count given
-fails:Array#pack with format 'Q' returns empty string if count = 0
-fails:Array#pack with format 'Q' with star parameter processes all remaining array items
-fails:Array#pack with format 's!' returns a string containing 2 bytes for an integer
-fails:Array#pack with format 's!' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 's!' drops higher bytes when a pack argument is >= 2**16
-fails:Array#pack with format 's!' drops higher bytes when a pack argument is < -2**16
-fails:Array#pack with format 's!' tries to convert the pack argument to an Integer using #to_int
-fails:Array#pack with format 's!' processes count number of array elements if count given
-fails:Array#pack with format 's!' with star parameter processes all remaining array items
-fails:Array#pack with format 's_' returns a string containing 2 bytes for an integer
-fails:Array#pack with format 's_' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 's_' drops higher bytes when a pack argument is >= 2**16
-fails:Array#pack with format 's_' drops higher bytes when a pack argument is < -2**16
-fails:Array#pack with format 's_' tries to convert the pack argument to an Integer using #to_int
-fails:Array#pack with format 's_' processes count number of array elements if count given
-fails:Array#pack with format 's_' with star parameter processes all remaining array items
-fails:Array#pack with format 'S_' returns a string containing 2 bytes for an integer
-fails:Array#pack with format 'S_' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 'S_' drops higher bytes when a pack argument is >= 2**16
-fails:Array#pack with format 'S_' drops higher bytes when a pack argument is < -2**16
-fails:Array#pack with format 'S_' tries to convert the pack argument to an Integer using #to_int
-fails:Array#pack with format 'S_' processes count number of array elements if count given
-fails:Array#pack with format 'S_' with star parameter processes all remaining array items
-fails:Array#pack with format 'i!' returns a string containing 4 bytes for an integer
-fails:Array#pack with format 'i!' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 'i!' tries to convert the pack argument to an Integer using #to_int
-fails:Array#pack with format 'i!' processes count number of array elements if count given
-fails:Array#pack with format 'i!' with star parameter processes all remaining array items
-fails:Array#pack with format 'i_' returns a string containing 4 bytes for an integer
-fails:Array#pack with format 'i_' regards negative values as 2's complement in order to converts it to positive
-fails:Array#pack with format 'i_' tries to convert the pack argument to an Integer using #to_int
-fails:Array#pack with format 'i_' processes count number of array elements if count given
-fails:Array#pack with format 'i_' with star parameter processes all remaining array items
-fails:Array#pack with format 'I!' returns a string containing 4 bytes for an integer
-fails:Array#pack with format 'I!'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment