#--
-# $Id: eet.rb 3 2005-03-26 19:59:05Z tilman $
+# $Id: eet.rb 59 2005-06-08 16:13:15Z tilman $
#
# Copyright (c) 2005 Tilman Sauerbeck (tilman at code-monkey de)
#
require "eet_ext"
class Object
- # :call-seq:
- # object.to_eet -> string
- #
- # Serializes the receiver to EET format.
- def to_eet
- props = to_eet_properties
-
- unless props.is_a?(Hash) && !props.empty?
- raise(Eet::PropertyError, "invalid EET properties")
- end
-
- eet_name = to_eet_name
-
- if eet_name.to_str.length < 1 || eet_name.to_str.include?(0)
- raise(Eet::NameError, "invalid EET name")
- end
-
- stream = Eet::Stream.new
-
- props.each_pair do |tag, arg|
- unless arg.is_a?(Array)
- raise(Eet::PropertyError, "hash value not an array")
- end
-
- value, type = arg
- next if value.nil?
-
- stream.push(*value.to_eet_chunks(tag, type))
- end
-
- chunk = Eet::Chunk.new(eet_name, stream.serialize)
- Eet::Stream.new(chunk).serialize
- end
-
def to_eet_chunks(tag, type = nil) # :nodoc:
[Eet::Chunk.new(tag, to_eet)]
end
end
end
-class Float # :nodoc:
- def to_eet_chunks(tag, type = nil)
- fmt = case type
- when :double: "%32.32f"
- else "%16.16f"
- end
-
- data = fmt % self
- [Eet::Chunk.new(tag, data + "\0")]
- end
-end
-
class String # :nodoc:
def to_eet_chunks(tag, type = nil)
[Eet::Chunk.new(tag, self + "\0")]
class TrueClass # :nodoc:
def to_eet_chunks(tag, type = nil)
- [Eet::Chunk.new(tag, [1].pack("c"))]
+ [Eet::Chunk.new(tag, "\1")]
end
end
class FalseClass # :nodoc:
def to_eet_chunks(tag, type = nil)
- [Eet::Chunk.new(tag, [0].pack("c"))]
+ [Eet::Chunk.new(tag, "\0")]
end
end
end
module Eet
- VERSION = "0.1.0"
+ VERSION = "0.1.3"
- class EetError < StandardError; end
- class NameError < EetError; end
- class PropertyError < EetError; end
class ChunkError < EetError; end
- class Stream < Array # :nodoc:
+ class Stream # :nodoc:
def initialize(chunk = nil)
super(chunk.nil? ? 0 : 1, chunk)
end
- def serialize
- inject("") { |a, c| a << c.serialize }
- end
-
def Stream.deserialize(data)
- data = data.to_str.dup
+ if data.to_str.empty?
+ raise(ArgumentError, "buffer is empty")
+ end
+
s = Stream.new
+ offset = 0
+
+ while offset < data.length
+ c, bytes = Chunk.deserialize(data[offset..-1])
- while data.length > 0
- s << Chunk.deserialize(data)
+ s << c
+ offset += bytes
end
s
end
class Chunk # :nodoc:
- attr_reader :tag, :data
-
- def initialize(tag, data)
- if tag.to_str.include?(0)
- raise(ArgumentError,
- "tag must not contain binary zeroes")
- end
-
- @tag = tag.to_str.dup.freeze
- @data = data.to_str.dup.freeze
-
- @size = @tag.length + 1 + @data.length
-
- # libeet uses a signed 32bit integer to store the
- # chunk size, so make sure we don't overflow it
- if @size >= (1 << 31)
- raise(ArgumentError, "tag or data too long")
+ def Chunk.deserialize(data)
+ if data.to_str.empty?
+ raise(ArgumentError, "buffer is empty")
end
- end
- def serialize
- buf = "CHnK"
- buf << [@size].pack("V")
- buf << @tag << "\0" << @data
- end
-
- def Chunk.deserialize(data)
if data.length < 8 || data[0, 4] != "CHnK"
raise(ChunkError, "invalid data")
end
c = Chunk.new(*data[8, size].split("\0", 2))
- data.replace(data[8 + size..-1] || "")
-
- c
+ [c, 8 + size]
end
end
end