Home » Fusion Middleware & Colab Suite » Weblogic & Application Server » BASE64_PKG - PL/SQL package to generate MIME-encoding
BASE64_PKG - PL/SQL package to generate MIME-encoding [message #76247] Tue, 27 November 2001 11:05 Go to next message
Brian Shensky
Messages: 1
Registered: November 2001
Junior Member
BASE64_PKG - PL/SQL package to generate 7-bit MIME encoding for a BLOB - suitable for use to include a BLOB as an enclosure in conjunction with UTL_SMTP. This version is terribly slow, but it does work...

Package BASE64_PKG IS
type vcarray is table of varchar2(76) index by binary_integer ;
--
function to_base64 ( p_blob_in in blob ) return number ;
function get_line ( p_line_num in number ) return varchar2 ;
function num_lines return number ;
end;

Package Body BASE64_PKG IS
--
-- THIS PACKAGE IS NOT THREAD SAFE!
-- (do NOT try to manipulate more than one blob at once)
--
l_line vcarray ;
l_num_lines integer := 0 ;
--
l_chunklength_8 constant integer := 57 ; -- becomes length=76 in b64 encode chars
l_chunklength_6 constant integer := 76 ; -- standard length of b64 chunk in an email message
--
function hex_to_num ( v_hex varchar2 ) return number is
hex varchar2(4);
num1 number;
num2 number;
begin
hex := substrb(v_hex,1,1);
if ( hex >= '0' and hex <= '9' ) then
num1 := to_number(hex);
end if;
if hex = 'A' then num1 := 10; end if;
if hex = 'B' then num1 := 11; end if;
if hex = 'C' then num1 := 12; end if;
if hex = 'D' then num1 := 13; end if;
if hex = 'E' then num1 := 14; end if;
if hex = 'F' then num1 := 15; end if;
--
hex := substrb(v_hex,2,1);
if ( hex >= '0' and hex <= '9' ) then
num2 := to_number(hex);
end if;
if hex = 'A' then num2 := 10; end if;
if hex = 'B' then num2 := 11; end if;
if hex = 'C' then num2 := 12; end if;
if hex = 'D' then num2 := 13; end if;
if hex = 'E' then num2 := 14; end if;
if hex = 'F' then num2 := 15; end if;
--
return ( (num1*16)+num2 ) ;
end;
--
function bin_to_chr ( p_bin in varchar2 ) return char is
begin
if ( p_bin = '000000' ) then return ( 'A' ) ; end if ;
if ( p_bin = '000001' ) then return ( 'B' ) ; end if ;
if ( p_bin = '000010' ) then return ( 'C' ) ; end if ;
if ( p_bin = '000011' ) then return ( 'D' ) ; end if ;
if ( p_bin = '000100' ) then return ( 'E' ) ; end if ;
if ( p_bin = '000101' ) then return ( 'F' ) ; end if ;
if ( p_bin = '000110' ) then return ( 'G' ) ; end if ;
if ( p_bin = '000111' ) then return ( 'H' ) ; end if ;
if ( p_bin = '001000' ) then return ( 'I' ) ; end if ;
if ( p_bin = '001001' ) then return ( 'J' ) ; end if ;
if ( p_bin = '001010' ) then return ( 'K' ) ; end if ;
if ( p_bin = '001011' ) then return ( 'L' ) ; end if ;
if ( p_bin = '001100' ) then return ( 'M' ) ; end if ;
if ( p_bin = '001101' ) then return ( 'N' ) ; end if ;
if ( p_bin = '001110' ) then return ( 'O' ) ; end if ;
if ( p_bin = '001111' ) then return ( 'P' ) ; end if ;
if ( p_bin = '010000' ) then return ( 'Q' ) ; end if ;
if ( p_bin = '010001' ) then return ( 'R' ) ; end if ;
if ( p_bin = '010010' ) then return ( 'S' ) ; end if ;
if ( p_bin = '010011' ) then return ( 'T' ) ; end if ;
if ( p_bin = '010100' ) then return ( 'U' ) ; end if ;
if ( p_bin = '010101' ) then return ( 'V' ) ; end if ;
if ( p_bin = '010110' ) then return ( 'W' ) ; end if ;
if ( p_bin = '010111' ) then return ( 'X' ) ; end if ;
if ( p_bin = '011000' ) then return ( 'Y' ) ; end if ;
if ( p_bin = '011001' ) then return ( 'Z' ) ; end if ;
if ( p_bin = '011010' ) then return ( 'a' ) ; end if ;
if ( p_bin = '011011' ) then return ( 'b' ) ; end if ;
if ( p_bin = '011100' ) then return ( 'c' ) ; end if ;
if ( p_bin = '011101' ) then return ( 'd' ) ; end if ;
if ( p_bin = '011110' ) then return ( 'e' ) ; end if ;
if ( p_bin = '011111' ) then return ( 'f' ) ; end if ;
if ( p_bin = '100000' ) then return ( 'g' ) ; end if ;
if ( p_bin = '100001' ) then return ( 'h' ) ; end if ;
if ( p_bin = '100010' ) then return ( 'i' ) ; end if ;
if ( p_bin = '100011' ) then return ( 'j' ) ; end if ;
if ( p_bin = '100100' ) then return ( 'k' ) ; end if ;
if ( p_bin = '100101' ) then return ( 'l' ) ; end if ;
if ( p_bin = '100110' ) then return ( 'm' ) ; end if ;
if ( p_bin = '100111' ) then return ( 'n' ) ; end if ;
if ( p_bin = '101000' ) then return ( 'o' ) ; end if ;
if ( p_bin = '101001' ) then return ( 'p' ) ; end if ;
if ( p_bin = '101010' ) then return ( 'q' ) ; end if ;
if ( p_bin = '101011' ) then return ( 'r' ) ; end if ;
if ( p_bin = '101100' ) then return ( 's' ) ; end if ;
if ( p_bin = '101101' ) then return ( 't' ) ; end if ;
if ( p_bin = '101110' ) then return ( 'u' ) ; end if ;
if ( p_bin = '101111' ) then return ( 'v' ) ; end if ;
if ( p_bin = '110000' ) then return ( 'w' ) ; end if ;
if ( p_bin = '110001' ) then return ( 'x' ) ; end if ;
if ( p_bin = '110010' ) then return ( 'y' ) ; end if ;
if ( p_bin = '110011' ) then return ( 'z' ) ; end if ;
if ( p_bin = '110100' ) then return ( '0' ) ; end if ;
if ( p_bin = '110101' ) then return ( '1' ) ; end if ;
if ( p_bin = '110110' ) then return ( '2' ) ; end if ;
if ( p_bin = '110111' ) then return ( '3' ) ; end if ;
if ( p_bin = '111000' ) then return ( '4' ) ; end if ;
if ( p_bin = '111001' ) then return ( '5' ) ; end if ;
if ( p_bin = '111010' ) then return ( '6' ) ; end if ;
if ( p_bin = '111011' ) then return ( '7' ) ; end if ;
if ( p_bin = '111100' ) then return ( '8' ) ; end if ;
if ( p_bin = '111101' ) then return ( '9' ) ; end if ;
if ( p_bin = '111110' ) then return ( '+' ) ; end if ;
if ( p_bin = '111111' ) then return ( '/' ) ; end if ;
return ( null ) ;
end ;
--
function bits_to_b64 ( str_bits in varchar2 ) return varchar2 is
str_base64 varchar2(76) := '' ;
bits_length integer ; -- length of str_bits string
bits_mod number ; -- rest of str_bits after division into 6 bits
str_base64_chr char ; -- 6bit chunk part trnsposed to ASCI character
str_6bit char(6) ; -- 6bit chunk part
begin
-- dbms_output.put_line('str_bits: length(str_bits)='||to_char(length(str_bits)));
bits_length := length ( str_bits ) ;
bits_mod := mod ( bits_length, 6 ) ;
-- divide the bits string into 6 bit parts and transpose each 6 bit into the ASCII Base64 character
for i in 0 .. ( floor ( bits_length / 6 ) - 1 ) loop
str_6bit := substr ( str_bits, ( 1 + ( i * 6 ) ), 6 ) ;
str_base64_chr := bin_to_chr ( str_6bit ) ;
str_base64 := str_base64 || str_base64_chr ;
end loop;
-- check if the bits strings has any rest after dividing into 6 bit chunks and if yes generate last
-- byte as defined within Base64 conventions
if ( bits_mod = 2 ) then
str_6bit := substr ( str_bits, bits_length - 2, 2 ) || '0000' ;
str_base64_chr := bin_to_chr ( str_6bit ) ;
str_base64 := str_base64 || str_base64_chr ;
str_base64 := str_base64 || '==' ;
end if;
if ( bits_mod = 4 ) then
str_6bit := substr ( str_bits, bits_length - 4, 4 ) || '00' ;
str_base64_chr := bin_to_chr ( str_6bit ) ;
str_base64 := str_base64 || str_base64_chr ;
str_base64 := str_base64 || '=' ;
end if;
return ( str_base64 ) ;
end ;
--
function bin_to_b64 ( p_chunk in varchar2 ) return varchar2 is
l_chunklen number ;
str_bits varchar2(456) := '' ;
str_byte varchar2(8) ;
numb_byte number ; -- read byte from blob converted into number
byte_part number ; -- read byte decreased by read bits within loop
bit number ; -- read bit
begin
l_chunklen := length ( p_chunk ) ;
-- dbms_output.put_line('bin_to_b64: got chunk, length='||to_char(l_chunklen)) ;
for j in 1..l_chunklen loop
numb_byte := hex_to_num ( substr ( p_chunk, ( ( 2 * ( j - 1 ) ) + 1 ), 2 ) ) ;
byte_part := 0 ;
str_byte := '' ;
-- transform each read byte into a string of 8 chars, each char containing "1" or "0"
for i in 0..7 loop
bit := floor ( ( to_number ( numb_byte ) - byte_part ) / power ( 2, ( 7 - i ) ) ) ;
byte_part := byte_part + ( bit * power ( 2,( 7 - i ) ) ) ;
str_byte := str_byte || to_char ( bit ) ;
end loop;
str_bits := str_bits || str_byte ;
end loop ;
-- send the bitstring to another function to convert to b64 string
return ( bits_to_b64 ( str_bits ) ) ;
end ;
--
function num_lines return number is
begin
return ( l_num_lines ) ;
end ;
--
function to_base64 ( p_blob_in in blob ) return number is
l_blob_size integer ;
l_chunk varchar2(114) ;
l_chunklength_read integer := l_chunklength_8 ;
begin
--
for i in 1..l_num_lines loop
l_line(i) := null ;
end loop ;
--
l_blob_size := dbms_lob.getlength ( p_blob_in ) ;
if ( l_blob_size = 0 ) then
l_num_lines := 0 ;
else
l_num_lines := ceil ( l_blob_size / l_chunklength_8 ) ;
-- dbms_output.put_line('to_base64: l_blob_size='||to_char(l_blob_size)) ;
-- dbms_output.put_line('to_base64: l_num_lines='||to_char(l_num_lines)) ;
--
for i in 1..l_num_lines loop
l_chunk := null ;
-- dbms_output.put_line('to_base64: doing chunk '||to_char( ( ( i - 1 ) * l_chunklength_8 ) + 1 )||'-'||to_char(( ( ( i - 1 ) * l_chunklength_8 ) + 1 ) + 56)) ;
dbms_lob.read ( p_blob_in, l_chunklength_read, ( ( ( i - 1 ) * l_chunklength_8 ) + 1 ), l_chunk ) ;
l_line(i) := bin_to_b64 ( l_chunk ) ;
end loop ;
end if ;
return ( l_num_lines ) ;
end ;
--
function get_line ( p_line_num in number ) return varchar2 is
begin
if ( p_line_num <= l_num_lines ) then
return ( l_line(p_line_num) ) ;
else
return ( null ) ;
end if ;
end ;
end ;

----------- TEST -------------

declare
vblob blob ;
parts number ;
begin
-- get the blob from the table
select content into vblob from blob_table where id = 5 ;
-- dbms_output.put_line('local: bloblength='||to_char(DBMS_LOB.GETLENGTH(vblob)));
-- seed the base64_pkg package matrix with base64 data from the blob
dbms_output.put_line(to_char(sysdate,'HH24:MI:SS'));
parts := base64_pkg.to_base64 ( vblob );
dbms_output.put_line(to_char(sysdate,'HH24:MI:SS'));
-- dbms_output.put_line('parts='||to_char(parts));
-- Now get each "line" from the matrix. The output is email/mime compliant 76 chars wide!
for i in 1..parts loop
dbms_output.put_line(base64_pkg.get_line(i));
end loop ;
dbms_output.put_line(to_char(sysdate,'HH24:MI:SS'));
end;

----------------------------------------------------------------------
Re: BASE64_PKG - PL/SQL package to generate MIME-encoding [message #76285 is a reply to message #76247] Fri, 18 January 2002 00:05 Go to previous message
Anikó Medgyesi
Messages: 1
Registered: January 2002
Junior Member
We are using this package, und this is perfect, but there is a little bug in function bits_to_b64.

bad codes:
str_6bit := substr ( str_bits, bits_length - 2, 2 ) || '0000' ;
and
str_6bit := substr ( str_bits, bits_length - 4, 4 ) || '00' ;

but the good ones:
str_6bit := substr ( str_bits, bits_length - 1, 2 ) || '0000' ;
and
str_6bit := substr ( str_bits, bits_length - 3, 4 ) || '00' ;
Previous Topic: Re: PLSQL toolkit and OAS
Next Topic: Re: ORACLE CERTIFIED PROFESSIONAL TEST EXAM
Goto Forum:
  


Current Time: Thu Mar 28 15:24:17 CDT 2024