diff --git a/REQUIRE b/REQUIRE index 94237c0..f153758 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1 +1,2 @@ julia 0.5 +Compat 0.13.0 diff --git a/src/PlyIO.jl b/src/PlyIO.jl index b0eb500..3fd67dd 100644 --- a/src/PlyIO.jl +++ b/src/PlyIO.jl @@ -2,6 +2,8 @@ __precompile__() module PlyIO +using Compat + # Types for the ply data model export Ply, PlyElement, PlyComment, ArrayProperty, ListProperty export plyname # Is there something in base we could overload for this? diff --git a/src/io.jl b/src/io.jl index 0b20bb3..40bf4fe 100644 --- a/src/io.jl +++ b/src/io.jl @@ -44,7 +44,7 @@ ply_type_name(::Int64) = "int64" ply_type_name(::Float32) = "float32" ply_type_name(::Float64) = "float64" -typealias PlyNativeType Union{UInt8,UInt16,UInt32,UInt64,Int8,Int16,Int32,Int64,Float32,Float64} +@compat const PlyNativeType = Union{UInt8,UInt16,UInt32,UInt64,Int8,Int16,Int32,Int64,Float32,Float64} ply_type_name{T<:PlyNativeType}(A::AbstractArray{T}) = ply_type_name(T) @@ -56,7 +56,10 @@ const _host_is_little_endian = (ENDIAN_BOM == 0x04030201) function read_header(ply_file) - @assert readline(ply_file) == "ply\n" + firstline = Compat.readline(ply_file) + if firstline != "ply" + throw(ErrorException("Expected \"ply\" header, got \"$firstline\"")) + end element_name = "" element_numel = 0 element_props = Vector{AbstractVector}() @@ -64,42 +67,55 @@ function read_header(ply_file) comments = PlyComment[] format = nothing while true - line = strip(readline(ply_file)) - if line == "end_header" + line = Compat.readline(ply_file) + if line == "" && eof(ply_file) + throw(ErrorException("Unexpected end of file reading ply header")) + elseif line == "end_header" break elseif startswith(line, "comment") push!(comments, PlyComment(strip(line[8:end]), length(elements)+1)) - elseif startswith(line, "format") - tok, format_type, format_version = split(line) - @assert tok == "format" - @assert format_version == "1.0" - format = format_type == "ascii" ? Format_ascii : - format_type == "binary_little_endian" ? Format_binary_little : - format_type == "binary_big_endian" ? Format_binary_big : - error("Unknown ply format $format_type") - elseif startswith(line, "element") - if !isempty(element_name) - push!(elements, PlyElement(element_name, element_numel, element_props)) - element_props = Vector{AbstractVector}() - end - tok, element_name, element_numel = split(line) - @assert tok == "element" - element_numel = parse(Int,element_numel) - elseif startswith(line, "property") + else tokens = split(line) - @assert tokens[1] == "property" - if tokens[2] == "list" - count_type_name, type_name, prop_name = tokens[3:end] - count_type = ply_type(count_type_name) - type_ = ply_type(type_name) - push!(element_props, ListProperty(prop_name, ply_type(count_type_name), ply_type(type_name))) + length(tokens) > 2 || throw(ErrorException("Bad ply header, line: \"$line\"")) + if tokens[1] == "format" + length(tokens) == 3 || throw(ErrorException("Bad ply header, line: \"$line\"")) + _, format_type, format_version = tokens + if format_version != "1.0" + throw(ErrorException("Expected ply version 1.0, got $format_version")) + end + format = format_type == "ascii" ? Format_ascii : + format_type == "binary_little_endian" ? Format_binary_little : + format_type == "binary_big_endian" ? Format_binary_big : + error("Unknown ply format $format_type") + elseif tokens[1] == "element" + if !isempty(element_name) + push!(elements, PlyElement(element_name, element_numel, element_props)) + element_props = Vector{AbstractVector}() + end + length(tokens) == 3 || throw(ErrorException("Bad ply header, line: \"$line\"")) + _, element_name, element_numel = tokens + element_numel = parse(Int,element_numel) + elseif tokens[1] == "property" + !isempty(element_name) || throw(ErrorException("Bad ply header: property before first element")) + if tokens[2] == "list" + length(tokens) == 5 || throw(ErrorException("Bad ply header, line: \"$line\"")) + count_type_name, type_name, prop_name = tokens[3:end] + count_type = ply_type(count_type_name) + type_ = ply_type(type_name) + push!(element_props, ListProperty(prop_name, ply_type(count_type_name), ply_type(type_name))) + else + length(tokens) == 3 || throw(ErrorException("Bad ply header, line: \"$line\"")) + type_name, prop_name = tokens[2:end] + push!(element_props, ArrayProperty(prop_name, ply_type(type_name))) + end else - type_name, prop_name = tokens[2:end] - push!(element_props, ArrayProperty(prop_name, ply_type(type_name))) + throw(ErrorException("Bad ply header, line: \"$line\"")) end end end - push!(elements, PlyElement(element_name, element_numel, element_props)) + if !isempty(element_name) + push!(elements, PlyElement(element_name, element_numel, element_props)) + end elements, format, comments end diff --git a/src/types.jl b/src/types.jl index c385190..d44d971 100644 --- a/src/types.jl +++ b/src/types.jl @@ -9,7 +9,7 @@ Return the name that `data` is associated with when serialized in a ply file function plyname end -typealias PropNameList Union{AbstractVector,Tuple} +@compat const PropNameList = Union{AbstractVector,Tuple} #-------------------------------------------------- """ @@ -41,7 +41,7 @@ Base.summary(prop::ArrayProperty) = "$(length(prop))-element $(typeof(prop)) \"$ Base.size(prop::ArrayProperty) = size(prop.data) Base.getindex(prop::ArrayProperty, i::Int) = prop.data[i] Base.setindex!(prop::ArrayProperty, v, i::Int) = prop.data[i] = v -Base.linearindexing(prop::ArrayProperty) = Base.LinearFast() +@compat Base.IndexStyle(::Type{<:ArrayProperty}) = IndexLinear() # List methods Base.resize!(prop::ArrayProperty, len) = resize!(prop.data, len) @@ -80,7 +80,7 @@ Base.summary(prop::ListProperty) = "$(length(prop))-element $(typeof(prop)) \"$( Base.length(prop::ListProperty) = length(prop.start_inds)-1 Base.size(prop::ListProperty) = (length(prop),) Base.getindex(prop::ListProperty, i::Int) = prop.data[prop.start_inds[i]:prop.start_inds[i+1]-1] -Base.linearindexing(prop::ListProperty) = Base.LinearFast() +@compat Base.IndexStyle(::Type{<:ListProperty}) = IndexLinear() # TODO: Do we need Base.setindex!() ? Hard to provide with above formulation... # List methods @@ -198,7 +198,7 @@ Ply() = Ply(Vector{PlyElement}(), Vector{String}()) function Base.show(io::IO, ply::Ply) buf = IOBuffer() write_header(ply, buf, true) - headerstr = takebuf_string(buf) + headerstr = String(take!(buf)) headerstr = replace(strip(headerstr), "\n", "\n ") print(io, "$Ply with header:\n $headerstr") end diff --git a/test/runtests.jl b/test/runtests.jl index c861a25..0556379 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,7 @@ using PlyIO using StaticArrays using Base.Test +using Compat @testset "PlyIO" begin @@ -22,7 +23,7 @@ using Base.Test buf = IOBuffer() save_ply(ply, buf, ascii=true) - str = takebuf_string(buf) + str = String(take!(buf)) open("simple_test_tmp.ply", "w") do fid write(fid, str) end @@ -58,7 +59,7 @@ end buf = IOBuffer() save_ply(ply, buf, ascii=true) - str = takebuf_string(buf) + str = String(take!(buf)) open("empty_test_tmp.ply", "w") do fid write(fid, str) end @@ -114,7 +115,7 @@ end UInt8, UInt16, UInt32, UInt64, Float32, Float64] ply = Ply() - arrayprop = zeros(proptype, 1) + 42 + arrayprop = fill(proptype(42), 1) listprop = ListProperty("listprop", proptype<:Integer ? proptype : Int32, proptype) push!(listprop, collect(proptype, 1:10)) push!(ply, PlyElement("test", ArrayProperty("arrayprop", arrayprop), listprop)) @@ -141,7 +142,7 @@ end )) buf = IOBuffer() save_ply(ply, buf, ascii=true) - str = takebuf_string(buf) + str = String(take!(buf)) open("SVector_properties_test_tmp.ply", "w") do fid write(fid, str) end @@ -164,4 +165,52 @@ end end +@testset "Malformed ply headers" begin + @test_throws ErrorException load_ply(IOBuffer("asdf")) + + @test_throws ErrorException load_ply(IOBuffer("ply")) + + @test_throws ErrorException load_ply(IOBuffer(""" + ply + format ascii 2.0 + """)) + + @test_throws ErrorException load_ply(IOBuffer(""" + ply + format 1.0 + end_header""")) + + @test_throws ErrorException load_ply(IOBuffer(""" + ply + format ascii 1.0 + asdf + end_header""")) + + @test_throws ErrorException load_ply(IOBuffer(""" + ply + format ascii 1.0 + element el + end_header""")) + + @test_throws ErrorException load_ply(IOBuffer(""" + ply + format ascii 1.0 + property float x + end_header""")) + + @test_throws ErrorException load_ply(IOBuffer(""" + ply + format ascii 1.0 + element el 0 + property + end_header""")) + + @test_throws ErrorException load_ply(IOBuffer(""" + ply + format ascii 1.0 + element el 0 + property list + end_header""")) +end + end # @testset PlyIO