lib/digest/ed2k.rb in digest-ed2k-hash-0.2.0 vs lib/digest/ed2k.rb in digest-ed2k-hash-0.3.0
- old
+ new
@@ -23,15 +23,11 @@
# Hash an IO object.
#
# @param [IO] io the IO object that will be read
# @return self to allow method chaining
def io(io)
- while (buf = io.read(CHUNK_SIZE))
- self << buf
- end
-
- self
+ self << io
end
# Calculate the hash of a file.
#
# @param [String] path the file that will be read
@@ -44,73 +40,82 @@
#
# @return self the reset digest object
def reset
@md4.reset
@finalized = false
- @small = true
- @buf = ''
self
end
# Rehash with new data.
#
- # @param [String] data the chunk of data to add to the hash
+ # @param [String, IO] data the chunk of data to add to the hash
# @return self to allow method chaining
# @raise RuntimeError if the digest object has been finalized
def update(data)
raise RuntimeError if @finalized
- @buf += data
- hash
+ # get the IO object
+ buf = to_io(data)
+ # if the chunk is smaller than CHUNK_SIZE just return the MD4 hash
+ if buf.size < CHUNK_SIZE
+ @md4 << buf.read
+ else
+ # read chunks from the IO object and update the MD4 hash
+ while (chunk = buf.read(CHUNK_SIZE))
+ @md4 << MD4.digest(chunk)
+ end
+
+ # weird EDonkey bug requires multiples of CHUNK_SIZE
+ # to append one additional MD4 hash
+ @md4 << MD4.new.digest if multiple?(buf.size)
+ end
+
self
end
alias << update
- # Finalize the digest.
+ # Finalize the hash and return the digest.
#
- # @param [String] str use this string to digest,
- # otherwise digest the current md4 hash
- def digest(str = nil)
- if str.nil?
+ # If no string is provided, the current hash is used
+ #
+ # @param [String, IO] data hash this chunk of data
+ def digest(data = nil)
+ if data.nil?
finish
@md4.digest
else
reset
- self << str
+ self << data
digest
end
end
- # {include:#digest}
- def hexdigest(str = nil)
- if str.nil?
+ # Finalize the hash and return the hexdigest.
+ #
+ # If no string is provided, the current hash is used
+ #
+ # @param [String, IO] data hash this chunk of data
+ def hexdigest(data = nil)
+ if data.nil?
finish
@md4.hexdigest
else
reset
- self << str
+ self << data
hexdigest
end
end
# Finalize the hash.
#
# @return self to allow method chaining
def finish
- unless @finalized
- @md4 << if @small
- @buf
- else
- MD4.digest(@buf)
- end
+ @finalized = true unless @finalized
- @finalized = true
- end
-
self
end
# Shows the current state and the digest class.
# If the digest is finalized, it shows the hexdigest.
@@ -120,43 +125,53 @@
end
class << self
# Calculate the digest of a string.
#
- # @param [String] str the string to digest
+ # @param [String, IO] data the string to digest
# @return a finalized digest object
- def digest(str)
- new.digest(str)
+ def digest(data)
+ new.digest(data)
end
# Calculate the hexdigest of a string.
- # @param [String] str the string to digest
+ #
+ # @param [String, IO] data the string to digest
# @return a finalized digest object
- def hexdigest(str)
- new.hexdigest(str)
+ def hexdigest(data)
+ new.hexdigest(data)
end
# Create a new digest object from a IO object.
+ #
# @param [IO] io the IO object to read
# @return a new digest object
def io(io)
new.io(io)
end
# Create a new digest object from a file.
- # @param [String] file the file to read
+ #
+ # @param [String] path the file to read
# @return a new digest object
def file(path)
new.file(path)
end
end
private
- def hash
- while @buf.size >= CHUNK_SIZE
- @small = false
- @md4 << MD4.digest(@buf.slice!(0...CHUNK_SIZE))
+ def to_io(obj)
+ if obj.is_a? String
+ StringIO.new(obj)
+ elsif obj.is_a? IO
+ obj
+ else
+ raise ArgumentError, "cannot hash #{obj.class.name} object"
end
+ end
+
+ def multiple?(buf_size)
+ (buf_size % CHUNK_SIZE).zero?
end
end
end