Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions lib/cfpropertylist/rbBinaryCFPropertyList.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
module CFPropertyList
# Binary PList parser class
class Binary
MAX_DEPTH = 512

# Read a binary plist file
def load(opts)
@unique_table = {}
Expand Down Expand Up @@ -264,7 +266,7 @@ def unpack_with_size(nbytes, buff)
end

# Read an binary array value, including contained objects
def read_binary_array(fname,fd,length)
def read_binary_array(fname,fd,length,depth=0)
ary = []

# first: read object refs
Expand All @@ -274,7 +276,7 @@ def read_binary_array(fname,fd,length)

# now: read objects
0.upto(length-1) do |i|
object = read_binary_object_at(fname,fd,objects[i])
object = read_binary_object_at(fname,fd,objects[i],depth+1)
ary.push object
end
end
Expand All @@ -284,7 +286,7 @@ def read_binary_array(fname,fd,length)
protected :read_binary_array

# Read a dictionary value, including contained objects
def read_binary_dict(fname,fd,length)
def read_binary_dict(fname,fd,length,depth=0)
dict = {}

# first: read keys
Expand All @@ -298,8 +300,8 @@ def read_binary_dict(fname,fd,length)

# read real keys and objects
0.upto(length-1) do |i|
key = read_binary_object_at(fname,fd,keys[i])
object = read_binary_object_at(fname,fd,objects[i])
key = read_binary_object_at(fname,fd,keys[i],depth+1)
object = read_binary_object_at(fname,fd,objects[i],depth+1)
dict[key.value] = object
end
end
Expand All @@ -310,7 +312,7 @@ def read_binary_dict(fname,fd,length)

# Read an object type byte, decode it and delegate to the correct
# reader function
def read_binary_object(fname,fd)
def read_binary_object(fname,fd,depth=0)
# first: read the marker byte
buff = fd.read(1)

Expand All @@ -321,7 +323,7 @@ def read_binary_object(fname,fd)
object_type = buff[0][0].chr

if(object_type != "0" && object_length == 15) then
object_length = read_binary_object(fname,fd)
object_length = read_binary_object(fname,fd,depth)
object_length = object_length.value
end

Expand All @@ -343,18 +345,19 @@ def read_binary_object(fname,fd)
when '8'
CFUid.new(read_binary_int(fname, fd, object_length).value)
when 'a' # array
read_binary_array(fname,fd,object_length)
read_binary_array(fname,fd,object_length,depth)
when 'd' # dictionary
read_binary_dict(fname,fd,object_length)
read_binary_dict(fname,fd,object_length,depth)
end
end
protected :read_binary_object

# Read an object type byte at position $pos, decode it and delegate to the correct reader function
def read_binary_object_at(fname,fd,pos)
def read_binary_object_at(fname,fd,pos,depth=0)
raise CFFormatError.new("#{fname}: Maximum depth exceeded") if depth > MAX_DEPTH
position = @offsets[pos]
fd.seek(position,IO::SEEK_SET)
read_binary_object(fname,fd)
read_binary_object(fname,fd,depth)
end
protected :read_binary_object_at

Expand Down
13 changes: 13 additions & 0 deletions test/test_array.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,17 @@ def test_big_array
assert_equal raw_xml('big_array'), plist.to_str(CFPropertyList::List::FORMAT_XML, :formatted => false)
assert_equal raw_binary('big_array'), plist.to_str(CFPropertyList::List::FORMAT_BINARY)
end

def test_deeply_nested_array_binary
nested = "x"
2000.times { nested = [nested] }

plist = CFPropertyList::List.new
plist.value = CFPropertyList.guess(nested)
binary = plist.to_str(CFPropertyList::List::FORMAT_BINARY)

assert_raises CFFormatError do
CFPropertyList::List.new(:data => binary)
end
end
end
13 changes: 13 additions & 0 deletions test/test_dictionary.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,17 @@ def test_empty_key_with_rexml
ensure
CFPropertyList::List.parsers = orig_parsers
end

def test_deeply_nested_dict_binary
nested = "x"
2000.times { |i| nested = {"k#{i}" => nested} }

plist = CFPropertyList::List.new
plist.value = CFPropertyList.guess(nested)
binary = plist.to_str(CFPropertyList::List::FORMAT_BINARY)

assert_raises CFFormatError do
CFPropertyList::List.new(:data => binary)
end
end
end