[QUIZ] Quoted Printable (#23) SOLUTION

Here is my partial solution for the Quoted Printable quiz. I'm still
pretty new to Ruby, so it took me a while to get what you see here. I
think the only thing I didn't get to adding was line length checks.

#!/usr/bin/env ruby

···

#
# TODO:
# - Limit lines to LINE_MAX_LENGTH during encoding.

require 'optparse'

# Global constants
XML_ENTITIES = %w(< > &)
LINE_END_PAIR = "\r\n"
LINE_CONTINUATION = "=\r\n"
LINE_MAX_LENGTH = 76

class String
    def qp_decode()
        result = ''
        # output portions of line, alternating normal text and encoded bytes
        left = 0
        while right = index('=', left) do
            result << slice(left ... right) # if right > left
            result << qp_decode_byte( slice(right, 3) )
            left = right + 3
        end
        # add remainder of line
        result << slice(left .. -1) if slice(left)
        # finished
        result
    end

    def qp_encode(handleXmlEntities)
        # preserve trailing whitespace for later
        trimmed = rstrip
        trail_ws = slice(trimmed.length .. -1)
        # encode characters on line
        result = ''
        trimmed.each_byte do |c|
            if handleXmlEntities and XML_ENTITIES.include?(c.chr)
                result << qp_encode_byte(c)
            else
                case c
                when 9, 32..60, 62..126
                    result << c
                else
                    result << qp_encode_byte(c)
                end
            end
        end
        # append trailing whitespace
        trail_ws.each_byte { |c| result << qp_encode_byte(c) }
        # finished
        result
    end

    def qp_decode_byte(s)
        s[1..-1].to_i(16)
    end

    def qp_encode_byte(c)
        '=' + (c < 10 ? '0' : '') + c.to_s(16).upcase
    end

    private :qp_decode_byte, :qp_encode_byte
end

class IO
    def qp_decode
        each_line { |line| $stdout.puts line.chomp.qp_decode } #
outputs native eol
    end

    def qp_encode(xmlEncode)
        each_line { |line| $stdout << line.chomp.qp_encode(xmlEncode)
<< LINE_END_PAIR }
    end
end

class QuotedPrintable
    def process(file)
        @decode ? file.qp_decode : file.qp_encode(@xmlEncode)
    end
    attr_writer :decode, :xmlEncode
end

# Main code from here down...
qp = QuotedPrintable.new

# Option Processing
opts = OptionParser.new
opts.on('-x') { qp.xmlEncode = true }
opts.on('-d') { qp.decode = true }
files = opts.parse(ARGV)

# File Processing
files.collect! { |f| File.new(f) }
files = [$stdin] if files.empty?
files.each { |f| qp.process(f) }

--
Matthew Moss <matthew.moss@gmail.com>

Matthew Moss wrote:

Here is my partial solution for the Quoted Printable quiz. I'm still
pretty new to Ruby, so it took me a while to get what you see here. I
think the only thing I didn't get to adding was line length checks.

And here's mine as well. Sorry for being late -- I coded this up on Friday and forgot about it until today.

It ought to handle everything correctly (including proper wrapping of lines that end in encoded characters) and it does most of the work with a few simple regular expressions.

quoted_printable.rb (2.36 KB)