Skip to content

FIX: Ensure loaded GIFTI files expose writable data arrays #750

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 29, 2019
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
48 changes: 23 additions & 25 deletions nibabel/gifti/parse_gifti_fast.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,41 @@ class GiftiParseError(ExpatError):

def read_data_block(encoding, endian, ordering, datatype, shape, data):
""" Tries to unzip, decode, parse the funny string data """
ord = array_index_order_codes.npcode[ordering]
enclabel = gifti_encoding_codes.label[encoding]
dtype = data_type_codes.type[datatype]
if enclabel == 'ASCII':
# GIFTI_ENCODING_ASCII
c = StringIO(data)
da = np.loadtxt(c)
da = da.astype(data_type_codes.type[datatype])
da = np.loadtxt(c, dtype=dtype)
return da # independent of the endianness

elif enclabel == 'B64BIN':
# GIFTI_ENCODING_B64BIN
dec = base64.b64decode(data.encode('ascii'))
dt = data_type_codes.type[datatype]
sh = tuple(shape)
newarr = np.frombuffer(dec, dtype=dt)
if len(newarr.shape) != len(sh):
newarr = newarr.reshape(sh, order=ord)

elif enclabel == 'B64GZ':
# GIFTI_ENCODING_B64GZ
# convert to bytes array for python 3.2
# http://www.diveintopython3.net/strings.html#byte-arrays
dec = base64.b64decode(data.encode('ascii'))
zdec = zlib.decompress(dec)
dt = data_type_codes.type[datatype]
sh = tuple(shape)
newarr = np.frombuffer(zdec, dtype=dt)
if len(newarr.shape) != len(sh):
newarr = newarr.reshape(sh, order=ord)

elif enclabel == 'External':
# GIFTI_ENCODING_EXTBIN
raise NotImplementedError("In what format are the external files?")

else:
elif enclabel not in ('B64BIN', 'B64GZ'):
return 0

# Numpy arrays created from bytes objects are read-only.
# Neither b64decode nor decompress will return bytearrays, and there
# are not equivalents to fobj.readinto to allow us to pass them, so
# there is not a simple way to avoid making copies.
# If this becomes a problem, we should write a decoding interface with
# a tunable chunk size.
dec = base64.b64decode(data.encode('ascii'))
if enclabel == 'B64BIN':
# GIFTI_ENCODING_B64BIN
buff = bytearray(dec)
else:
# GIFTI_ENCODING_B64GZ
buff = bytearray(zlib.decompress(dec))
del dec

sh = tuple(shape)
newarr = np.frombuffer(buff, dtype=dtype)
if len(newarr.shape) != len(sh):
newarr = newarr.reshape(sh, order=array_index_order_codes.npcode[ordering])

# check if we need to byteswap
required_byteorder = gifti_endian_codes.byteorder[endian]
if (required_byteorder in ('big', 'little') and
Expand Down
7 changes: 7 additions & 0 deletions nibabel/gifti/tests/test_parse_gifti_fast.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,13 @@ def test_readwritedata():
assert_array_almost_equal(img.darrays[0].data,
img2.darrays[0].data)

def test_modify_darray():
for fname in (DATA_FILE1, DATA_FILE2, DATA_FILE5):
img = load(fname)
darray = img.darrays[0]
darray.data[:] = 0
assert_true(np.array_equiv(darray.data, 0))


def test_write_newmetadata():
img = gi.GiftiImage()
Expand Down