Skip to content

Commit 012ee8a

Browse files
committed
Merge pull request #173 from ruby-ldap/ber-encoding-integers-refactoring
Refactor BER encoding/decoding of Integers
2 parents 9dc1362 + c207770 commit 012ee8a

File tree

5 files changed

+48
-60
lines changed

5 files changed

+48
-60
lines changed

lib/net/ber/ber_parser.rb

+12-3
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,18 @@ def parse_ber_object(syntax, id, data)
4141
s.ber_identifier = id
4242
s
4343
elsif object_type == :integer
44-
j = 0
45-
data.each_byte { |b| j = (j << 8) + b }
46-
j
44+
neg = !(data.unpack("C").first & 0x80).zero?
45+
int = 0
46+
47+
data.each_byte do |b|
48+
int = (int << 8) + (neg ? 255 - b : b)
49+
end
50+
51+
if neg
52+
(int + 1) * -1
53+
else
54+
int
55+
end
4756
elsif object_type == :oid
4857
# See X.690 pgh 8.19 for an explanation of this algorithm.
4958
# This is potentially not good enough. We may need a

lib/net/ber/core_ext.rb

+3-10
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,10 @@ class Array
3333
end
3434
# :startdoc:
3535

36-
require 'net/ber/core_ext/bignum'
36+
require 'net/ber/core_ext/integer'
3737
# :stopdoc:
38-
class Bignum
39-
include Net::BER::Extensions::Bignum
40-
end
41-
# :startdoc:
42-
43-
require 'net/ber/core_ext/fixnum'
44-
# :stopdoc:
45-
class Fixnum
46-
include Net::BER::Extensions::Fixnum
38+
class Integer
39+
include Net::BER::Extensions::Integer
4740
end
4841
# :startdoc:
4942

lib/net/ber/core_ext/bignum.rb

-22
This file was deleted.

lib/net/ber/core_ext/fixnum.rb renamed to lib/net/ber/core_ext/integer.rb

+22-22
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
# -*- ruby encoding: utf-8 -*-
22
##
3-
# Ber extensions to the Fixnum class.
4-
module Net::BER::Extensions::Fixnum
3+
# BER extensions to the Integer class, affecting Fixnum and Bignum objects.
4+
module Net::BER::Extensions::Integer
55
##
6-
# Converts the fixnum to BER format.
6+
# Converts the Integer to BER format.
77
def to_ber
88
"\002#{to_ber_internal}"
99
end
1010

1111
##
12-
# Converts the fixnum to BER enumerated format.
12+
# Converts the Integer to BER enumerated format.
1313
def to_ber_enumerated
1414
"\012#{to_ber_internal}"
1515
end
1616

1717
##
18-
# Converts the fixnum to BER length encodining format.
18+
# Converts the Integer to BER length encoding format.
1919
def to_ber_length_encoding
2020
if self <= 127
2121
[self].pack('C')
@@ -33,34 +33,34 @@ def to_ber_application(tag)
3333
end
3434

3535
##
36-
# Used to BER-encode the length and content bytes of a Fixnum. Callers
36+
# Used to BER-encode the length and content bytes of an Integer. Callers
3737
# must prepend the tag byte for the contained value.
3838
def to_ber_internal
39-
# CAUTION: Bit twiddling ahead. You might want to shield your eyes or
40-
# something.
39+
# Compute the byte length, accounting for negative values requiring two's
40+
# complement.
41+
size = 1
42+
size += 1 until (((self < 0) ? ~self : self) >> (size * 8)).zero?
4143

42-
# Looks for the first byte in the fixnum that is not all zeroes. It does
43-
# this by masking one byte after another, checking the result for bits
44-
# that are left on.
45-
size = Net::BER::MAX_FIXNUM_SIZE
46-
while size > 1
47-
break if (self & (0xff << (size - 1) * 8)) > 0
48-
size -= 1
44+
# Padding for positive, negative values. See section 8.5 of ITU-T X.690:
45+
# http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
46+
47+
# For positive integers, if most significant bit in an octet is set to one,
48+
# pad the result (otherwise it's decoded as a negative value).
49+
if self > 0 && (self & (0x80 << (size - 1) * 8)) > 0
50+
size += 1
4951
end
5052

51-
# for positive integers, if most significant bit in an octet is set to one,
52-
# pad the result (otherwise it's decoded as a negative value)
53-
# See section 8.5 of ITU-T X.690:
54-
# http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
55-
if self > 0 && (self & (0b10000000 << (size - 1) * 8)) > 0
53+
# And for negative integers, pad if the most significant bit in the octet
54+
# is not set to one (othwerise, it's decoded as positive value).
55+
if self < 0 && (self & (0x80 << (size - 1) * 8)) == 0
5656
size += 1
5757
end
5858

59-
# Store the size of the fixnum in the result
59+
# Store the size of the Integer in the result
6060
result = [size]
6161

6262
# Appends bytes to result, starting with higher orders first. Extraction
63-
# of bytes is done by right shifting the original fixnum by an amount
63+
# of bytes is done by right shifting the original Integer by an amount
6464
# and then masking that with 0xff.
6565
while size > 0
6666
# right shift size - 1 bytes, mask with 0xff

test/ber/test_ber.rb

+11-3
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,17 @@ def test_false
4545
5_000_000_000 => "\x02\x05\x01\x2a\x05\xF2\x00",
4646

4747
# negatives
48-
# -1 => "\x02\x01\xFF",
49-
# -127 => "\x02\x01\x81",
50-
# -128 => "\x02\x01\x80"
48+
-1 => "\x02\x01\xFF",
49+
-127 => "\x02\x01\x81",
50+
-128 => "\x02\x01\x80",
51+
-255 => "\x02\x02\xFF\x01",
52+
-256 => "\x02\x02\xFF\x00",
53+
-65535 => "\x02\x03\xFF\x00\x01",
54+
-65536 => "\x02\x03\xFF\x00\x00",
55+
-65537 => "\x02\x03\xFE\xFF\xFF",
56+
-8388607 => "\x02\x03\x80\x00\x01",
57+
-8388608 => "\x02\x03\x80\x00\x00",
58+
-16_777_215 => "\x02\x04\xFF\x00\x00\x01",
5159
}.each do |number, expected_encoding|
5260
define_method "test_encode_#{number}" do
5361
assert_equal expected_encoding.b, number.to_ber

0 commit comments

Comments
 (0)