1 /**
  2  * This file is part of the Web Enabled Audio and Sound Enhancement Library (aka the Weasel audio library) Copyright 2011 - 2013 Warren Willmey. It is covered by the GNU General Public License version 3 as published by the Free Software Foundation, you should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
  3  */
  4 
  5 if( undefined == window.weasel ) window.weasel = {};
  6 
  7 // ---------------------------------------------------------------------------
  8 /** Object to stream encode bytes/ints into a Base64 string.
  9  * 
 10  * @constructor
 11  * 
 12  * @author Warren Willmey 2012
 13  */
 14 weasel.Base64Stream = function( )
 15 {
 16 	this.sBase64Stream = '';
 17 
 18 	this.iBitCount = 0;
 19 	this.iBitStream= 0;
 20 	this.iBytesIn = 0;
 21 	
 22 	this.sBase64StreamSaved = '';
 23 	this.iBitCountSaved = 0;
 24 	this.iBitStreamSaved= 0;
 25 	this.iBytesInSaved = 0;
 26 };
 27 
 28 //---------------------------------------------------------------------------
 29 /** Lookup table of Base64 tokens for easy conversion of byte array to Base64, 
 30  * might be improved by using a 12bit to Base64 pair of chars as opposed to 6bit to single Base64 char.
 31  *  
 32  * @const
 33  * @type {array}
 34  */
 35 weasel.Base64Stream.prototype.aBase64Tokens = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split( '' );
 36 
 37 // ---------------------------------------------------------------------------
 38 /**
 39  * Convert, if there are enough, bits in the stream into Base64 characters.
 40  * 
 41  * @private
 42  */
 43 weasel.Base64Stream.prototype.__convertBitStream = function( )
 44 {
 45 	while( this.iBitCount >= 6 )
 46 	{
 47 		var iTokenNumber = (this.iBitStream >>> ( this.iBitCount - 6 )) & 63;
 48 		this.sBase64Stream += this.aBase64Tokens[ iTokenNumber ];
 49 
 50 		this.iBitCount -= 6;
 51 		this.iBitStream &= 0x7fffffff >>> (31 - this.iBitCount);
 52 	}
 53 };
 54 
 55 // ---------------------------------------------------------------------------
 56 /**
 57  * Append a byte to the Base64 stream.
 58  * 
 59  * @param {int} iByte = Byte of data to append to the stream.
 60  */
 61 weasel.Base64Stream.prototype.appendByte = function( iByte )
 62 {
 63 	this.iBitCount += 8;
 64 	this.iBitStream = ( this.iBitStream << 8) | iByte;
 65 	this.iBytesIn++;
 66 
 67 	this.__convertBitStream();
 68 };
 69 
 70 // ---------------------------------------------------------------------------
 71 /** Append 2 bytes at once to the stream, this is to reduce the overheads of calling
 72  * appendByte() 2 times.
 73  * 
 74  * @param {int} iWord = The 2 bytes you want to append to the stream in format 0x1122.
 75  */
 76 weasel.Base64Stream.prototype.appendWord = function( iWord )
 77 {
 78 	this.iBitCount += 16;
 79 	this.iBitStream = ( this.iBitStream << 16) | iWord;
 80 	this.iBytesIn += 2;
 81 
 82 	this.__convertBitStream();
 83 };
 84 
 85 // ---------------------------------------------------------------------------
 86 /** Append 3 bytes at once to the stream, this is to reduce the overheads of calling
 87  * appendByte() 3 times.
 88  * 
 89  * @param {int} i3Bytes = The 3 bytes you want to append to the stream in format 0x112233.
 90  */
 91 weasel.Base64Stream.prototype.appendTriple = function( i3Bytes )
 92 {
 93 	this.iBitCount += 24;
 94 	this.iBitStream = ( this.iBitStream << 24) | i3Bytes;
 95 	this.iBytesIn += 3;
 96 
 97 	this.__convertBitStream();
 98 };
 99 
100 // ---------------------------------------------------------------------------
101 /**
102  * Complete the Base64 stream (flush all remaining bits and append terminators).
103  * 
104  */
105 weasel.Base64Stream.prototype.flush = function()
106 {
107 	this.__convertBitStream();
108 	
109 	if( 0 != this.iBitCount )
110 	{
111 		var iBitPadding = 6 - this.iBitCount;
112 		this.iBitCount += iBitPadding;
113 		this.iBitStream <<= iBitPadding;
114 
115 		this.__convertBitStream();
116 	}
117 	
118 	// Append terminators.
119 	//
120 	if( 1 == this.iBytesIn % 3 )
121 	{
122 		this.sBase64Stream += '==';
123 	}
124 	else if( 2 == this.iBytesIn % 3 )
125 	{
126 		this.sBase64Stream += '=';
127 	}
128 };
129 
130 // ---------------------------------------------------------------------------
131 /**
132  * Get the generated base encoded string, you should have called flush() before using this.
133  *
134  * @return {string} = The base64 encoded byte stream.
135  */
136 weasel.Base64Stream.prototype.getBase64EncodedString = function()
137 {
138 	return this.sBase64Stream;
139 };
140 
141 // ---------------------------------------------------------------------------
142 /**
143  * Add a non-encoded string to the beginning of the Base64 encoded string, such as the dataURI header.
144  *
145  * @param {string} sString = The string to prepend.
146  * 
147  */
148 weasel.Base64Stream.prototype.prepend = function( sString )
149 {
150 	this.sBase64Stream = sString.concat( this.sBase64Stream );
151 };
152 
153 // ---------------------------------------------------------------------------
154 /**
155  * Save the current state of the base 64 encoding, if you have already saved the state it will be overwritten.
156  *
157  */
158 weasel.Base64Stream.prototype.save = function()
159 {
160 	this.sBase64StreamSaved = this.sBase64Stream;
161 	this.iBitCountSaved = this.iBitCount;
162 	this.iBitStreamSaved= this.iBitStream;
163 	this.iBytesInSaved = this.iBytesIn;
164 	
165 };
166 
167 // ---------------------------------------------------------------------------
168 /**
169  * Load the previously saved state of the base 64 encoding.
170  *
171  */
172 weasel.Base64Stream.prototype.load = function()
173 {
174 	this.sBase64Stream = this.sBase64StreamSaved;
175 	this.iBitCount = this.iBitCountSaved;
176 	this.iBitStream= this.iBitStreamSaved;
177 	this.iBytesIn = this.iBytesInSaved;
178 	
179 };
180