Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
julia 0.5
Compat 0.13.0
2 changes: 2 additions & 0 deletions src/PlyIO.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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?
Expand Down
76 changes: 46 additions & 30 deletions src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -56,50 +56,66 @@ 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}()
elements = PlyElement[]
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

Expand Down
8 changes: 4 additions & 4 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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}

#--------------------------------------------------
"""
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
57 changes: 53 additions & 4 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using PlyIO
using StaticArrays
using Base.Test
using Compat

@testset "PlyIO" begin

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand All @@ -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
Expand All @@ -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