Skip to content

Commit 59dc04a

Browse files
committed
NF - incorporate Ians code with tests; fix 4 byte boundaries
1 parent 4ae5b67 commit 59dc04a

File tree

2 files changed

+68
-25
lines changed

2 files changed

+68
-25
lines changed

nibabel/dicom/csareader.py

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,75 @@ class CSAReadError(Exception):
88
pass
99

1010

11-
def read(fileobj):
12-
''' Read CSA header from fileobj
11+
def read(csa_str):
12+
''' Read CSA header from string `csa_str`
1313
1414
Parameters
1515
----------
16-
fileobj : file-like
17-
file-like object implementing ``read, seek, tell`. The data is
18-
taken to start at position 0 and end at the end of the file.
16+
csa_str : str
17+
byte string containing CSA header information
1918
2019
Returns
2120
-------
2221
header : dict
2322
header information
24-
tags : sequence
25-
sequence of tags from header
2623
'''
27-
fileobj.seek(0)
28-
hdr_id = fileobj.read(4)
29-
hdr = {}
30-
tags = []
24+
hdr_id = csa_str[:4]
25+
csa_len = len(csa_str)
26+
csa_dict = {'tags': {}}
3127
if hdr_id != 'SV10':
32-
hdr['type'] = 1
33-
hdr['n_tags'], = unpack('<i', hdr_id)
28+
csa_dict['type'] = 1
29+
csa_dict['n_tags'], = unpack('<i', hdr_id)
30+
ptr = 4
3431
else:
35-
hdr['type'] = 2
36-
hdr['unused1'] = fileobj.read(4)
37-
hdr['n_tags'], = unpack('<I', fileobj.read(4))
38-
hdr['unused3'], = unpack('<I', fileobj.read(4))
39-
return hdr, tags
32+
csa_dict['type'] = 2
33+
csa_dict['unused0'] = csa_str[4:8]
34+
csa_dict['n_tags'], = unpack('<I', csa_str[8:12])
35+
ptr = 12
36+
csa_dict['check'], = unpack('<I', csa_str[ptr:ptr+4])
37+
ptr +=4
38+
for tag_no in range(csa_dict['n_tags']):
39+
name, vm, vr, syngodt, n_items, xx = \
40+
unpack('<64sI4sIII',csa_str[ptr:ptr+84])
41+
name = nt_str(name)
42+
tag = {'pointer': ptr,
43+
'n_items': n_items,
44+
'last3': xx}
45+
ptr+=84
46+
assert n_items < 100
47+
for item_no in range(n_items):
48+
tag['pointer'] = ptr
49+
x0,x1,x2,x3 = unpack('<4i',csa_str[ptr:ptr+16])
50+
tag['xx'] = [x0,x1,x2,x3]
51+
ptr+=16
52+
item_len = x1
53+
if (ptr + item_len) > csa_len:
54+
raise CSAReadError('Item is too long, aborting read')
55+
format = '<%ds' % item_len
56+
tag['value'] = unpack(format,csa_str[ptr:ptr+item_len])
57+
plus4 = item_len % 4
58+
if plus4 != 0:
59+
ptr+=item_len + (4-plus4)
60+
else:
61+
ptr+=item_len
62+
tag['end_pointer'] = ptr
63+
csa_dict['tags'][name] = tag
64+
return csa_dict
65+
66+
67+
def nt_str(s):
68+
''' Strip string to first null
69+
70+
Parameters
71+
----------
72+
s : str
73+
74+
Returns
75+
-------
76+
sdash : str
77+
s stripped to first occurence of null (0)
78+
'''
79+
zero_pos = s.find(chr(0))
80+
if zero_pos == -1:
81+
return s
82+
return s[:zero_pos]

nibabel/dicom/tests/test_csareader.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@
1717

1818
data_path = pjoin(os.path.dirname(__file__), 'data')
1919

20-
CSA2_B0 = pjoin(data_path, 'csa2_b0.bin')
21-
CSA2_B1000 = pjoin(data_path, 'csa2_b1000.bin')
20+
CSA2_B0 = open(pjoin(data_path, 'csa2_b0.bin')).read()
21+
CSA2_B1000 = open(pjoin(data_path, 'csa2_b1000.bin')).read()
2222

2323

2424
@parametric
2525
def test_csa():
26-
csa_f = open(CSA2_B0, 'rb')
27-
hdr, tags = csa.read(csa_f)
28-
yield assert_equal(hdr['type'], 2)
29-
yield assert_equal(hdr['n_tags'], 83)
26+
csa_info = csa.read(CSA2_B0)
27+
yield assert_equal(csa_info['type'], 2)
28+
yield assert_equal(csa_info['n_tags'], 83)
29+
tags = csa_info['tags']
3030
yield assert_equal(len(tags), 83)
31-
31+
print csa_info

0 commit comments

Comments
 (0)