Daniel Martin
7/18/2006 3:11:00 PM
Fabio Vitale <fabio@sferaconsulting.it> writes:
> Now 3 major questions:
>
> Q 1: what type must I declare for Filename in the class MRKMessage?
Okay, first off I apologize but I lead you astray. Apparently it's
not enough to override bit_length in your subclass. When you read the
file, you're not getting the stuff lined up properly. Therefore I've
decided to make up for it by finishing the rest of your code for you.
Note that now I override round_byte_length instead, and we get:
require 'bit-struct'
class MRKHeader < BitStruct
unsigned :version, 32, "Version", :endian => :native
unsigned :uid_Validity, 32, "UIDValidity", :endian => :native
unsigned :uid_next, 32, "UIDNext", :endian => :native
unsigned :last_write_counter, 32, "LastWriteCounter", :endian => :native
rest :unused, "Unused"
# Override so that it gets padded properly
def MRKHeader.round_byte_length
super
36
end
end
# Ideally, I'd construct some sort of "flags" bit-struct field
# Or define a boolean field type and make this a series of boolean
# fields.
# However, for now we can deal with a series of 0s and 1s
class MRKMessageFlags < BitStruct
unsigned :flagUnused, 2, "Unused"
unsigned :flagSeen, 1, "Seen"
unsigned :flagAnswered, 1, "Answered"
unsigned :flagFlagged, 1, "Flagged"
unsigned :flagDeleted, 1, "Deleted"
unsigned :flagDraft, 1, "Draft"
unsigned :flagRecent, 1, "Recent"
end
class MRKMessage < BitStruct
# Note "text" for nul-terminated strings
text :filename, 23*8, "FileName", :endian => :native
nest :flags, MRKMessageFlags, "Flags"
unsigned :uid, 32, "UID", :endian => :native
unsigned :msg_size, 32, "MsgSize", :endian => :native
unsigned :date, 32, "Date", :endian => :native
# Now we futz with the way that date is set and gotten.
# we rename the existing date field to __date, and
# then we supply our own meaning for "date" that does
# translation into and out of seconds-since-1970
# Again, the ideal solution would be to define a new bit-struct
# field type that did this stuff itself.
alias_method :__date=, :date=
alias_method :__date, :date
def date=(time)
self.__date= time.to_i
end
def date
Time.at(self.__date)
end
# we don't need to override the length computation here
end
File.open("imap.mrk", "rb") {|f|
head_string = f.read(MRKHeader.round_byte_length)
raise "No header!" unless head_string
mrk_header = MRKHeader.new(head_string)
puts mrk_header.inspect
while msg_string = f.read(MRKMessage.round_byte_length) do
puts MRKMessage.new(msg_string).inspect
end
}
__END__
This produces (on the first bit from your file):
#<MRKHeader version=1, uid_Validity=1106138982, uid_next=5825,
last_write_counter=9872,
unused="\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\r\n">
#<MRKMessage filename="md50000004286.msg", flags=#<MRKMessageFlags
flagUnused=0, flagSeen=1, flagAnswered=1, flagFlagged=0,
flagDeleted=0, flagDraft=0, flagRecent=0>, uid=4150, msg_size=20732,
date=Mon Dec 19 12:18:35 Eastern Standard Time 2005>
This is more what you expected, right?