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