#############################################################################
## Name:        Base64.pm
## Purpose:     XML::Smart::Base64
## Author:      Graciliano M. P.
## Modified by:
## Created:     25/5/2003
## RCS-ID:      
## Copyright:   (c) 2003 Graciliano M. P.
## Licence:     This program is free software; you can redistribute it and/or
##              modify it under the same terms as Perl itself


#############################################################################


## 
## Modified by Harish to fix bugs in xml creation and to errors more readable.
##     Tue Nov  1 21:18:43 IST 2011


############################################################################


package XML::Smart::Base64                                     ;

use strict                                                     ;
use warnings                                                   ;

use Carp                                                       ;

use XML::Smart::Shared qw( _unset_sig_warn _reset_sig_warn )   ;

our $VERSION = '1.3'       ;


my ($BASE64_PM) ;
eval("use MIME::Base64 ()") ;
if ( defined &MIME::Base64::encode_base64 ) { $BASE64_PM = 1 ;}




#################
# ENCODE_BASE64 #
#################

sub encode_base64 {

    my $value   = $_[0] ;
	
    if( $BASE64_PM ) { 
	
	eval { 
	    _unset_sig_warn() ;
	    my $encoded = MIME::Base64::encode_base64( $value  ) ;
	    my $decoded = MIME::Base64::decode_base64( $encoded) ;
	    _reset_sig_warn() ;
	    
	    my $tmp_decoded =  $decoded ;
	    $tmp_decoded    =~ s/\n//g  ;
	    
	    my $tmp_value   =  $value   ;
	    $tmp_value      =~ s/\n//g  ;
	    
	    return $encoded if( $tmp_decoded eq $tmp_value ) ;
	}; 

    }

    { 
	my $encoded     ;
	my $decoded     ;
	my $tmp_value   ;
	my $tmp_decoded ;
	eval {
	    _unset_sig_warn() ;
	    $encoded = _encode_base64_pure_perl( $value   ) ;
	    $decoded = _decode_base64_pure_perl( $encoded ) ;
	    _reset_sig_warn() ;
	
	    $tmp_decoded    =  $decoded ;
	    $tmp_decoded    =~ s/\n//g  ;
	    
	    $tmp_value      =  $value   ;
	    $tmp_value      =~ s/\n//g  ;
	} ; unless( $@ ) {
	    return $encoded if( $tmp_decoded eq $tmp_value ) ;
	}
    }
    
    { 
	_unset_sig_warn() ;
	my $encoded = _encode_ord_special( $value   ) ;
	my $decoded = _decode_ord_special( $encoded ) ;
	_reset_sig_warn() ;
	
	my $tmp_decoded =  $decoded ;
	$tmp_decoded    =~ s/\n//g  ;
	
	my $tmp_value   =  $value   ;
	$tmp_value      =~ s/\n//g  ;
	
	return $encoded if( $tmp_decoded eq $tmp_value ) ;
    }
    


    croak( "Error Encoding\n" ) ;

}

############################
# _ENCODE_BASE64_PURE_PERL #
############################

sub _encode_base64_pure_perl {
    my $res = "";
    my $eol = $_[1];
    $eol = "\n" unless defined $eol;
    pos($_[0]) = 0;                          # ensure start at the beginning
    while ($_[0] =~ /(.{1,45})/gs) {
	my $text = $1 ;
	$res .= substr( pack('u', $text ), 1 ) ;
	chop($res);
    }
    $res =~ tr|` -_|AA-Za-z0-9+/|;               # `# help emacs
    # fix padding at the end
    my $padding = (3 - length($_[0]) % 3) % 3;
    $res =~ s/.{$padding}$/'=' x $padding/e if $padding;
    # break encoded string into lines of no more than 76 characters each
    if (length $eol) {
	$res =~ s/(.{1,76})/$1$eol/g;
    }
    $res;
}



############################
#   _ENCODE_ORD_SPECIAL    #
############################


sub _encode_ord_special { 

    my $value = shift ;

    my @chars = split( //, $value ) ;
    my @ords  ;
    foreach my $char ( @chars ) { 
	push @ords, ord( $char ) ;
    }

    return join( "|", @ords ) ;

}


############################
#   _DECODE_ORD_SPECIAL    #
############################


sub _decode_ord_special {

    my $value = shift ;
    my @ords = split( /\|/, $value ) ;
    my @chars  ;
    foreach my $ord ( @ords ) { 
	push @chars, chr( $ord ) ;
    }

    return join( "", @chars ) ;

}

#################
# DECODE_BASE64 #
#################

sub decode_base64 {
    
    my $value = $_[0] ;

    if( $BASE64_PM ) { 

	eval { 
	    _unset_sig_warn() ;
	    my $decoded = MIME::Base64::decode_base64( $value   ) ;
	    my $encoded = MIME::Base64::encode_base64( $decoded ) ;
	    _reset_sig_warn() ;
	    
	    my $tmp_value   = $value   ;
	    $tmp_value      =~ s/\n//g ;
	    
	    my $tmp_encoded = $encoded ;
	    $tmp_encoded    =~ s/\n//g ;
	    
	    return $decoded if( $tmp_encoded eq $tmp_value  ) ;
	}; 

    }

    {

	my $decoded     ;
	my $encoded     ;
	my $tmp_value   ;
	my $tmp_encoded ;
	eval { 
	    $decoded = _decode_base64_pure_perl( $value     ) ;
	    $encoded = _encode_base64_pure_perl( $decoded   ) ;
	
	    $tmp_value      = $value   ;
	    $tmp_value      =~ s/\n//g ;
	    
	    $tmp_encoded    = $encoded ;
	    $tmp_encoded    =~ s/\n//g ;
	} ; unless( $@ ) { 
	    return $decoded if( $tmp_encoded eq $tmp_value  ) ;
	}
	
    }

    {

	my $decoded = _decode_ord_special( $value     ) ;
	my $encoded = _encode_ord_special( $decoded   ) ;
	
	my $tmp_value   = $value   ;
	$tmp_value      =~ s/\n//g ;
	
	my $tmp_encoded = $encoded ;
	$tmp_encoded    =~ s/\n//g ;
	
	return $decoded if( $tmp_encoded eq $tmp_value  ) ;
	
    }

    croak "Error Decoding $value\n"  ;

}


############################
# _DECODE_BASE64_PURE_PERL #
############################

sub _decode_base64_pure_perl {
  local($^W) = 0 ;
  my $str = shift ;
  my $res = "";

  $str =~ tr|A-Za-z0-9+=/||cd;            # remove non-base64 chars
  if (length($str) % 4) {
	#require Carp;
	#Carp::carp("Length of base64 data not a multiple of 4")
  }
  $str =~ s/=+$//;                        # remove padding
  $str =~ tr|A-Za-z0-9+/| -_|;            # convert to uuencoded format
  while ($str =~ /(.{1,60})/gs) {
	my $len = chr(32 + length($1)*3/4); # compute length byte
	$res .= unpack("u", $len . $1 );    # uudecode
  }
  $res;
}

#######
# END #
#######

1;

