Base64 Encoding/Decoding for large files

Help
Bel Od
2004-06-23
2004-06-24
  • Bel Od

    Bel Od - 2004-06-23

    Done! It works!

    //Base64.h

    #include <acdk.h>
    #include <acdk/lang/System.h>
    #include <acdk/io/File.h>
    #include <acdk/io/FileReader.h>
    #include <acdk/io/FileWriter.h>

    #include "Base64DecodingException.h"

    using namespace acdk::io;

    // defining RBase64, Base64Array and RBase64Array
    ACDK_DECL_CLASS(Base64);

    class Base64 : public acdk::lang::Object {

    private:

    public:

        /**
         * Symbol that represents the end of an input stream
         */
        static const int END_OF_INPUT;

        /**
         * A character that is not a valid base 64 character.
         */
        static const int NON_BASE_64;

        /**
         * A character that is not a valid base 64 character.
         */
        static const int NON_BASE_64_WHITESPACE;

        /**
         * A character that is not a valid base 64 character.
         */
        static const int NON_BASE_64_PADDING;

        /**
         * Table of the sixty-four characters that are used as
         * the Base64 alphabet: [A-Za-z0-9+/]
         */
        static const byte base64Chars[];   // decimal 64

        /**
         * Reverse lookup table for the Base64 alphabet.
         * reversebase64Chars[byte] gives n for the nth Base64
         * character or negative if a character is not a Base64 character.
         */
        static signed char reverseBase64Chars[];  // decimal 256

        /**
         * Static initializer (forced) of the reverse lookup table for the Base64 alphabet.
         */
        static bool forceStaticInitOfReverceBase64Chars;

        /**
         * Method to perform the static initialization of the reverse lookup table.
         */
        static bool staticInitOfReverceBase64Chars() {
            // Fill in NON_BASE_64 for all characters to start with
            for (int i=0; i<256; i++){
                reverseBase64Chars[i] = NON_BASE_64;
            }
            // For characters that are base64Chars, adjust
            // the reverse lookup table.
            for (byte j=0; j < 64; j++){
                reverseBase64Chars[base64Chars[j]] = j;
            }
            reverseBase64Chars[' ']  = NON_BASE_64_WHITESPACE;
            reverseBase64Chars['\n'] = NON_BASE_64_WHITESPACE;
            reverseBase64Chars['\r'] = NON_BASE_64_WHITESPACE;
            reverseBase64Chars['\t'] = NON_BASE_64_WHITESPACE;
            reverseBase64Chars['\f'] = NON_BASE_64_WHITESPACE;
            reverseBase64Chars['=']  = NON_BASE_64_PADDING;
            return true;
        };
       
        /**
         * Reads the next (decoded) Base64 character from the input stream.
         * Non Base64 characters are skipped.
         *
         * @param in Stream from which bytes are read.
         * @param throwExceptions Throw an exception if an unexpected character is encountered.
         * @return the next Base64 character from the stream or -1 if there are no more Base64 characters on the stream.
         * @throws IOException if an IO Error occurs.
         * @throws Base64DecodingException if unexpected data is encountered when throwExceptions is specified.
         */
        static int readBase64(RFileReader in, bool throwExceptions) throw (RIOException);

        /**
         * Encode this file in Base64.
         * Line breaks will be inserted every 76 characters.
         *
         * @param fIn File to be encoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @param lineBreaks  Whether to insert line breaks every 76 characters in the output.
         * @throws IOException if an input or output error occurs.
         */
        static void encode(RFile fIn, RFile fOut) throw (RIOException);

        /**
         * Encode this file in Base64.
         *
         * @param fIn File to be encoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @param lineBreaks  Whether to insert line breaks every 76 characters in the output.
         * @throws IOException if an input or output error occurs.
         */
        static void encode(RFile fIn, RFile fOut, bool lineBreaks) throw (RIOException);

        /**
         * Encode data from the InputStream to the OutputStream in Base64.
         *
         * @param in Stream from which to read data that needs to be encoded.
         * @param out Stream to which to write encoded data.
         * @param lineBreaks Whether to insert line breaks every 76 characters in the output.
         * @throws IOException if there is a problem reading or writing.
         */
        static void encode(RFileReader in, RFileWriter out, bool lineBreaks) throw (RIOException);

        /**
         * Decode Base64 encoded data from one file to the other.
         * Characters in the Base64 alphabet, white space and equals sign are
         * expected to be in urlencoded data.  The presence of other characters
         * could be a sign that the data is corrupted.
         *
         * @param fIn File to be decoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @throws IOException if an IO error occurs.
         * @throws Base64DecodingException if unexpected data is encountered.
         */
        static void decode(RFile fIn, RFile fOut) throw (RIOException);

        /**
         * Decode Base64 encoded data from one file to the other.
         * Characters in the Base64 alphabet, white space and equals sign are
         * expected to be in urlencoded data.  The presence of other characters
         * could be a sign that the data is corrupted.
         *
         * @param fIn File to be decoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @param throwExceptions Whether to throw exceptions when unexpected data is encountered.
         * @throws IOException if an IO error occurs.
         * @throws Base64DecodingException if unexpected data is encountered when throwExceptions is specified.
         */
        static void decode(RFile fIn, RFile fOut, bool throwExceptions) throw (RIOException);

         /**
         * Decode Base64 encoded data from the InputStream to the OutputStream.
         * Characters in the Base64 alphabet, white space and equals sign are
         * expected to be in urlencoded data.  The presence of other characters
         * could be a sign that the data is corrupted.
         *
         * @param in Stream from which to read data that needs to be decoded.
         * @param out Stream to which to write decoded data.
         * @param throwExceptions Whether to throw exceptions when unexpected data is encountered.
         * @throws IOException if an IO error occurs.
         * @throws Base64DecodingException if unexpected data is encountered when throwExceptions is specified.
         */
       static void decode(RFileReader in, RFileWriter out, bool throwExceptions) throw (RIOException);

    };

    ==================================

    #include "Base64.h"

    /*
    * Base64 encoding and decoding.
    * This C++ class is a conversion of Base64.java
    * from:
    * Java package com.Ostermiller.util
    * Copyright (C) 2001-2002 Stephen Ostermiller
    * http://ostermiller.org/contact.pl?regarding=Java+Utilities
    *
    * This program is free software; you can redistribute it and/or modify
    * it under the terms of the GNU General Public License as published by
    * the Free Software Foundation; either version 2 of the License, or
    * (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    * GNU General Public License for more details.
    *
    */

    /**
    * Implements Base64 encoding and decoding as defined by RFC 2045: "Multipurpose Internet
    * Mail Extensions (MIME) Part One: Format of Internet Message Bodies" page 23.
    * More information about this class is available from <a target="_top" href=
    * "http://ostermiller.org/utils/Base64.html">ostermiller.org</a>.
    *
    * <blockquote>
    * <p>The Base64 Content-Transfer-Encoding is designed to represent
    * arbitrary sequences of octets in a form that need not be humanly
    * readable.  The encoding and decoding algorithms are simple, but the
    * encoded data are consistently only about 33 percent larger than the
    * unencoded data.  This encoding is virtually identical to the one used
    * in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421.</p>
    *
    * <p>A 65-character subset of US-ASCII is used, enabling 6 bits to be
    * represented per printable character. (The extra 65th character, "=",
    * is used to signify a special processing function.)</p>
    *
    * <p>NOTE:  This subset has the important property that it is represented
    * identically in all versions of ISO 646, including US-ASCII, and all
    * characters in the subset are also represented identically in all
    * versions of EBCDIC. Other popular encodings, such as the encoding
    * used by the uuencode utility, Macintosh binhex 4.0 [RFC-1741], and
    * the base85 encoding specified as part of Level 2 PostScript, do no
    * share these properties, and thus do not fulfill the portability
    * requirements a binary transport encoding for mail must meet.</p>
    *
    * <p>The encoding process represents 24-bit groups of input bits as output
    * strings of 4 encoded characters.  Proceeding from left to right, a
    * 24-bit input group is formed by concatenating 3 8bit input groups.
    * These 24 bits are then treated as 4 concatenated 6-bit groups, each
    * of which is translated into a single digit in the base64 alphabet.
    * When encoding a bit stream via the base64 encoding, the bit stream
    * must be presumed to be ordered with the most-significant-bit first.
    * That is, the first bit in the stream will be the high-order bit in
    * the first 8bit byte, and the eighth bit will be the low-order bit in
    * the first 8bit byte, and so on.</p>
    *
    * <p>Each 6-bit group is used as an index into an array of 64 printable
    * characters.  The character referenced by the index is placed in the
    * output string.  These characters, identified in Table 1, below, are
    * selected so as to be universally representable, and the set excludes
    * characters with particular significance to SMTP (e.g., ".", CR, LF)
    * and to the multipart boundary delimiters defined in RFC 2046 (e.g.,
    * "-").</p>
    * <pre>
    *                  Table 1: The Base64 Alphabet
    *
    *   Value Encoding  Value Encoding  Value Encoding  Value Encoding
    *       0 A            17 R            34 i            51 z
    *       1 B            18 S            35 j            52 0
    *       2 C            19 T            36 k            53 1
    *       3 D            20 U            37 l            54 2
    *       4 E            21 V            38 m            55 3
    *       5 F            22 W            39 n            56 4
    *       6 G            23 X            40 o            57 5
    *       7 H            24 Y            41 p            58 6
    *       8 I            25 Z            42 q            59 7
    *       9 J            26 a            43 r            60 8
    *      10 K            27 b            44 s            61 9
    *      11 L            28 c            45 t            62 +
    *      12 M            29 d            46 u            63 /
    *      13 N            30 e            47 v
    *      14 O            31 f            48 w         (pad) =
    *      15 P            32 g            49 x
    *      16 Q            33 h            50 y
    * </pre>
    * <p>The encoded output stream must be represented in lines of no more
    * than 76 characters each.  All line breaks or other characters no
    * found in Table 1 must be ignored by decoding software.  In base64
    * data, characters other than those in Table 1, line breaks, and other
    * white space probably indicate a transmission error, about which a
    * warning message or even a message rejection might be appropriate
    * under some circumstances.</p>
    *
    * <p>Special processing is performed if fewer than 24 bits are available
    * at the end of the data being encoded.  A full encoding quantum is
    * always completed at the end of a body.  When fewer than 24 input bits
    * are available in an input group, zero bits are added (on the right)
    * to form an integral number of 6-bit groups.  Padding at the end of
    * the data is performed using the "=" character.  Since all base64
    * input is an integral number of octets, only the following cases can
    * arise: (1) the final quantum of encoding input is an integral
    * multiple of 24 bits; here, the final unit of encoded output will be
    * an integral multiple of 4 characters with no "=" padding, (2) the
    * final quantum of encoding input is exactly 8 bits; here, the final
    * unit of encoded output will be two characters followed by two "="
    * padding characters, or (3) the final quantum of encoding input is
    * exactly 16 bits; here, the final unit of encoded output will be three
    * characters followed by one "=" padding character.</p>
    *
    * <p>Because it is used only for padding at the end of the data, the
    * occurrence of any "=" characters may be taken as evidence that the
    * end of the data has been reached (without truncation in transit).  No
    * such assurance is possible, however, when the number of octets
    * transmitted was a multiple of three and no "=" characters are
    * present.</p>
    *
    * <p>Any characters outside of the base64 alphabet are to be ignored in
    * base64-encoded data.</p>
    *
    * <p>Care must be taken to use the proper octets for line breaks if base64
    * encoding is applied directly to text material that has not been
    * converted to canonical form.  In particular, text line breaks must be
    * converted into CRLF sequences prior to base64 encoding.  The
    * important thing to note is that this may be done directly by the
    * encoder rather than in a prior canonicalization step in some
    * implementations.</p>
    *
    * <p>NOTE: There is no need to worry about quoting potential boundary
    * delimiters within base64-encoded bodies within multipart entities
    * because no hyphen characters are used in the base64 encoding.</p>
    * </blockquote>
    */

    // Base64.cpp
    // virtual

    // static
        /**
         * Symbol that represents the end of an input stream
         */
        const int Base64::END_OF_INPUT = -1;

        /**
         * A character that is not a valid base 64 character.
         */
        const int Base64::NON_BASE_64 = -1;

        /**
         * A character that is not a valid base 64 character.
         */
        const int Base64::NON_BASE_64_WHITESPACE = -2;

        /**
         * A character that is not a valid base 64 character.
         */
        const int Base64::NON_BASE_64_PADDING = -3;

        /**
         * Table of the sixty-four characters that are used as
         * the Base64 alphabet: [A-Za-z0-9+/]
         */
        const byte Base64::base64Chars[]  = {
            'A','B','C','D','E','F','G','H',
            'I','J','K','L','M','N','O','P',
            'Q','R','S','T','U','V','W','X',
            'Y','Z','a','b','c','d','e','f',
            'g','h','i','j','k','l','m','n',
            'o','p','q','r','s','t','u','v',
            'w','x','y','z','0','1','2','3',
            '4','5','6','7','8','9','+','/'};

        /**
         * Reverse lookup table for the Base64 alphabet.
         * reversebase64Chars[byte] gives n for the nth Base64
         * character or negative if a character is not a Base64 character.
         */
        signed char Base64::reverseBase64Chars[0x100];

        /**
         * Static initializer (forced) of the reverse lookup table for the Base64 alphabet.
         */
        bool Base64::forceStaticInitOfReverceBase64Chars = staticInitOfReverceBase64Chars();

        /**
         * Reads the next (decoded) Base64 character from the input stream.
         * Non Base64 characters are skipped.
         *
         * @param in Stream from which bytes are read.
         * @param throwExceptions Throw an exception if an unexpected character is encountered.
         * @return the next Base64 character from the stream or -1 if there are no more Base64 characters on the stream.
         * @throws IOException if an IO Error occurs.
         * @throws Base64DecodingException if unexpected data is encountered when throwExceptions is specified.
         */
        int Base64::readBase64(RFileReader in, bool throwExceptions) throw (RIOException) {
            int read;
            int numPadding = 0;
            do {
                read = in->read();
                if (read == Base64::END_OF_INPUT) return Base64::END_OF_INPUT;
                read = Base64::reverseBase64Chars[(byte)read];
                if (throwExceptions && (read == Base64::NON_BASE_64 || (numPadding > 0 && read > Base64::NON_BASE_64))){
                    /*throw new Base64DecodingException (
                        MessageFormat.format(
                            labels.getString("unexpectedchar"),
                            new String[] {
                                "'" + (char)read + "' (0x" + Integer.toHexString(read) + ")"
                            }
                        ),
                        (char)read
                    );*/
                    THROW1(Base64DecodingException, "Unexpected Base64 character while decoding in Base64::readBase64");
                }
                if (read == Base64::NON_BASE_64_PADDING){
                    numPadding++;
                }
            } while (read <= Base64::NON_BASE_64);
            return read;
        }

        /**
         * Encode this file in Base64.
         * Line breaks will be inserted every 76 characters.
         *
         * @param fIn File to be encoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @param lineBreaks  Whether to insert line breaks every 76 characters in the output.
         * @throws IOException if an input or output error occurs.
         */
        void Base64::encode(RFile fIn, RFile fOut) throw (RIOException) {
            Base64::encode(fIn, fOut, true);
        }
       
        /**
         * Encode this file in Base64.
         *
         * @param fIn File to be encoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @param lineBreaks  Whether to insert line breaks every 76 characters in the output.
         * @throws IOException if an input or output error occurs.
         */
        void Base64::encode(RFile fIn, RFile fOut, bool lineBreaks) throw (RIOException) {
            RFileReader in = Nil;
            RFileWriter out = Nil;
            try {
                in = new FileReader(fIn);
                out = new FileWriter(fOut);
                Base64::encode(in, out, lineBreaks);
                in->close();
                in = Nil;
                out->flush();
                out->close();
                out = Nil;
            }
            catch (RIOException ioe){
                if (in != Nil){
                    try {
                        in->close();
                    } catch (RIOException ignore){
                    }
                    in = Nil;
                }
                if (out != Nil){
                    try {
                        out->flush();
                        out->close();
                    } catch (RIOException ignore){
                    }
                    out = Nil;
                }
            }
            /*finally {
                if (in != Nil){
                    try {
                        in.close();
                    } catch (IOException ignore){
                    }
                    in = Nil;
                }
                if (out != Nil){
                    try {
                        out->flush();
                        out->close();
                    } catch (RIOException ignore){
                    }
                    out = Nil;
                }
            }*/
        }
       
        /**
         * Encode data from the InputStream to the OutputStream in Base64.
         *
         * @param in Stream from which to read data that needs to be encoded.
         * @param out Stream to which to write encoded data.
         * @param lineBreaks Whether to insert line breaks every 76 characters in the output.
         * @throws IOException if there is a problem reading or writing.
         */
        void Base64::encode(RFileReader in, RFileWriter out, bool lineBreaks) throw (RIOException) {
            // Base64 encoding converts three bytes of input to
            // four bytes of output
            RintArray inBuffer = new intArray(3);
            int lineCount = 0;

            bool done = false;
            while (!done && (inBuffer[0] = in->read()) != Base64::END_OF_INPUT){
                // Fill the buffer
                inBuffer[1] = in->read();
                inBuffer[2] = in->read();

                // Calculate the out Buffer
                // The first byte of our in buffer will always be valid
                // but we must check to make sure the other two bytes
                // are not END_OF_INPUT before using them.
                // The basic idea is that the three bytes get split into
                // four bytes along these lines:
                //      [AAAAAABB] [BBBBCCCC] [CCDDDDDD]
                // [xxAAAAAA] [xxBBBBBB] [xxCCCCCC] [xxDDDDDD]
                // bytes are considered to be zero when absent.
                // the four bytes are then mapped to common ASCII symbols

                // A's: first six bits of first byte
                out->write(Base64::base64Chars[ inBuffer[0] >> 2 ]);
                if (inBuffer[1] != Base64::END_OF_INPUT){
                    // B's: last two bits of first byte, first four bits of second byte
                    out->write(Base64::base64Chars [(( inBuffer[0] << 4 ) & 0x30) | (inBuffer[1] >> 4) ]);
                    if (inBuffer[2] != Base64::END_OF_INPUT){
                        // C's: last four bits of second byte, first two bits of third byte
                        out->write(Base64::base64Chars [((inBuffer[1] << 2) & 0x3c) | (inBuffer[2] >> 6) ]);
                        // D's: last six bits of third byte
                        out->write(Base64::base64Chars [inBuffer[2] & 0x3F]);
                    } else {
                        // C's: last four bits of second byte
                        out->write(Base64::base64Chars [((inBuffer[1] << 2) & 0x3c)]);
                        // an equals sign for a character that is not a Base64 character
                        out->write('=');
                        done = true;
                    }
                } else {
                    // B's: last two bits of first byte
                    out->write(Base64::base64Chars [(( inBuffer[0] << 4 ) & 0x30)]);
                    // an equal signs for characters that is not a Base64 characters
                    out->write('=');
                    out->write('=');
                    done = true;
                }
                lineCount += 4;
                if (lineBreaks && lineCount >= 76){
                    out->write('\n');
                    lineCount = 0;
                }
            }
            if (lineBreaks && lineCount >= 1){
                out->write('\n');
                lineCount = 0;
            }
            out->flush();
        }

        /**
         * Decode Base64 encoded data from one file to the other.
         * Characters in the Base64 alphabet, white space and equals sign are
         * expected to be in urlencoded data.  The presence of other characters
         * could be a sign that the data is corrupted.
         *
         * @param fIn File to be decoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @throws IOException if an IO error occurs.
         * @throws Base64DecodingException if unexpected data is encountered.
         */
        void Base64::decode(RFile fIn, RFile fOut) throw (RIOException) {
            decode(fIn, fOut, true);
        }

        /**
         * Decode Base64 encoded data from one file to the other.
         * Characters in the Base64 alphabet, white space and equals sign are
         * expected to be in urlencoded data.  The presence of other characters
         * could be a sign that the data is corrupted.
         *
         * @param fIn File to be decoded.
         * @param fOut File to which the results should be written (may be the same as fIn).
         * @param throwExceptions Whether to throw exceptions when unexpected data is encountered.
         * @throws IOException if an IO error occurs.
         * @throws Base64DecodingException if unexpected data is encountered when throwExceptions is specified.
         */
        void Base64::decode(RFile fIn, RFile fOut, bool throwExceptions) throw (RIOException) {
            RFileReader in = Nil;
            RFileWriter out = Nil;
            try {
                in = new FileReader(fIn);
                out = new FileWriter(fOut);
                decode(in, out, throwExceptions);
                in->close();
                in = Nil;
                out->flush();
                out->close();
                out = Nil;
            }
            catch (RIOException ioe){
                if (in != Nil){
                    try {
                        in->close();
                    } catch (RIOException ignore){
                    }
                    in = Nil;
                }
                if (out != Nil){
                    try {
                        out->flush();
                        out->close();
                    } catch (RIOException ignore){
                    }
                    out = Nil;
                }
            }
            /*finally {
                if (in != null){
                    try {
                        in.close();
                    } catch (IOException ignore){
                    }
                    in = null;
                }
                if (out != null){
                    try {
                        out.flush();
                        out.close();
                    } catch (IOException ignore){
                    }
                    out = null;
                }
            }*/
        }

        /**
         * Decode Base64 encoded data from the InputStream to the OutputStream.
         * Characters in the Base64 alphabet, white space and equals sign are
         * expected to be in urlencoded data.  The presence of other characters
         * could be a sign that the data is corrupted.
         *
         * @param in Stream from which to read data that needs to be decoded.
         * @param out Stream to which to write decoded data.
         * @param throwExceptions Whether to throw exceptions when unexpected data is encountered.
         * @throws IOException if an IO error occurs.
         * @throws Base64DecodingException if unexpected data is encountered when throwExceptions is specified.
         */
        void Base64::decode(RFileReader in, RFileWriter out, bool throwExceptions) throw (RIOException) {
            // Base64 decoding converts four bytes of input to three bytes of output
            RintArray inBuffer = new intArray(4);

            // read bytes unmapping them from their ASCII encoding in the process
            // we must read at least two bytes to be able to output anything
            bool done = false;
            while (!done && (inBuffer[0] = Base64::readBase64(in, throwExceptions)) != Base64::END_OF_INPUT
                && (inBuffer[1] = Base64::readBase64(in, throwExceptions)) != Base64::END_OF_INPUT){
                // Fill the buffer
                inBuffer[2] = Base64::readBase64(in, throwExceptions);
                inBuffer[3] = Base64::readBase64(in, throwExceptions);

                // Calculate the output
                // The first two bytes of our in buffer will always be valid
                // but we must check to make sure the other two bytes
                // are not END_OF_INPUT before using them.
                // The basic idea is that the four bytes will get reconstituted
                // into three bytes along these lines:
                // [xxAAAAAA] [xxBBBBBB] [xxCCCCCC] [xxDDDDDD]
                //      [AAAAAABB] [BBBBCCCC] [CCDDDDDD]
                // bytes are considered to be zero when absent.

                // six A and two B
                out->write(inBuffer[0] << 2 | inBuffer[1] >> 4);
                if (inBuffer[2] != Base64::END_OF_INPUT){
                    // four B and four C
                    out->write(inBuffer[1] << 4 | inBuffer[2] >> 2);
                    if (inBuffer[3] != Base64::END_OF_INPUT){
                        // two C and six D
                        out->write(inBuffer[2] << 6 | inBuffer[3]);
                    } else {
                        done = true;
                    }
                } else {
                    done = true;
                }
            }
            out->flush();
        }

    ===================================
    //Base64DecodingException.h
    using namespace acdk::io;

    // Declare Base64DecodingException, derived from Exception
    // Defines also RBase64DecodingException
    ACDK_DECL_THROWABLE(Base64DecodingException, IOException);

    class Base64DecodingException : extends acdk::io::IOException {

    public:

        Base64DecodingException() : IOException() {};

        Base64DecodingException(RString what) : IOException(what) {}
    };

    ======================================

    /**
    * Base64Runner.h
    */

    #include <acdk.h>
    #include <acdk/lang/System.h>
    #include "Base64.h"

    // defining RBase64Runner, Base64RunnerArray and RBase64RunnerArray
    ACDK_DECL_CLASS(Base64Runner);

    class Base64Runner : public acdk::lang::Object {
       
    public:
        Base64Runner() : Object() {}
        static int b64rmain(RStringArray args);

    };

    =======================================

    /**
    * Base64Runner.cpp
    */

    #include "Base64Runner.h"

    //static
    int Base64Runner::b64rmain(RStringArray args) {
      System::out->println("Begin file encoding");
      RString fileToEncode = new String("D:\\temp\\file_to_encode.txt");
      RFile f1 = new File(fileToEncode);
      System::out->println(fileToEncode);
      RString fileEncoded = new String("D:\\temp\\file_encoded.txt");
      System::out->println(fileEncoded);
      RFile f2 = new File(fileEncoded);
      RString fileDecoded = new String("D:\\temp\\file_decoded.txt");
      System::out->println(fileDecoded);
      RFile f3 = new File(fileDecoded);

      System::out->println("Begin file encoding");
      Base64::encode(f1, f2);
      System::out->println("Begin file decoding");
      Base64::decode(f2, f3);
      System::out->println("End file encoding/decoding");
      return 0;
    }

    int main(int argc, char* argv[], char** envptr) {
      return acdk::lang::System::main(Base64Runner::b64rmain, argc, argv, envptr);
    }

     
    • Roger Rene Kommer

      Hi,

      Some criticism to your code ;-)

      > static void encode(RFileReader in, RFileWriter out, bool lineBreaks) throw (RIOException);

      should be transfered to

      static void encode(IN(RReader) in, IN(RWriter) out, bool lineBreaks) THROWS1(RIOException);

      Marking the input parameters in and out is maybe not very important
      here, but if you write a class, which overloads some virtual function
      the IN() tagging is important.
      ACDK_DECL_CLASS(A);

      class A : extends Object {
      public:
      A() {}
      virtual void printIt(IN(RObject) obj) { System::out->println("Via A: " + obj->toString()); }
      };
      class B : extends A
      {
      public:
        B() {}
        virtual void printIt(RObject obj) { System::out->println("Via B: " + obj->toString()); }
      };

      RA a = new B();
      RObject o = new Integer(42);
      a->printIt(o);
      OUTPUT:
      Via A: 42 // virtual methods doesn't work like expected

      A side effect of IN() tagging is speed, because
      the underlying memory management knows, that the calling function owns
      the reference.

      More critical is to use THROWS1(RIOException) instead of throw (RIOException);
      The reason is, that methods may throw other exceptions - like NullPointerException,
      but if it is not declared in the method signature, the application terminates
      immediately. The THROWS1(RIOException) delcarations expand to
      throw(RIOException, ::acdk::lang::RThrowable), so that all ACDK exception can
      be catched (and does not terminate the process), even they ared explizit explicit
      declared in the method.

      In Java a method always can throw RuntimeExceptions (or derived) even without
      declared it in the method signature.

      Another reason to use THROWS1(..) instead of throw(..) is, that some compiler
      doesn't support throw declarations very well. In this cases THROWS1() will simply
      expand to nothing.

      Last issue is more a desing concern:
      In the encoding/decoding implementation only methods of the Reader/Writer interface are used.
      Declaring the methods with FileReader/FileWriter the usage of the Base64 class
      is limited to the usage of the class in connection of files. You cannot use the
      Base64 class for example in connection of a socket stream or a memory reader/writer.

      ...
      static void encode(IN(Reader) in, IN(RWriter) out, bool lineBreaks);

      // reading from inside a ZIP file
      RFile inputFile = new File("d:\\temp\\myZipFile.zip/MyCompressedFile.txt");
      RReader inputReader = inputFile->getReader(); // inputReader is not a FileReader, but
                                                    // a specialized Reader to decompress the MyCompressedFile.txt
                                                    // from the zip file

      RFile outputFile = new File("ftp://my.ftp.server.com/incoming/MyFile.txt");
      RWriter outputWriter = outputFile->getWriter();
      Base64::encode(inputReader, outputWriter); // write it directly on a ftp server

      outputWriter = new MemWriter(); // alternativally write it just into a buffer
      Base64::encode(inputReader, outputWriter);
      RbyteArray buffer = outputWriter->getBuffer();
      // buffer contains the encoded content

      In the acdk_text package there is also a Base64 encoding/decoding class (acdk/acdk_text/src/acdk/text/Base64.h/.cpp, but operates currently only on byteArray's.

      Roger

       
    • Bel Od

      Bel Od - 2004-06-24

      Thanks for your comments, I will take all of them into consideration and I will modify the code accordingly.

       

Log in to post a comment.

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

JavaScript is required for this form.





No, thanks