Skip to content

Commit

Permalink
Fix bug with incorrect array length in read
Browse files Browse the repository at this point in the history
  • Loading branch information
eivindjahren committed Aug 4, 2021
1 parent ea3a79d commit c5a5541
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 12 deletions.
16 changes: 16 additions & 0 deletions src/ecl_data_io/_unformatted/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,19 @@ def item_size(type_keyword):
if type_keyword[0:2] == b"C0":
return int(type_keyword[2:4].decode("ascii"))
return static_item_sizes.get(type_keyword, None)


def bytes_in_array(array_length, item_type):
"""
:param array_length: Number of items in the array
:param item_type: Type of items in the array
:returns: Number of bytes used to store an array of
given type and length
"""
g_len = group_len(item_type)
full_groups = array_length // g_len

if array_length % g_len:
return (full_groups + 1) * 8 + array_length * item_size(item_type)
else:
return full_groups * 8 + array_length * item_size(item_type)
20 changes: 9 additions & 11 deletions src/ecl_data_io/_unformatted/read.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import io

import numpy as np

import ecl_data_io.types as ecl_io_types
from ecl_data_io._unformatted.common import group_len, item_size
import numpy as np
from ecl_data_io._unformatted.common import bytes_in_array, group_len, item_size
from ecl_data_io.array_entry import EclArray
from ecl_data_io.errors import EclParsingError

Expand Down Expand Up @@ -61,7 +60,9 @@ def _read_record_marker(self, expected_value):
"""
value = int.from_bytes(self.stream.read(4), byteorder="big", signed=True)
if value != expected_value:
raise EclParsingError(f"Unexpected size of record {value}")
raise EclParsingError(
f"Unexpected size of record {value} ({value.to_bytes(4, byteorder='big', signed=True)})"
)

def _read_keyword(self):
"""
Expand Down Expand Up @@ -102,7 +103,9 @@ def _read(self):
return
start_marker_value = int.from_bytes(start_marker, byteorder="big", signed=True)
if start_marker_value != 16:
raise EclParsingError(f"Unexpected size of record {start_marker_value}")
raise EclParsingError(
f"Unexpected size of record {start_marker_value} ({start_marker})"
)
self._read_keyword()
self._length = self._read_length()
self._read_type()
Expand Down Expand Up @@ -133,12 +136,7 @@ def _read(self):
f"has item length {type_len} which requires 0 number of"
f"elements, but found {self._length} amount of elements."
)

g_len = group_len(self.type)
num_groups = self._length // g_len + 1
if self._length == 0:
num_groups = 0
bytes_to_skip = num_groups * 8 + self._length * type_len
bytes_to_skip = bytes_in_array(self._length, self.type)

self._data_start = self.stream.tell()
self.stream.seek(bytes_to_skip, io.SEEK_CUR)
29 changes: 28 additions & 1 deletion tests/test_formatted_common.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
from ecl_data_io._unformatted.common import group_len, item_size
import hypothesis.strategies as st
import pytest
from ecl_data_io._unformatted.common import bytes_in_array, group_len, item_size
from hypothesis import given


def test_group_len():
Expand All @@ -21,3 +24,27 @@ def test_item_size():
assert item_size(b"DOUB") == 8
assert item_size(b"MESS") == 0
assert item_size(b"x231") is None


def test_bytes_in_array():
assert bytes_in_array(1000, b"DOUB") == 8008
assert bytes_in_array(1000, b"REAL") == 4008
assert bytes_in_array(900, b"REAL") == 900 * 4 + 8
assert bytes_in_array(1100, b"REAL") == 1000 * 4 + 8 + 100 * 4 + 8
assert bytes_in_array(0, b"REAL") == 0


@pytest.mark.parametrize(
"item_type",
[
b"C032",
b"CHAR",
b"INTE",
b"REAL",
b"LOGI",
b"DOUB",
],
)
@given(length=st.integers(min_value=1, max_value=104))
def test_bytes_in_array_one_group(item_type, length):
assert bytes_in_array(length, item_type) == 8 + length * item_size(item_type)

0 comments on commit c5a5541

Please sign in to comment.