I’m reading a binary file that stores a UInt16 that tells me if the rest of the section of the file is little-endian or big-endian. If the result of the read is 0x4d4d, it is little endian, and if it is 0x4949 it is big-endian (there are no other possible values). I had considered handling it like this:
f_read = read
function swapped_read(s, typ)
ntoh(read(s, typ))
end
function handle_endianness(io)
if read(io, UInt16) == 0x4d4d
global f_read = swapped_read
end
end
# ... rest of program
… but handling this with a global variable feels icky … surely there is a better way?
Especially since it looks like the global variable has to be untyped …
function swapped_read(s, typ)
ntoh(read(s, typ))
end
function handle_endianness(io)
if read(io, UInt16) == 0x4d4d
return swapped_read
else
return read
end
end
open(filename, "r") do file
f_read = handle_endianness(io)
# proceed with f_read
end
Why not just write your own read function that takes an endian-ness flag? Something like:
function myread(io, ::Type{T}, swap::Bool) where {T}
x = read(io, T)
return swap ? bswap(x) : x
end
Or, if you don’t want to pass a swap flag around everywhere, you can stash it in the io object by using an IOContext wrapper, i.e. replace io with IOContext(io, :byteswap=>swap) and then call get(io, :byteswap, false) anyplace you need to know whether to swap the byte order.
(Even fancier would be to define your own IO type that includes a byteswap flag, and then override standard functions like read for your IO subtype. Then you wouldn’t even have to touch most of your I/O code to explicitly call your myread function.)