Skip to content

Commit 685edf1

Browse files
committed
Merge pull request #34 from JuliaIO/sd/multi_lib
allow for multiple loader/saver libraries
2 parents 419e624 + 78f05b7 commit 685edf1

File tree

8 files changed

+221
-140
lines changed

8 files changed

+221
-140
lines changed

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,24 @@ add_loader(format"HDF5", :HDF5)
6868
add_saver(format"PNG", :ImageMagick)
6969
```
7070
These packages will be automatically loaded as needed.
71+
You can also define the loaders and savers in a short form like this:
72+
```jl
73+
add_format(format"OFF", "OFF", ".off", [:MeshIO])
74+
```
75+
This means MeshIO supports loading and saving of the `off` format.
76+
You can add multiple loaders and specifiers like this:
77+
```jl
78+
add_format(
79+
format"BMP",
80+
UInt8[0x42,0x4d],
81+
".bmp",
82+
[:OSXNativeIO, LOAD, OSX],
83+
[:ImageMagick]
84+
)
85+
```
86+
This means, OSXNative has first priority (gets loaded first) and only supports loading `bmp` on `OSX`.
87+
So on windows, `OSXNativeIO` will be ignored and `ImageMagick` has first priority.
88+
You can add any combination of `LOAD`, `SAVE`, `OSX`, `Unix`, `Windows` and `Linux`.
7189

7290
Users are encouraged to contribute these definitions to the
7391
`registry.jl` file of this package, so that information about file

src/FileIO.jl

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ include("query.jl")
3939
include("loadsave.jl")
4040
include("registry.jl")
4141

42+
43+
4244
@doc """
4345
- `load(filename)` loads the contents of a formatted file, trying to infer
4446
the format from `filename` and/or magic bytes in the file.
@@ -49,8 +51,17 @@ the magic bytes are essential.
4951
""" ->
5052
function load(s::@compat(Union{AbstractString,IO}), args...; options...)
5153
q = query(s)
52-
check_loader(q)
53-
load(q, args...; options...)
54+
libraries = applicable_loaders(q)
55+
last_exception = ErrorException("No library available to load $s")
56+
for library in libraries
57+
try
58+
Library = check_loader(library)
59+
return Library.load(q, args...; options...)
60+
catch e
61+
last_exception = e
62+
end
63+
end
64+
rethrow(last_exception)
5465
end
5566

5667
@doc """
@@ -61,8 +72,17 @@ trying to infer the format from `filename`.
6172
""" ->
6273
function save(s::@compat(Union{AbstractString,IO}), data...; options...)
6374
q = query(s)
64-
check_saver(q)
65-
save(q, data...; options...)
75+
libraries = applicable_savers(q)
76+
last_exception = ErrorException("No library available to save $s")
77+
for library in libraries
78+
try
79+
Library = check_saver(library)
80+
return Library.save(q, data...; options...)
81+
catch e
82+
last_exception = e #TODO, better and standardized exception propagation system
83+
end
84+
end
85+
rethrow(last_exception)
6686
end
6787

6888
# Fallbacks

src/loadsave.jl

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
const sym2loader = Dict{Symbol,Symbol}()
2-
const sym2saver = Dict{Symbol,Symbol}()
1+
const sym2loader = Dict{Symbol,Vector{Symbol}}()
2+
const sym2saver = Dict{Symbol,Vector{Symbol}}()
33

4-
for (fchk,fadd,dct) in ((:check_loader, :add_loader, :sym2loader),
5-
(:check_saver, :add_saver, :sym2saver))
4+
for (appl,fchk,fadd,dct) in ((:applicable_loaders, :check_loader, :add_loader, :sym2loader),
5+
(:applicable_savers, :check_saver, :add_saver, :sym2saver))
66
@eval begin
7-
function $fchk{sym}(::Formatted{DataFormat{sym}})
8-
if haskey($dct, sym)
9-
pkg = $dct[sym]
10-
if !isdefined(Main, pkg)
11-
eval(Main, Expr(:using, pkg))
12-
end
13-
end
7+
$appl{sym}(::Formatted{DataFormat{sym}}) = get($dct, sym, [:nothing])
8+
function $fchk(pkg::Symbol)
9+
pkg == :nothing && return FileIO #nothing is the symbol for no load/save specific lib. see above
10+
!isdefined(Main, pkg) && eval(Main, Expr(:import, pkg))
11+
return Main.(pkg)
1412
end
15-
1613
function $fadd{sym}(::Type{DataFormat{sym}}, pkg::Symbol)
17-
$dct[sym] = pkg
14+
list = get($dct, sym, Symbol[])
15+
$dct[sym] = push!(list, pkg)
1816
end
1917
end
2018
end

src/query.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,33 @@
11
### Format registry infrastructure
2+
abstract OS
3+
abstract Unix <: OS
4+
immutable Windows <: OS end
5+
immutable OSX <: Unix end
6+
immutable Linux <: Unix end
7+
8+
immutable LOAD end
9+
immutable SAVE end
10+
11+
split_predicates(list) = filter(x-> x <: OS, list), filter(x-> !(x <: OS), list)
12+
applies_to_os(os::Vector) = isempty(os) || any(applies_to_os, os)
13+
applies_to_os{O <: OS}(os::Type{O}) = false
14+
@unix_only applies_to_os{U <: Unix}(os::Type{U}) = true
15+
@windows_only applies_to_os(os::Type{Windows}) = true
16+
@osx_only applies_to_os(os::Type{OSX}) = true
17+
@linux_only applies_to_os(os::Type{Linux}) = true
18+
19+
function add_loadsave(format, predicates)
20+
library = shift!(predicates)
21+
os, loadsave = split_predicates(predicates)
22+
if applies_to_os(os)
23+
if isempty(loadsave) || (LOAD in loadsave)
24+
add_loader(format, library)
25+
end
26+
if isempty(loadsave) || (SAVE in loadsave)
27+
add_saver(format, library)
28+
end
29+
end
30+
end
231

332
@doc """
433
`DataFormat{sym}()` indicates a known binary or text format of kind `sym`,
@@ -25,6 +54,15 @@ const magic_list = Array(Pair, 0) # sorted, see magic_cmp below
2554
const sym2info = Dict{Symbol,Any}() # Symbol=>(magic, extension)
2655
const magic_func = Array(Pair, 0) # for formats with complex magic #s
2756

57+
58+
function add_format(fmt, magic, extension, load_save_libraries...)
59+
add_format(fmt, magic, extension)
60+
for library in load_save_libraries
61+
add_loadsave(fmt, library)
62+
end
63+
fmt
64+
end
65+
2866
@doc """
2967
`add_format(fmt, magic, extention)` registers a new `DataFormat`.
3068
For example:

src/registry.jl

Lines changed: 69 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
### Simple cases
2-
add_format(format"JLD", "Julia data file (HDF5)", ".jld")
3-
add_loader(format"JLD", :JLD)
4-
add_saver(format"JLD", :JLD)
2+
add_format(format"JLD", "Julia data file (HDF5)", ".jld", [:JLD])
53

64
# Image formats
75
add_format(format"PBMText", b"P1", ".pbm")
@@ -11,83 +9,65 @@ add_format(format"PBMBinary", b"P4", ".pbm")
119
add_format(format"PGMBinary", b"P5", ".pgm")
1210
add_format(format"PPMBinary", b"P6", ".ppm")
1311

14-
add_format(format"NRRD", "NRRD", [".nrrd", ".nhdr"])
15-
add_loader(format"NRRD", :NRRD)
16-
add_saver(format"NRRD", :NRRD)
17-
18-
add_format(format"AndorSIF", "Andor Technology Multi-Channel File", ".sif")
19-
add_loader(format"AndorSIF", :AndorSIF)
20-
21-
add_format(format"BMP", UInt8[0x42,0x4d], ".bmp")
22-
add_loader(format"BMP", :ImageMagick)
23-
add_saver(format"BMP", :ImageMagick)
24-
add_format(format"AVI", UInt8[0x52,0x49,0x46,0x46], ".avi")
25-
add_loader(format"AVI", :ImageMagick)
26-
add_saver(format"AVI", :ImageMagick)
27-
add_format(format"CRW", UInt8[0x49,0x49,0x1a,0x00,0x00,0x00,0x48,0x45], ".crw")
28-
add_loader(format"CRW", :ImageMagick)
29-
add_saver(format"CRW", :ImageMagick)
30-
add_format(format"CUR", UInt8[0x00,0x00,0x02,0x00], ".cur")
31-
add_loader(format"CUR", :ImageMagick)
32-
add_saver(format"CUR", :ImageMagick)
33-
add_format(format"DCX", UInt8[0xb1,0x68,0xde,0x3a], ".dcx")
34-
add_loader(format"DCX", :ImageMagick)
35-
add_saver(format"DCX", :ImageMagick)
36-
add_format(format"DOT", UInt8[0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1], ".dot")
37-
add_loader(format"DOT", :ImageMagick)
38-
add_saver(format"DOT", :ImageMagick)
39-
add_format(format"EPS", UInt8[0x25,0x21,0x50,0x53,0x2d,0x41,0x64,0x6f], ".eps")
40-
add_loader(format"EPS", :ImageMagick)
41-
add_saver(format"EPS", :ImageMagick)
42-
add_format(format"GIF", UInt8[0x47,0x49,0x46,0x38], ".gif")
43-
add_loader(format"GIF", :ImageMagick)
44-
add_saver(format"GIF", :ImageMagick)
45-
add_format(format"HDR", UInt8[0x23,0x3f,0x52,0x41,0x44,0x49,0x41,0x4e], ".hdr")
46-
add_loader(format"HDR", :ImageMagick)
47-
add_saver(format"HDR", :ImageMagick)
48-
add_format(format"ICO", UInt8[0x00,0x00,0x01,0x00], ".ico")
49-
add_loader(format"ICO", :ImageMagick)
50-
add_saver(format"ICO", :ImageMagick)
51-
add_format(format"INFO", UInt8[0x7a,0x62,0x65,0x78], ".info")
52-
add_loader(format"INFO", :ImageMagick)
53-
add_saver(format"INFO", :ImageMagick)
54-
add_format(format"JP2", UInt8[0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20], ".jp2")
55-
add_loader(format"JP2", :ImageMagick)
56-
add_saver(format"JP2", :ImageMagick)
57-
add_format(format"JPEG", UInt8[0xff,0xd8,0xff], [".jpeg", ".jpg", ".JPG"]) # 0xe1
58-
add_loader(format"JPEG", :ImageMagick)
59-
add_saver(format"JPEG", :ImageMagick)
60-
add_format(format"PCX", UInt8[0x0a,0x05,0x01,0x01], ".pcx")
61-
add_loader(format"PCX", :ImageMagick)
62-
add_saver(format"PCX", :ImageMagick)
63-
add_format(format"PDB", UInt8[0x73,0x7a,0x65,0x7a], ".pdb")
64-
add_loader(format"PDB", :ImageMagick)
65-
add_saver(format"PDB", :ImageMagick)
66-
add_format(format"PDF", UInt8[0x25,0x50,0x44,0x46], ".pdf")
67-
add_loader(format"PDF", :ImageMagick)
68-
add_saver(format"PDF", :ImageMagick)
69-
add_format(format"PGM", UInt8[0x50,0x35,0x0a], ".pgm")
70-
add_loader(format"PGM", :ImageMagick)
71-
add_saver(format"PGM", :ImageMagick)
72-
add_format(format"PNG", UInt8[0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a], ".png")
73-
add_loader(format"PNG", :ImageMagick)
74-
add_saver(format"PNG", :ImageMagick)
75-
add_format(format"PSD", UInt8[0x38,0x42,0x50,0x53], ".psd")
76-
add_loader(format"PSD", :ImageMagick)
77-
add_saver(format"PSD", :ImageMagick)
78-
add_format(format"RGB", UInt8[0x01,0xda,0x01,0x01,0x00,0x03], ".rgb")
79-
add_loader(format"RGB", :ImageMagick)
80-
add_saver(format"RGB", :ImageMagick)
81-
82-
add_format(format"TIFF", (UInt8[0x4d,0x4d,0x00,0x2a], UInt8[0x4d,0x4d,0x00,0x2b], UInt8[0x49,0x49,0x2a,0x00]), [".tiff", ".tif"])
83-
add_loader(format"TIFF", :ImageMagick)
84-
add_saver(format"TIFF", :ImageMagick)
85-
add_format(format"WMF", UInt8[0xd7,0xcd,0xc6,0x9a], ".wmf")
86-
add_loader(format"WMF", :ImageMagick)
87-
add_saver(format"WMF", :ImageMagick)
88-
add_format(format"WPG", UInt8[0xff,0x57,0x50,0x43], ".wpg")
89-
add_loader(format"WPG", :ImageMagick)
90-
add_saver(format"WPG", :ImageMagick)
12+
add_format(format"NRRD", "NRRD", [".nrrd", ".nhdr"], [:NRRD])
13+
14+
add_format(format"AndorSIF", "Andor Technology Multi-Channel File", ".sif", [:AndorSIF, LOAD])
15+
16+
17+
add_format(format"AVI", UInt8[0x52,0x49,0x46,0x46], ".avi", [:ImageMagick])
18+
add_format(format"CRW", UInt8[0x49,0x49,0x1a,0x00,0x00,0x00,0x48,0x45], ".crw", [:ImageMagick])
19+
add_format(format"CUR", UInt8[0x00,0x00,0x02,0x00], ".cur", [:ImageMagick])
20+
add_format(format"DCX", UInt8[0xb1,0x68,0xde,0x3a], ".dcx", [:ImageMagick])
21+
add_format(format"DOT", UInt8[0xd0,0xcf,0x11,0xe0,0xa1,0xb1,0x1a,0xe1], ".dot", [:ImageMagick])
22+
add_format(format"EPS", UInt8[0x25,0x21,0x50,0x53,0x2d,0x41,0x64,0x6f], ".eps", [:ImageMagick])
23+
add_format(format"HDR", UInt8[0x23,0x3f,0x52,0x41,0x44,0x49,0x41,0x4e], ".hdr", [:ImageMagick])
24+
add_format(format"ICO", UInt8[0x00,0x00,0x01,0x00], ".ico", [:ImageMagick])
25+
add_format(format"INFO", UInt8[0x7a,0x62,0x65,0x78], ".info",[:ImageMagick])
26+
add_format(format"JP2", UInt8[0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20], ".jp2", [:ImageMagick])
27+
add_format(format"PCX", UInt8[0x0a,0x05,0x01,0x01], ".pcx", [:ImageMagick])
28+
add_format(format"PDB", UInt8[0x73,0x7a,0x65,0x7a], ".pdb", [:ImageMagick])
29+
add_format(format"PDF", UInt8[0x25,0x50,0x44,0x46], ".pdf", [:ImageMagick])
30+
add_format(format"PGM", UInt8[0x50,0x35,0x0a], ".pgm", [:ImageMagick])
31+
add_format(format"PSD", UInt8[0x38,0x42,0x50,0x53], ".psd", [:ImageMagick])
32+
add_format(format"RGB", UInt8[0x01,0xda,0x01,0x01,0x00,0x03], ".rgb", [:ImageMagick])
33+
add_format(format"WMF", UInt8[0xd7,0xcd,0xc6,0x9a], ".wmf", [:ImageMagick])
34+
add_format(format"WPG", UInt8[0xff,0x57,0x50,0x43], ".wpg", [:ImageMagick])
35+
36+
add_format(
37+
format"GIF",
38+
UInt8[0x47,0x49,0x46,0x38],
39+
".gif",
40+
[:OSXNativeIO, LOAD, OSX],
41+
[:ImageMagick]
42+
)
43+
add_format(
44+
format"PNG",
45+
UInt8[0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a],
46+
".png",
47+
[:OSXNativeIO, LOAD, OSX],
48+
[:ImageMagick]
49+
)
50+
add_format(
51+
format"TIFF",
52+
(UInt8[0x4d,0x4d,0x00,0x2a], UInt8[0x4d,0x4d,0x00,0x2b], UInt8[0x49,0x49,0x2a,0x00]),
53+
[".tiff", ".tif"],
54+
[:OSXNativeIO, LOAD, OSX],
55+
[:ImageMagick]
56+
)
57+
add_format(
58+
format"JPEG",
59+
UInt8[0xff,0xd8,0xff],
60+
[".jpeg", ".jpg", ".JPG"],
61+
[:OSXNativeIO, LOAD, OSX],
62+
[:ImageMagick]
63+
) # 0xe1
64+
add_format(
65+
format"BMP",
66+
UInt8[0x42,0x4d],
67+
".bmp",
68+
[:OSXNativeIO, LOAD, OSX],
69+
[:ImageMagick]
70+
)
9171

9272
#=
9373
add_format(format"NPY", UInt8[0x93, 'N', 'U', 'M', 'P', 'Y'], ".npy")
@@ -100,30 +80,14 @@ add_saver(format"ZIP", :ZipeFile)
10080
=#
10181

10282
#Shader files
103-
add_format(format"GLSLShader", (), [".frag", ".vert", ".geom", ".comp"])
104-
add_loader(format"GLSLShader", :GLAbstraction)
105-
add_saver(format"GLSLShader", :GLAbstraction)
83+
add_format(format"GLSLShader", (), [".frag", ".vert", ".geom", ".comp"], [:GLAbstraction])
10684

10785
# Mesh formats
108-
add_format(format"OBJ", (), ".obj")
109-
add_loader(format"OBJ", :MeshIO)
110-
add_saver(format"OBJ", :MeshIO)
111-
112-
add_format(format"PLY_ASCII", "ply\nformat ascii 1.0", ".ply")
113-
add_format(format"PLY_BINARY", "ply\nformat binary_little_endian 1.0", ".ply")
114-
115-
add_loader(format"PLY_ASCII", :MeshIO)
116-
add_loader(format"PLY_BINARY", :MeshIO)
117-
add_saver(format"PLY_ASCII", :MeshIO)
118-
add_saver(format"PLY_BINARY", :MeshIO)
119-
120-
add_format(format"2DM", "MESH2D", ".2dm")
121-
add_loader(format"2DM", :MeshIO)
122-
add_saver(format"2DM", :MeshIO)
123-
124-
add_format(format"OFF", "OFF", ".off")
125-
add_loader(format"OFF", :MeshIO)
126-
add_saver(format"OFF", :MeshIO)
86+
add_format(format"OBJ", (), ".obj", [:MeshIO])
87+
add_format(format"PLY_ASCII", "ply\nformat ascii 1.0", ".ply", [:MeshIO])
88+
add_format(format"PLY_BINARY", "ply\nformat binary_little_endian 1.0", ".ply", [:MeshIO])
89+
add_format(format"2DM", "MESH2D", ".2dm", [:MeshIO])
90+
add_format(format"OFF", "OFF", ".off", [:MeshIO])
12791

12892

12993

@@ -150,10 +114,7 @@ function detecthdf5(io)
150114
end
151115
false
152116
end
153-
add_format(format"HDF5", detecthdf5, [".h5", ".hdf5"])
154-
add_loader(format"HDF5", :HDF5)
155-
add_saver(format"HDF5", :HDF5)
156-
117+
add_format(format"HDF5", detecthdf5, [".h5", ".hdf5"], [:HDF5])
157118

158119
function detect_stlascii(io)
159120
try
@@ -190,10 +151,6 @@ function detect_stlbinary(io)
190151
seekstart(io)
191152
return result
192153
end
193-
add_format(format"STL_ASCII", detect_stlascii, [".stl", ".STL"])
194-
add_format(format"STL_BINARY", detect_stlbinary, [".stl", ".STL"])
195-
add_loader(format"STL_ASCII", :MeshIO)
196-
add_saver(format"STL_BINARY", :MeshIO)
197-
add_saver(format"STL_ASCII", :MeshIO)
198-
add_loader(format"STL_BINARY", :MeshIO)
154+
add_format(format"STL_ASCII", detect_stlascii, [".stl", ".STL"], [:MeshIO])
155+
add_format(format"STL_BINARY", detect_stlbinary, [".stl", ".STL"], [:MeshIO])
199156

test/loadsave.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ try
1515
empty!(FileIO.sym2loader)
1616
empty!(FileIO.sym2saver)
1717
file_dir = joinpath(dirname(@__FILE__), "files")
18-
facts("Load") do
18+
context("Load") do
1919
@fact load(joinpath(file_dir, "file1.pbm")) --> "PBMText"
2020
@fact load(joinpath(file_dir, "file2.pbm")) --> "PBMBinary"
2121
# Regular HDF5 file with magic bytes starting at position 0
@@ -78,7 +78,7 @@ end
7878
add_loader(format"DUMMY", :Dummy)
7979
add_saver(format"DUMMY", :Dummy)
8080

81-
facts("Save") do
81+
context("Save") do
8282
a = [0x01,0x02,0x03]
8383
fn = string(tempname(), ".dmy")
8484
save(fn, a)

0 commit comments

Comments
 (0)