diff --git a/src/plain.jl b/src/plain.jl index 85b5a5e38..f431ec5c8 100644 --- a/src/plain.jl +++ b/src/plain.jl @@ -4,10 +4,10 @@ module HDF5 -include("datafile.jl") - ## Add methods to... -import Base: close, convert, done, dump, endof, flush, getindex, has, isempty, isvalid, length, names, ndims, next, read, setindex!, show, size, start, write +import Base: close, convert, done, dump, eltype, endof, flush, getindex, has, isempty, isvalid, length, names, ndims, next, read, setindex!, show, size, start, write + +include("datafile.jl") ## C types typealias C_time_t Int @@ -388,6 +388,13 @@ end # An empty array type type EmptyArray{T}; end +# Stub types to encode fixed-size arrays for H5T_ARRAY +immutable DimSize{N}; end # Int-wrapper (can't use tuple of Int as param) +immutable FixedArray{T,D<:(DimSize...)}; end +dimsize{N}(::Type{DimSize{N}}) = N +size{T,D}(::Type{FixedArray{T,D}}) = map(dimsize, D)::(Int...) +eltype{T,D}(::Type{FixedArray{T,D}}) = T + # VLEN objects type HDF5Vlen{T} data @@ -965,9 +972,7 @@ function read{T<:HDF5BitsKind}(obj::DatasetOrAttribute, ::Type{T}) end # Read array of BitsKind function read{T<:HDF5BitsKind}(obj::DatasetOrAttribute, ::Type{Array{T}}) - local data dims = size(obj) - dspace = dataspace(obj) data = Array(T, dims...) readarray(obj, hdf5_type_id(T), data) data @@ -976,6 +981,38 @@ end function read{T<:BitsKindOrByteString}(obj::DatasetOrAttribute, ::Type{EmptyArray{T}}) Array(T, 0) end +# Fixed-size arrays (H5T_ARRAY) +function read{A<:FixedArray}(obj::DatasetOrAttribute, ::Type{A}) + T = eltype(A) + sz = size(A) + data = Array(T, sz) + readarray(obj, hdf5_type_id(T), data) + data +end +function read{A<:FixedArray}(obj::DatasetOrAttribute, ::Type{Array{A}}) + T = eltype(A) + if !(T<:HDF5BitsKind) + error("Sorry, not yet supported") + end + sz = size(A) + dims = size(obj) + data = Array(T, tuple(sz..., dims...)) + nd = length(sz) + hsz = Hsize[convert(Hsize,sz[nd-i+1]) for i = 1:nd] + memtype_id = h5t_array_create(hdf5_type_id(T), convert(Cuint, length(sz)), hsz) + try + h5d_read(obj.id, memtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) + finally + h5t_close(memtype_id) + end + ret = Array(Array{T}, dims) + # Because of garbage-collection concerns, it's best to copy the data + L = prod(sz) + for i = 1:prod(dims) + ret[i] = reshape(data[(i-1)*L+1:i*L], sz) + end + ret +end # Clean up string buffer according to padding mode function unpad(s::ByteString, pad::Cint) @@ -1497,6 +1534,8 @@ function hdf5_to_julia_eltype(objtype) T = HDF5Vlen{hdf5_to_julia_eltype(HDF5Datatype(super_id))} elseif class_id == H5T_COMPOUND T = HDF5Compound + elseif class_id == H5T_ARRAY + T = hdf5array(objtype) else error("Class id ", class_id, " is not yet supported") end @@ -1724,8 +1763,11 @@ for (jlname, h5name, outtype, argtypes, argsyms, ex_error) in (:h5s_get_simple_extent_dims, :H5Sget_simple_extent_dims, Cint, (Hid, Ptr{Hsize}, Ptr{Hsize}), (:space_id, :dims, :maxdims), :(error("Error getting the dimensions for a dataspace"))), (:h5s_get_simple_extent_ndims, :H5Sget_simple_extent_ndims, Cint, (Hid,), (:space_id,), :(error("Error getting the number of dimensions for a dataspace"))), (:h5s_get_simple_extent_type, :H5Sget_simple_extent_type, Cint, (Hid,), (:space_id,), :(error("Error getting the dataspace type"))), + (:h5t_array_create, :H5Tarray_create2, Hid, (Hid, Cuint, Ptr{Hsize}), (:basetype_id, :ndims, :sz), :(error("Error creating H5T_ARRAY of id ", basetype_id, " and size ", sz))), (:h5t_copy, :H5Tcopy, Hid, (Hid,), (:dtype_id,), :(error("Error copying datatype"))), (:h5t_create, :H5Tcreate, Hid, (Cint, Csize_t), (:class_id, :sz), :(error("Error creating datatype of id ", classid))), + (:h5t_get_array_dims, :H5Tget_array_dims2, Cint, (Hid, Ptr{Hsize}), (:dtype_id, :dims), :(error("Error getting dimensions of array"))), + (:h5t_get_array_ndims, :H5Tget_array_ndims, Cint, (Hid,), (:dtype_id,), :(error("Error getting ndims of array"))), (:h5t_get_class, :H5Tget_class, Cint, (Hid,), (:dtype_id,), :(error("Error getting class"))), (:h5t_get_cset, :H5Tget_cset, Cint, (Hid,), (:dtype_id,), :(error("Error getting character set encoding"))), (:h5t_get_member_class, :H5Tget_member_class, Cint, (Hid, Cuint), (:dtype_id, :index), :(error("Error getting class of compound datatype member #", index))), @@ -1855,6 +1897,16 @@ function vlen_get_buf_size(dset::HDF5Dataset, dtype::HDF5Datatype, dspace::HDF5D sz[1] end +function hdf5array(objtype) + nd = h5t_get_array_ndims(objtype.id) + dims = Array(Hsize, nd) + h5t_get_array_dims(objtype.id, dims) + eltyp = HDF5Datatype(h5t_get_super(objtype.id)) + T = hdf5_to_julia_eltype(eltyp) + dimsizes = ntuple(nd, i->DimSize{int(dims[nd-i+1])}) # reverse order + FixedArray{T, dimsizes} +end + ### Property manipulation ### get_create_properties(dset::HDF5Dataset) = HDF5Properties(h5d_get_create_plist(dset.id)) get_create_properties(g::HDF5Group) = HDF5Properties(h5g_get_create_plist(dset.id)) diff --git a/test/readremote.jl b/test/readremote.jl index 9244275cc..21c8b107e 100644 --- a/test/readremote.jl +++ b/test/readremote.jl @@ -17,6 +17,29 @@ opq = Array{Uint8}[[0x4f, 0x50, 0x41, 0x51, 0x55, 0x45, 0x30], [0x4f, 0x50, 0x41, 0x51, 0x55, 0x45, 0x31], [0x4f, 0x50, 0x41, 0x51, 0x55, 0x45, 0x32], [0x4f, 0x50, 0x41, 0x51, 0x55, 0x45, 0x33]] +# For H5T_ARRAY +AA = Array{Int,2}[ +[ 0 0 0; + 0 -1 -2; + 0 -2 -4; + 0 -3 -6; + 0 -4 -8], +[ 0 1 2; + 1 1 1; + 2 1 0; + 3 1 -1; + 4 1 -2], +[ 0 2 4; + 2 3 4; + 4 4 4; + 6 5 4; + 8 6 4], +[ 0 3 6; + 3 5 7; + 6 7 8; + 9 9 9; + 12 11 10]] + const savedir = joinpath(tempdir(), "h5") if !isdir(savedir) @@ -132,3 +155,9 @@ d = read(fid, "DS1") @assert d.tag == "Character array" @assert d.data == opq close(fid) + +file = getfile("h5ex_t_array.h5") +fid = h5open(file, "r") +A = read(fid, "DS1") +@assert A == AA +close(fid)