Skip to content

Commit 7789af4

Browse files
authored
feat: support header_type UInt32 (#83)
* feat: support header_type UInt32 * formatting * Revert syntax changes * Add test for header type UInt32
1 parent e4f0366 commit 7789af4

5 files changed

Lines changed: 41 additions & 27 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ Further example VTK files can be found in the
8989
* Probably reading from VTK files that were *not* created by [WriteVTK.jl](https://github.com/JuliaVTK/WriteVTK.jl) will fail, specifically since
9090
* compressed data is assumed to be stored as a single block
9191
* appended data is assumed to be stored as `raw`
92-
* `header_type` is hardcoded to `UInt64`
9392
* Extracting primitives from `PolyData` files other than vortices, lines, and/or polygons
9493
* Likely anything else that is not specifically mentioned under *What works*
9594

docs/src/index.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,6 @@ Further example VTK files can be found in the
9898
* Probably reading from VTK files that were *not* created by [WriteVTK.jl](https://github.com/JuliaVTK/WriteVTK.jl) will fail, specifically since
9999
* compressed data is assumed to be stored as a single block
100100
* appended data is assumed to be stored as `raw`
101-
* `header_type` is hardcoded to `UInt64`
102101
* Extracting primitives from `PolyData` files other than vortices, lines, and/or polygons
103102
* Likely anything else that is not specifically mentioned under *What works*
104103
## Development

src/ReadVTK.jl

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,14 @@ mutable struct VTKFile
4747
appended_data::Vector{UInt8}
4848
n_points::Int
4949
n_cells::Int
50+
header_type::DataType
5051

5152
# Create inner constructor to add finalizer (this requires VTKFile to be a *mutable* struct)
5253
function VTKFile(filename, xml_file, file_type, version, byte_order, compressor,
53-
appended_data, n_points, n_cells)
54+
appended_data, n_points, n_cells, header_type)
5455
# Create new object
5556
vtk_file = new(filename, xml_file, file_type, version, byte_order, compressor,
56-
appended_data, n_points, n_cells)
57+
appended_data, n_points, n_cells, header_type)
5758

5859
# Create finalizer that releases memory for VTK file
5960
f(vtk_file) = free(vtk_file.xml_file)
@@ -63,8 +64,8 @@ mutable struct VTKFile
6364
end
6465
end
6566

66-
# Header type is hardcoded
67-
header_type(::VTKFile) = UInt64
67+
# Header type
68+
header_type(vtk_file::VTKFile) = vtk_file.header_type
6869

6970
# Return true if data is compressed (= XML attribute `compressor` is non-empty in VTK file)
7071
is_compressed(vtk_file::VTKFile) = !isempty(vtk_file.compressor)
@@ -133,7 +134,8 @@ function VTKFile(filename)
133134
(byte_order == "BigEndian" && !is_little_endian))
134135

135136
# Ensure matching header type
136-
@assert header_type == "UInt64"
137+
@assert header_type in ("UInt32", "UInt64")
138+
header_type_parsed = string_to_data_type(header_type)
137139

138140
# Ensure supported compression type
139141
@assert in(compressor, ("", "vtkZLibDataCompressor"))
@@ -162,7 +164,7 @@ function VTKFile(filename)
162164

163165
# Create and return VTKFile
164166
return VTKFile(filename, xml_file, file_type, version, byte_order, compressor,
165-
appended_data, n_points, n_cells)
167+
appended_data, n_points, n_cells, header_type_parsed)
166168
end
167169

168170
# Show basic information on REPL
@@ -766,17 +768,21 @@ function get_data(data_array::VTKDataArray{T, N, <:FormatBinary}) where {T, N}
766768
raw = base64decode(split(strip(content(data_array.data_array)), "\n")[1])
767769

768770
if is_compressed(data_array)
769-
# If data is stored compressed, the first four integers of type `header_type` are the header and
770-
# must be discarded
771-
first = 1 + 4 * sizeof(header_type(data_array.vtk_file))
771+
# If data is stored compressed, the header consists of `3 + num_blocks` integers of type
772+
# `header_type`. It must be discarded.
773+
HeaderType = header_type(data_array.vtk_file)
774+
header_num_blocks = reinterpret(HeaderType, raw[1:sizeof(HeaderType)])[1]
775+
header_len = 3 + header_num_blocks
776+
first = 1 + header_len * sizeof(HeaderType)
772777
last = length(raw)
773778

774779
# Pass data through ZLib decompressor
775780
uncompressed = transcode(ZlibDecompressor, raw[first:last])
776781
else
777782
# If data is stored uncompressed, the first integer of type `header_type` is the header and must
778783
# be discarded
779-
first = 1 + sizeof(header_type(data_array.vtk_file))
784+
HeaderType = header_type(data_array.vtk_file)
785+
first = 1 + sizeof(HeaderType)
780786
last = length(raw)
781787
uncompressed = view(raw, first:last)
782788
end
@@ -799,24 +805,28 @@ function get_data(data_array::VTKDataArray{T, N, <:FormatAppended}) where {T, N}
799805
HeaderType = header_type(data_array.vtk_file)
800806

801807
if is_compressed(data_array)
802-
# If data is stored compressed, the first four integers of type `header_type` are the header and
803-
# the fourth value contains the number of bytes to read
808+
# If data is stored compressed, the header consists of `3 + num_blocks` integers of type `header_type`.
809+
# The sum of the subsequent blocks contains the total number of compressed bytes to read.
804810
first = data_array.offset + 1
805-
last = data_array.offset + 4 * sizeof(HeaderType)
806-
header = Int.(reinterpret(HeaderType, raw[first:last]))
807-
n_bytes = header[4]
811+
header_num_blocks = reinterpret(HeaderType,
812+
raw[first:(first + sizeof(HeaderType) - 1)])[1]
813+
header_len = 3 + header_num_blocks
808814

809-
first = data_array.offset + 4 * sizeof(HeaderType) + 1
810-
last = first + n_bytes - 1
815+
last_header = data_array.offset + header_len * sizeof(HeaderType)
816+
header = Int.(reinterpret(HeaderType, raw[first:last_header]))
817+
n_bytes = sum(@view header[4:end])
818+
819+
first_data = last_header + 1
820+
last_data = first_data + n_bytes - 1
811821

812822
# Pass data through ZLib decompressor
813-
if last > length(raw)
823+
if last_data > length(raw)
814824
@show data_array data_array.vtk_file.xml_file
815-
@show first, last, size(raw)
825+
@show first, last_data, size(raw)
816826
error("mistake in get_data")
817827
end
818828

819-
uncompressed = transcode(ZlibDecompressor, raw[first:last])
829+
uncompressed = transcode(ZlibDecompressor, raw[first_data:last_data])
820830
else
821831
# If data is stored uncompressed, the first integer of type `header_type` is the header and
822832
# contains the number of bytes to read
@@ -981,7 +991,6 @@ function get_extents(xml_file, min_extent = [0; 0; 0])
981991
end
982992

983993

984-
985994
"""
986995
get_points(vtk_file::VTKFile)
987996

test/runtests.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ using ReadVTK, WriteVTK
66
# Note: The purpose of using a specific commit hash (instead of `main`) is to be able to tie a given
77
# version of ReadVTK to a specific version of the test file repository. This way, also tests
88
# for older ReadVTK releases should continue to work.
9-
TEST_EXAMPLES_COMMIT = "1f961a7ad38e76a8d552b8392d8cd661ab9f79b4"
9+
TEST_EXAMPLES_COMMIT = "18046cff6e50624cb0cb30cd2eb454833620958b"
1010

1111
# Local folder to store downloaded example files. If you change this, also adapt `../.gitignore`!
1212
TEST_EXAMPLES_DIR = abspath("examples")

test/structuredgrid.jl

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ for compress in [true, false]
106106

107107
name = vtk_save(vtk)[1]
108108

109-
# read the file back
109+
# Read the file back
110110
@testset "$name compress=$compress" begin
111111
vtk_read = VTKFile(name)
112112
@testset "coordinates" begin
113-
# read coordinates
113+
# Read coordinates
114114
x_read, y_read, z_read = get_coordinates(vtk_read)
115115

116116
@test sum(abs.(x - x_read)) == 0.0
@@ -120,7 +120,7 @@ for compress in [true, false]
120120
end
121121
end
122122

123-
# point data
123+
# Point data
124124
@testset "point data" begin
125125
point_data = get_point_data(vtk_read)
126126
p_read = get_data_reshaped(point_data["p_values"])
@@ -141,3 +141,10 @@ for compress in [true, false]
141141
end
142142
end
143143
end
144+
145+
@testset "Reading inline binary with header format UInt32" begin
146+
vtk = VTKFile(get_test_example_file("pointdata_inline_binary_compressed.vts"))
147+
point_data = get_point_data(vtk)
148+
r = get_data(point_data["RadialDistance"])
149+
@test sum(r) == 480.0
150+
end

0 commit comments

Comments
 (0)