/*
 * Cat decoder example program
 * Version 0.1.0 6SEP2000
 * Copyright 2000, Joe Sunday <sunday@csh.rit.edu>. All Rights Reserved
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 *  SUCH DAMAGE. 
 *
*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

/*
 * Read a string in from the keyboard. Return value is dynamically
 * allocated with malloc() and must be free()d when done.
*/
char* readstring();

/*
 * Decode string from the scanner output into a ascii string. Return
 * value is dynamically allocated with malloc and must be free()d.
*/
char* decode( char* string );

/*
 * Convert c from ascii to the 0-63 values used in the decoding.
*/
char tr( char c );

int main( int argc, char** argv ) {
    char* string;
    char* type;
    char* barcode;
    char* dtype;
    char* dbarcode;
    char* p;
    
    string = readstring();
    p = string;
    while( *p && ( *p != '.' ) ) p++;
    if( *p != '.' ) {
        printf( "Unexpected EOL found\n" );
        exit( 1 );
    }

    p++;
    while( *p && ( *p != '.' ) ) p++;
    if( *p != '.' ) {
        printf( "Unexpected EOL found\n" );
        exit( 1 );
    }
    
    *(p++) = 0;
    type = p;
    while( *p && *p != '.' ) p++;
    if( *p != '.' ) {
        printf( "Unexpected EOL found\n" );
        exit( 1 );
    }
    
    *(p++) = 0;
    barcode = p;
    while( *p && *p != '.' ) p++;
    if( *p != '.' ) {
        printf( "Unexpected EOL found\n" );
        exit( 1 );
    }
    *p = 0;
    dtype = decode( type );
    printf( "%s ", dtype );
    dbarcode = decode( barcode );
    printf( "%s\n", dbarcode );
    free( string );
    return 0;
}

char *readstring( ) {
    char *string;    
    int c;
    int len = 0;
    int maxlen = 50;

    string = (char*) malloc( maxlen );
    c = getc( stdin );                     
    while( (c != EOF) && ( c != '\r' ) &&  ( c != '\n' ) ) {
        string[len] = c;                                          
        len++;
        string[len] = 0;
        if( len == (maxlen - 2) ) {
            char* t = (char*)malloc( maxlen + 50);
            maxlen += 50;
            strncpy( t, string, len );           
            free( string );
            string = t;              
         }
         c = getc( stdin );
     }             
     return string;
}

char *decode( char* string ) {
    char *out;
    char *p;
    char work[4];
    char work2[4];
    int i;
 
    /* Every 4 characters in the input results in 3 characters in the output.*/ 
    i = ( ( strlen( string ) / 4 ) * 3 ) + 3;
    out = (char*)calloc( 1, i );
    p = string;

    while( *p ) {
        bzero( work, 4 );
        for( i = 0; (i < 4) && *p; i++, p++ ) {
            /* Translate every character from ascii to a value between 0-63 */
            work[i] = tr( *p ); 
        }
        /* Take the 6 least significant bits of every block of 4 bytes
         * and compress into a 3 byte string.
        */
        work2[0] = ( ( work[0] << 2 ) & 0xFC ) | ( ( work[1] >> 4 ) & 0x03 );
        work2[1] = ( ( work[1] << 4 ) & 0xF0 ) | ( ( work[2] >> 2 ) & 0x0F );
        work2[2] = ( ( work[2] << 6 ) & 0xC0 ) | ( work[3] & 0x3F );
        work2[3] = 0;
        strncat( out, work2, 3 );
    }
    p = out;
    while( *p ) {
        /* XOR each byte of the output with 'C' */
        *p = *p ^ 'C';
        p++;
    }
    return out;
}

char tr( char c ) {
    char out;
    
    if( (c >= 'a') && (c <= 'z') ) {
        out = c - 'a';
    }
    else if( ( c >= 'A' ) && ( c <= 'Z' ) ) {
        out = c - 'A' + 26;
    }
    else if( ( c >= '0' ) && ( c <= '9' ) ) {
        out = c - '0' + 52;
    }
    else if( c == '+' ) {
        out = 62;
    }
    else if( c == '-' ) {
        out = 63;
    }
    else {
        printf( "Bad character /%c/ in code.\n", c );
    }
    return out;
}

