1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.util; 18 19 import android.annotation.UnsupportedAppUsage; 20 import java.io.UnsupportedEncodingException; 21 22 /** 23 * Utilities for encoding and decoding the Base64 representation of 24 * binary data. See RFCs <a 25 * href="http://www.ietf.org/rfc/rfc2045.txt">2045</a> and <a 26 * href="http://www.ietf.org/rfc/rfc3548.txt">3548</a>. 27 */ 28 public class Base64 { 29 /** 30 * Default values for encoder/decoder flags. 31 */ 32 public static final int DEFAULT = 0; 33 34 /** 35 * Encoder flag bit to omit the padding '=' characters at the end 36 * of the output (if any). 37 */ 38 public static final int NO_PADDING = 1; 39 40 /** 41 * Encoder flag bit to omit all line terminators (i.e., the output 42 * will be on one long line). 43 */ 44 public static final int NO_WRAP = 2; 45 46 /** 47 * Encoder flag bit to indicate lines should be terminated with a 48 * CRLF pair instead of just an LF. Has no effect if {@code 49 * NO_WRAP} is specified as well. 50 */ 51 public static final int CRLF = 4; 52 53 /** 54 * Encoder/decoder flag bit to indicate using the "URL and 55 * filename safe" variant of Base64 (see RFC 3548 section 4) where 56 * {@code -} and {@code _} are used in place of {@code +} and 57 * {@code /}. 58 */ 59 public static final int URL_SAFE = 8; 60 61 /** 62 * Flag to pass to {@link Base64OutputStream} to indicate that it 63 * should not close the output stream it is wrapping when it 64 * itself is closed. 65 */ 66 public static final int NO_CLOSE = 16; 67 68 // -------------------------------------------------------- 69 // shared code 70 // -------------------------------------------------------- 71 72 /* package */ static abstract class Coder { 73 public byte[] output; 74 public int op; 75 76 /** 77 * Encode/decode another block of input data. this.output is 78 * provided by the caller, and must be big enough to hold all 79 * the coded data. On exit, this.opwill be set to the length 80 * of the coded data. 81 * 82 * @param finish true if this is the final call to process for 83 * this object. Will finalize the coder state and 84 * include any final bytes in the output. 85 * 86 * @return true if the input so far is good; false if some 87 * error has been detected in the input stream.. 88 */ process(byte[] input, int offset, int len, boolean finish)89 public abstract boolean process(byte[] input, int offset, int len, boolean finish); 90 91 /** 92 * @return the maximum number of bytes a call to process() 93 * could produce for the given number of input bytes. This may 94 * be an overestimate. 95 */ maxOutputSize(int len)96 public abstract int maxOutputSize(int len); 97 } 98 99 // -------------------------------------------------------- 100 // decoding 101 // -------------------------------------------------------- 102 103 /** 104 * Decode the Base64-encoded data in input and return the data in 105 * a new byte array. 106 * 107 * <p>The padding '=' characters at the end are considered optional, but 108 * if any are present, there must be the correct number of them. 109 * 110 * @param str the input String to decode, which is converted to 111 * bytes using the default charset 112 * @param flags controls certain features of the decoded output. 113 * Pass {@code DEFAULT} to decode standard Base64. 114 * 115 * @throws IllegalArgumentException if the input contains 116 * incorrect padding 117 */ decode(String str, int flags)118 public static byte[] decode(String str, int flags) { 119 return decode(str.getBytes(), flags); 120 } 121 122 /** 123 * Decode the Base64-encoded data in input and return the data in 124 * a new byte array. 125 * 126 * <p>The padding '=' characters at the end are considered optional, but 127 * if any are present, there must be the correct number of them. 128 * 129 * @param input the input array to decode 130 * @param flags controls certain features of the decoded output. 131 * Pass {@code DEFAULT} to decode standard Base64. 132 * 133 * @throws IllegalArgumentException if the input contains 134 * incorrect padding 135 */ decode(byte[] input, int flags)136 public static byte[] decode(byte[] input, int flags) { 137 return decode(input, 0, input.length, flags); 138 } 139 140 /** 141 * Decode the Base64-encoded data in input and return the data in 142 * a new byte array. 143 * 144 * <p>The padding '=' characters at the end are considered optional, but 145 * if any are present, there must be the correct number of them. 146 * 147 * @param input the data to decode 148 * @param offset the position within the input array at which to start 149 * @param len the number of bytes of input to decode 150 * @param flags controls certain features of the decoded output. 151 * Pass {@code DEFAULT} to decode standard Base64. 152 * 153 * @throws IllegalArgumentException if the input contains 154 * incorrect padding 155 */ decode(byte[] input, int offset, int len, int flags)156 public static byte[] decode(byte[] input, int offset, int len, int flags) { 157 // Allocate space for the most data the input could represent. 158 // (It could contain less if it contains whitespace, etc.) 159 Decoder decoder = new Decoder(flags, new byte[len*3/4]); 160 161 if (!decoder.process(input, offset, len, true)) { 162 throw new IllegalArgumentException("bad base-64"); 163 } 164 165 // Maybe we got lucky and allocated exactly enough output space. 166 if (decoder.op == decoder.output.length) { 167 return decoder.output; 168 } 169 170 // Need to shorten the array, so allocate a new one of the 171 // right size and copy. 172 byte[] temp = new byte[decoder.op]; 173 System.arraycopy(decoder.output, 0, temp, 0, decoder.op); 174 return temp; 175 } 176 177 /* package */ static class Decoder extends Coder { 178 /** 179 * Lookup table for turning bytes into their position in the 180 * Base64 alphabet. 181 */ 182 private static final int DECODE[] = { 183 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 184 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 185 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 186 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, 187 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 188 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 189 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 190 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 191 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 192 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 193 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 196 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 197 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 198 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 199 }; 200 201 /** 202 * Decode lookup table for the "web safe" variant (RFC 3548 203 * sec. 4) where - and _ replace + and /. 204 */ 205 private static final int DECODE_WEBSAFE[] = { 206 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 207 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 208 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 209 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, 210 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 211 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, 212 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 213 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 214 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 215 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 216 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 217 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 218 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 219 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 220 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 221 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 222 }; 223 224 /** Non-data values in the DECODE arrays. */ 225 private static final int SKIP = -1; 226 private static final int EQUALS = -2; 227 228 /** 229 * States 0-3 are reading through the next input tuple. 230 * State 4 is having read one '=' and expecting exactly 231 * one more. 232 * State 5 is expecting no more data or padding characters 233 * in the input. 234 * State 6 is the error state; an error has been detected 235 * in the input and no future input can "fix" it. 236 */ 237 private int state; // state number (0 to 6) 238 private int value; 239 240 final private int[] alphabet; 241 Decoder(int flags, byte[] output)242 public Decoder(int flags, byte[] output) { 243 this.output = output; 244 245 alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE; 246 state = 0; 247 value = 0; 248 } 249 250 /** 251 * @return an overestimate for the number of bytes {@code 252 * len} bytes could decode to. 253 */ maxOutputSize(int len)254 public int maxOutputSize(int len) { 255 return len * 3/4 + 10; 256 } 257 258 /** 259 * Decode another block of input data. 260 * 261 * @return true if the state machine is still healthy. false if 262 * bad base-64 data has been detected in the input stream. 263 */ process(byte[] input, int offset, int len, boolean finish)264 public boolean process(byte[] input, int offset, int len, boolean finish) { 265 if (this.state == 6) return false; 266 267 int p = offset; 268 len += offset; 269 270 // Using local variables makes the decoder about 12% 271 // faster than if we manipulate the member variables in 272 // the loop. (Even alphabet makes a measurable 273 // difference, which is somewhat surprising to me since 274 // the member variable is final.) 275 int state = this.state; 276 int value = this.value; 277 int op = 0; 278 final byte[] output = this.output; 279 final int[] alphabet = this.alphabet; 280 281 while (p < len) { 282 // Try the fast path: we're starting a new tuple and the 283 // next four bytes of the input stream are all data 284 // bytes. This corresponds to going through states 285 // 0-1-2-3-0. We expect to use this method for most of 286 // the data. 287 // 288 // If any of the next four bytes of input are non-data 289 // (whitespace, etc.), value will end up negative. (All 290 // the non-data values in decode are small negative 291 // numbers, so shifting any of them up and or'ing them 292 // together will result in a value with its top bit set.) 293 // 294 // You can remove this whole block and the output should 295 // be the same, just slower. 296 if (state == 0) { 297 while (p+4 <= len && 298 (value = ((alphabet[input[p] & 0xff] << 18) | 299 (alphabet[input[p+1] & 0xff] << 12) | 300 (alphabet[input[p+2] & 0xff] << 6) | 301 (alphabet[input[p+3] & 0xff]))) >= 0) { 302 output[op+2] = (byte) value; 303 output[op+1] = (byte) (value >> 8); 304 output[op] = (byte) (value >> 16); 305 op += 3; 306 p += 4; 307 } 308 if (p >= len) break; 309 } 310 311 // The fast path isn't available -- either we've read a 312 // partial tuple, or the next four input bytes aren't all 313 // data, or whatever. Fall back to the slower state 314 // machine implementation. 315 316 int d = alphabet[input[p++] & 0xff]; 317 318 switch (state) { 319 case 0: 320 if (d >= 0) { 321 value = d; 322 ++state; 323 } else if (d != SKIP) { 324 this.state = 6; 325 return false; 326 } 327 break; 328 329 case 1: 330 if (d >= 0) { 331 value = (value << 6) | d; 332 ++state; 333 } else if (d != SKIP) { 334 this.state = 6; 335 return false; 336 } 337 break; 338 339 case 2: 340 if (d >= 0) { 341 value = (value << 6) | d; 342 ++state; 343 } else if (d == EQUALS) { 344 // Emit the last (partial) output tuple; 345 // expect exactly one more padding character. 346 output[op++] = (byte) (value >> 4); 347 state = 4; 348 } else if (d != SKIP) { 349 this.state = 6; 350 return false; 351 } 352 break; 353 354 case 3: 355 if (d >= 0) { 356 // Emit the output triple and return to state 0. 357 value = (value << 6) | d; 358 output[op+2] = (byte) value; 359 output[op+1] = (byte) (value >> 8); 360 output[op] = (byte) (value >> 16); 361 op += 3; 362 state = 0; 363 } else if (d == EQUALS) { 364 // Emit the last (partial) output tuple; 365 // expect no further data or padding characters. 366 output[op+1] = (byte) (value >> 2); 367 output[op] = (byte) (value >> 10); 368 op += 2; 369 state = 5; 370 } else if (d != SKIP) { 371 this.state = 6; 372 return false; 373 } 374 break; 375 376 case 4: 377 if (d == EQUALS) { 378 ++state; 379 } else if (d != SKIP) { 380 this.state = 6; 381 return false; 382 } 383 break; 384 385 case 5: 386 if (d != SKIP) { 387 this.state = 6; 388 return false; 389 } 390 break; 391 } 392 } 393 394 if (!finish) { 395 // We're out of input, but a future call could provide 396 // more. 397 this.state = state; 398 this.value = value; 399 this.op = op; 400 return true; 401 } 402 403 // Done reading input. Now figure out where we are left in 404 // the state machine and finish up. 405 406 switch (state) { 407 case 0: 408 // Output length is a multiple of three. Fine. 409 break; 410 case 1: 411 // Read one extra input byte, which isn't enough to 412 // make another output byte. Illegal. 413 this.state = 6; 414 return false; 415 case 2: 416 // Read two extra input bytes, enough to emit 1 more 417 // output byte. Fine. 418 output[op++] = (byte) (value >> 4); 419 break; 420 case 3: 421 // Read three extra input bytes, enough to emit 2 more 422 // output bytes. Fine. 423 output[op++] = (byte) (value >> 10); 424 output[op++] = (byte) (value >> 2); 425 break; 426 case 4: 427 // Read one padding '=' when we expected 2. Illegal. 428 this.state = 6; 429 return false; 430 case 5: 431 // Read all the padding '='s we expected and no more. 432 // Fine. 433 break; 434 } 435 436 this.state = state; 437 this.op = op; 438 return true; 439 } 440 } 441 442 // -------------------------------------------------------- 443 // encoding 444 // -------------------------------------------------------- 445 446 /** 447 * Base64-encode the given data and return a newly allocated 448 * String with the result. 449 * 450 * @param input the data to encode 451 * @param flags controls certain features of the encoded output. 452 * Passing {@code DEFAULT} results in output that 453 * adheres to RFC 2045. 454 */ encodeToString(byte[] input, int flags)455 public static String encodeToString(byte[] input, int flags) { 456 try { 457 return new String(encode(input, flags), "US-ASCII"); 458 } catch (UnsupportedEncodingException e) { 459 // US-ASCII is guaranteed to be available. 460 throw new AssertionError(e); 461 } 462 } 463 464 /** 465 * Base64-encode the given data and return a newly allocated 466 * String with the result. 467 * 468 * @param input the data to encode 469 * @param offset the position within the input array at which to 470 * start 471 * @param len the number of bytes of input to encode 472 * @param flags controls certain features of the encoded output. 473 * Passing {@code DEFAULT} results in output that 474 * adheres to RFC 2045. 475 */ encodeToString(byte[] input, int offset, int len, int flags)476 public static String encodeToString(byte[] input, int offset, int len, int flags) { 477 try { 478 return new String(encode(input, offset, len, flags), "US-ASCII"); 479 } catch (UnsupportedEncodingException e) { 480 // US-ASCII is guaranteed to be available. 481 throw new AssertionError(e); 482 } 483 } 484 485 /** 486 * Base64-encode the given data and return a newly allocated 487 * byte[] with the result. 488 * 489 * @param input the data to encode 490 * @param flags controls certain features of the encoded output. 491 * Passing {@code DEFAULT} results in output that 492 * adheres to RFC 2045. 493 */ encode(byte[] input, int flags)494 public static byte[] encode(byte[] input, int flags) { 495 return encode(input, 0, input.length, flags); 496 } 497 498 /** 499 * Base64-encode the given data and return a newly allocated 500 * byte[] with the result. 501 * 502 * @param input the data to encode 503 * @param offset the position within the input array at which to 504 * start 505 * @param len the number of bytes of input to encode 506 * @param flags controls certain features of the encoded output. 507 * Passing {@code DEFAULT} results in output that 508 * adheres to RFC 2045. 509 */ encode(byte[] input, int offset, int len, int flags)510 public static byte[] encode(byte[] input, int offset, int len, int flags) { 511 Encoder encoder = new Encoder(flags, null); 512 513 // Compute the exact length of the array we will produce. 514 int output_len = len / 3 * 4; 515 516 // Account for the tail of the data and the padding bytes, if any. 517 if (encoder.do_padding) { 518 if (len % 3 > 0) { 519 output_len += 4; 520 } 521 } else { 522 switch (len % 3) { 523 case 0: break; 524 case 1: output_len += 2; break; 525 case 2: output_len += 3; break; 526 } 527 } 528 529 // Account for the newlines, if any. 530 if (encoder.do_newline && len > 0) { 531 output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) * 532 (encoder.do_cr ? 2 : 1); 533 } 534 535 encoder.output = new byte[output_len]; 536 encoder.process(input, offset, len, true); 537 538 assert encoder.op == output_len; 539 540 return encoder.output; 541 } 542 543 /* package */ static class Encoder extends Coder { 544 /** 545 * Emit a new line every this many output tuples. Corresponds to 546 * a 76-character line length (the maximum allowable according to 547 * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>). 548 */ 549 public static final int LINE_GROUPS = 19; 550 551 /** 552 * Lookup table for turning Base64 alphabet positions (6 bits) 553 * into output bytes. 554 */ 555 private static final byte ENCODE[] = { 556 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 557 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 558 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 559 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 560 }; 561 562 /** 563 * Lookup table for turning Base64 alphabet positions (6 bits) 564 * into output bytes. 565 */ 566 private static final byte ENCODE_WEBSAFE[] = { 567 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 568 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 569 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 570 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', 571 }; 572 573 final private byte[] tail; 574 /* package */ int tailLen; 575 private int count; 576 577 final public boolean do_padding; 578 final public boolean do_newline; 579 final public boolean do_cr; 580 final private byte[] alphabet; 581 Encoder(int flags, byte[] output)582 public Encoder(int flags, byte[] output) { 583 this.output = output; 584 585 do_padding = (flags & NO_PADDING) == 0; 586 do_newline = (flags & NO_WRAP) == 0; 587 do_cr = (flags & CRLF) != 0; 588 alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE; 589 590 tail = new byte[2]; 591 tailLen = 0; 592 593 count = do_newline ? LINE_GROUPS : -1; 594 } 595 596 /** 597 * @return an overestimate for the number of bytes {@code 598 * len} bytes could encode to. 599 */ maxOutputSize(int len)600 public int maxOutputSize(int len) { 601 return len * 8/5 + 10; 602 } 603 process(byte[] input, int offset, int len, boolean finish)604 public boolean process(byte[] input, int offset, int len, boolean finish) { 605 // Using local variables makes the encoder about 9% faster. 606 final byte[] alphabet = this.alphabet; 607 final byte[] output = this.output; 608 int op = 0; 609 int count = this.count; 610 611 int p = offset; 612 len += offset; 613 int v = -1; 614 615 // First we need to concatenate the tail of the previous call 616 // with any input bytes available now and see if we can empty 617 // the tail. 618 619 switch (tailLen) { 620 case 0: 621 // There was no tail. 622 break; 623 624 case 1: 625 if (p+2 <= len) { 626 // A 1-byte tail with at least 2 bytes of 627 // input available now. 628 v = ((tail[0] & 0xff) << 16) | 629 ((input[p++] & 0xff) << 8) | 630 (input[p++] & 0xff); 631 tailLen = 0; 632 }; 633 break; 634 635 case 2: 636 if (p+1 <= len) { 637 // A 2-byte tail with at least 1 byte of input. 638 v = ((tail[0] & 0xff) << 16) | 639 ((tail[1] & 0xff) << 8) | 640 (input[p++] & 0xff); 641 tailLen = 0; 642 } 643 break; 644 } 645 646 if (v != -1) { 647 output[op++] = alphabet[(v >> 18) & 0x3f]; 648 output[op++] = alphabet[(v >> 12) & 0x3f]; 649 output[op++] = alphabet[(v >> 6) & 0x3f]; 650 output[op++] = alphabet[v & 0x3f]; 651 if (--count == 0) { 652 if (do_cr) output[op++] = '\r'; 653 output[op++] = '\n'; 654 count = LINE_GROUPS; 655 } 656 } 657 658 // At this point either there is no tail, or there are fewer 659 // than 3 bytes of input available. 660 661 // The main loop, turning 3 input bytes into 4 output bytes on 662 // each iteration. 663 while (p+3 <= len) { 664 v = ((input[p] & 0xff) << 16) | 665 ((input[p+1] & 0xff) << 8) | 666 (input[p+2] & 0xff); 667 output[op] = alphabet[(v >> 18) & 0x3f]; 668 output[op+1] = alphabet[(v >> 12) & 0x3f]; 669 output[op+2] = alphabet[(v >> 6) & 0x3f]; 670 output[op+3] = alphabet[v & 0x3f]; 671 p += 3; 672 op += 4; 673 if (--count == 0) { 674 if (do_cr) output[op++] = '\r'; 675 output[op++] = '\n'; 676 count = LINE_GROUPS; 677 } 678 } 679 680 if (finish) { 681 // Finish up the tail of the input. Note that we need to 682 // consume any bytes in tail before any bytes 683 // remaining in input; there should be at most two bytes 684 // total. 685 686 if (p-tailLen == len-1) { 687 int t = 0; 688 v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4; 689 tailLen -= t; 690 output[op++] = alphabet[(v >> 6) & 0x3f]; 691 output[op++] = alphabet[v & 0x3f]; 692 if (do_padding) { 693 output[op++] = '='; 694 output[op++] = '='; 695 } 696 if (do_newline) { 697 if (do_cr) output[op++] = '\r'; 698 output[op++] = '\n'; 699 } 700 } else if (p-tailLen == len-2) { 701 int t = 0; 702 v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) | 703 (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2); 704 tailLen -= t; 705 output[op++] = alphabet[(v >> 12) & 0x3f]; 706 output[op++] = alphabet[(v >> 6) & 0x3f]; 707 output[op++] = alphabet[v & 0x3f]; 708 if (do_padding) { 709 output[op++] = '='; 710 } 711 if (do_newline) { 712 if (do_cr) output[op++] = '\r'; 713 output[op++] = '\n'; 714 } 715 } else if (do_newline && op > 0 && count != LINE_GROUPS) { 716 if (do_cr) output[op++] = '\r'; 717 output[op++] = '\n'; 718 } 719 720 assert tailLen == 0; 721 assert p == len; 722 } else { 723 // Save the leftovers in tail to be consumed on the next 724 // call to encodeInternal. 725 726 if (p == len-1) { 727 tail[tailLen++] = input[p]; 728 } else if (p == len-2) { 729 tail[tailLen++] = input[p]; 730 tail[tailLen++] = input[p+1]; 731 } 732 } 733 734 this.op = op; 735 this.count = count; 736 737 return true; 738 } 739 } 740 741 @UnsupportedAppUsage Base64()742 private Base64() { } // don't instantiate 743 } 744