1//////////////////////////////////////////////////////////////////////////////// 2// 3// ADOBE SYSTEMS INCORPORATED 4// Copyright 2004-2007 Adobe Systems Incorporated 5// All Rights Reserved. 6// 7// NOTICE: Adobe permits you to use, modify, and distribute this file 8// in accordance with the terms of the license agreement accompanying it. 9// 10//////////////////////////////////////////////////////////////////////////////// 11 12package mx.utils 13{ 14 15import flash.utils.ByteArray; 16 17/** 18 * A utility class to encode a String or ByteArray as a Base64 encoded String. 19 * 20 * @langversion 3.0 21 * @playerversion Flash 9 22 * @playerversion AIR 1.1 23 * @productversion Flex 3 24 */ 25public class Base64Encoder 26{ 27 //-------------------------------------------------------------------------- 28 // 29 // Static Class Variables 30 // 31 //-------------------------------------------------------------------------- 32 33 /** 34 * Constant definition for the string "UTF-8". 35 * 36 * @langversion 3.0 37 * @playerversion Flash 9 38 * @playerversion AIR 1.1 39 * @productversion Flex 3 40 */ 41 public static const CHARSET_UTF_8:String = "UTF-8"; 42 43 /** 44 * The character codepoint to be inserted into the encoded output to 45 * denote a new line if <code>insertNewLines</code> is true. 46 * 47 * The default is <code>10</code> to represent the line feed <code>\n</code>. 48 * 49 * @langversion 3.0 50 * @playerversion Flash 9 51 * @playerversion AIR 1.1 52 * @productversion Flex 3 53 */ 54 public static var newLine:int = 10; 55 56 //-------------------------------------------------------------------------- 57 // 58 // Constructor 59 // 60 //-------------------------------------------------------------------------- 61 62 /** 63 * Constructor. 64 * 65 * @langversion 3.0 66 * @playerversion Flash 9 67 * @playerversion AIR 1.1 68 * @productversion Flex 3 69 */ 70 public function Base64Encoder() 71 { 72 super(); 73 reset(); 74 } 75 76 //-------------------------------------------------------------------------- 77 // 78 // Variables 79 // 80 //-------------------------------------------------------------------------- 81 82 /** 83 * A Boolean flag to control whether the sequence of characters specified 84 * for <code>Base64Encoder.newLine</code> are inserted every 76 characters 85 * to wrap the encoded output. 86 * 87 * The default is true. 88 * 89 * @langversion 3.0 90 * @playerversion Flash 9 91 * @playerversion AIR 1.1 92 * @productversion Flex 3 93 */ 94 public var insertNewLines:Boolean = true; 95 96 //-------------------------------------------------------------------------- 97 // 98 // Public Methods 99 // 100 //-------------------------------------------------------------------------- 101 102 /** 103 * @private 104 */ 105 public function drain():String 106 { 107 var result:String = ""; 108 109 for (var i:uint = 0; i < _buffers.length; i++) 110 { 111 var buffer:Array = _buffers[i] as Array; 112 result += String.fromCharCode.apply(null, buffer); 113 } 114 115 _buffers = []; 116 _buffers.push([]); 117 118 return result; 119 } 120 121 /** 122 * Encodes the characters of a String in Base64 and adds the result to 123 * an internal buffer. Strings must be in ASCII format. 124 * 125 * <p>Subsequent calls to this method add on to the 126 * internal buffer. After all data have been encoded, call 127 * <code>toString()</code> to obtain a Base64 encoded String.</p> 128 * 129 * @param data The String to encode. 130 * @param offset The character position from which to start encoding. 131 * @param length The number of characters to encode from the offset. 132 * 133 * @langversion 3.0 134 * @playerversion Flash 9 135 * @playerversion AIR 1.1 136 * @productversion Flex 3 137 */ 138 public function encode(data:String, offset:uint=0, length:uint=0):void 139 { 140 if (length == 0) 141 length = data.length; 142 143 var currentIndex:uint = offset; 144 145 var endIndex:uint = offset + length; 146 if (endIndex > data.length) 147 endIndex = data.length; 148 149 while (currentIndex < endIndex) 150 { 151 _work[_count] = data.charCodeAt(currentIndex); 152 _count++; 153 154 if (_count == _work.length || endIndex - currentIndex == 1) 155 { 156 encodeBlock(); 157 _count = 0; 158 _work[0] = 0; 159 _work[1] = 0; 160 _work[2] = 0; 161 } 162 currentIndex++; 163 } 164 } 165 166 /** 167 * Encodes the UTF-8 bytes of a String in Base64 and adds the result to an 168 * internal buffer. The UTF-8 information does not contain a length prefix. 169 * Subsequent calls to this method add on to the internal buffer. After all 170 * data have been encoded, call <code>toString()</code> to obtain a Base64 171 * encoded String. 172 * 173 * @param data The String to encode. 174 * 175 * @langversion 3.0 176 * @playerversion Flash 9 177 * @playerversion AIR 1.1 178 * @productversion Flex 3 179 */ 180 public function encodeUTFBytes(data:String):void 181 { 182 var bytes:ByteArray = new ByteArray(); 183 bytes.writeUTFBytes(data); 184 bytes.position = 0; 185 encodeBytes(bytes); 186 } 187 188 /** 189 * Encodes a ByteArray in Base64 and adds the result to an internal buffer. 190 * Subsequent calls to this method add on to the internal buffer. After all 191 * data have been encoded, call <code>toString()</code> to obtain a 192 * Base64 encoded String. 193 * 194 * @param data The ByteArray to encode. 195 * @param offset The index from which to start encoding. 196 * @param length The number of bytes to encode from the offset. 197 * 198 * @langversion 3.0 199 * @playerversion Flash 9 200 * @playerversion AIR 1.1 201 * @productversion Flex 3 202 */ 203 public function encodeBytes(data:ByteArray, offset:uint=0, length:uint=0):void 204 { 205 if (length == 0) 206 length = data.length; 207 208 var oldPosition:uint = data.position; 209 data.position = offset; 210 var currentIndex:uint = offset; 211 212 var endIndex:uint = offset + length; 213 if (endIndex > data.length) 214 endIndex = data.length; 215 216 while (currentIndex < endIndex) 217 { 218 _work[_count] = data[currentIndex]; 219 _count++; 220 221 if (_count == _work.length || endIndex - currentIndex == 1) 222 { 223 encodeBlock(); 224 _count = 0; 225 _work[0] = 0; 226 _work[1] = 0; 227 _work[2] = 0; 228 } 229 currentIndex++; 230 } 231 232 data.position = oldPosition; 233 } 234 235 /** 236 * @private 237 */ 238 public function flush():String 239 { 240 if (_count > 0) 241 encodeBlock(); 242 243 var result:String = drain(); 244 reset(); 245 return result; 246 } 247 248 /** 249 * Clears all buffers and resets the encoder to its initial state. 250 * 251 * @langversion 3.0 252 * @playerversion Flash 9 253 * @playerversion AIR 1.1 254 * @productversion Flex 3 255 */ 256 public function reset():void 257 { 258 _buffers = []; 259 _buffers.push([]); 260 _count = 0; 261 _line = 0; 262 _work[0] = 0; 263 _work[1] = 0; 264 _work[2] = 0; 265 } 266 267 /** 268 * Returns the current buffer as a Base64 encoded String. Note that 269 * calling this method also clears the buffer and resets the 270 * encoder to its initial state. 271 * 272 * @return The Base64 encoded String. 273 * 274 * @langversion 3.0 275 * @playerversion Flash 9 276 * @playerversion AIR 1.1 277 * @productversion Flex 3 278 */ 279 public function toString():String 280 { 281 return flush(); 282 } 283 284 //-------------------------------------------------------------------------- 285 // 286 // Private Methods 287 // 288 //-------------------------------------------------------------------------- 289 290 /** 291 * @private 292 */ 293 private function encodeBlock():void 294 { 295 var currentBuffer:Array = _buffers[_buffers.length - 1] as Array; 296 if (currentBuffer.length >= MAX_BUFFER_SIZE) 297 { 298 currentBuffer = []; 299 _buffers.push(currentBuffer); 300 } 301 302 currentBuffer.push(ALPHABET_CHAR_CODES[(_work[0] & 0xFF) >> 2]); 303 currentBuffer.push(ALPHABET_CHAR_CODES[((_work[0] & 0x03) << 4) | ((_work[1] & 0xF0) >> 4)]); 304 305 if (_count > 1) 306 currentBuffer.push(ALPHABET_CHAR_CODES[((_work[1] & 0x0F) << 2) | ((_work[2] & 0xC0) >> 6) ]); 307 else 308 currentBuffer.push(ESCAPE_CHAR_CODE); 309 310 if (_count > 2) 311 currentBuffer.push(ALPHABET_CHAR_CODES[_work[2] & 0x3F]); 312 else 313 currentBuffer.push(ESCAPE_CHAR_CODE); 314 315 if (insertNewLines) 316 { 317 if ((_line += 4) == 76) 318 { 319 currentBuffer.push(newLine); 320 _line = 0; 321 } 322 } 323 } 324 325 //-------------------------------------------------------------------------- 326 // 327 // Private Variables 328 // 329 //-------------------------------------------------------------------------- 330 331 /** 332 * An Array of buffer Arrays. 333 * 334 * @langversion 3.0 335 * @playerversion Flash 9 336 * @playerversion AIR 1.1 337 * @productversion Flex 3 338 */ 339 private var _buffers:Array; 340 private var _count:uint; 341 private var _line:uint; 342 private var _work:Array = [ 0, 0, 0 ]; 343 344 /** 345 * This value represents a safe number of characters (i.e. arguments) that 346 * can be passed to String.fromCharCode.apply() without exceeding the AVM+ 347 * stack limit. 348 * 349 * @private 350 */ 351 public static const MAX_BUFFER_SIZE:uint = 32767; 352 353 private static const ESCAPE_CHAR_CODE:Number = 61; // The '=' char 354 355 /* 356 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 357 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 358 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 359 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 360 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 361 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 362 'w', 'x', 'y', 'z', '0', '1', '2', '3', 363 '4', '5', '6', '7', '8', '9', '+', '/' 364 */ 365 private static const ALPHABET_CHAR_CODES:Array = 366 [ 367 65, 66, 67, 68, 69, 70, 71, 72, 368 73, 74, 75, 76, 77, 78, 79, 80, 369 81, 82, 83, 84, 85, 86, 87, 88, 370 89, 90, 97, 98, 99, 100, 101, 102, 371 103, 104, 105, 106, 107, 108, 109, 110, 372 111, 112, 113, 114, 115, 116, 117, 118, 373 119, 120, 121, 122, 48, 49, 50, 51, 374 52, 53, 54, 55, 56, 57, 43, 47 375 ]; 376 377} 378 379} 380