1/* 2 * Copyright (C) 2013 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 17package com.android.inputmethod.latin.utils; 18 19import com.android.inputmethod.annotations.UsedForTesting; 20 21import java.io.EOFException; 22import java.io.IOException; 23import java.io.LineNumberReader; 24 25@UsedForTesting 26public class Base64Reader { 27 private final LineNumberReader mReader; 28 29 private String mLine; 30 private int mCharPos; 31 private int mByteCount; 32 33 @UsedForTesting 34 public Base64Reader(final LineNumberReader reader) { 35 mReader = reader; 36 reset(); 37 } 38 39 @UsedForTesting 40 public void reset() { 41 mLine = null; 42 mCharPos = 0; 43 mByteCount = 0; 44 } 45 46 @UsedForTesting 47 public int getLineNumber() { 48 return mReader.getLineNumber(); 49 } 50 51 @UsedForTesting 52 public int getByteCount() { 53 return mByteCount; 54 } 55 56 private void fillBuffer() throws IOException { 57 if (mLine == null || mCharPos >= mLine.length()) { 58 mLine = mReader.readLine(); 59 mCharPos = 0; 60 } 61 if (mLine == null) { 62 throw new EOFException(); 63 } 64 } 65 66 private int peekUint8() throws IOException { 67 fillBuffer(); 68 final char c = mLine.charAt(mCharPos); 69 if (c >= 'A' && c <= 'Z') 70 return c - 'A' + 0; 71 if (c >= 'a' && c <= 'z') 72 return c - 'a' + 26; 73 if (c >= '0' && c <= '9') 74 return c - '0' + 52; 75 if (c == '+') 76 return 62; 77 if (c == '/') 78 return 63; 79 if (c == '=') 80 return 0; 81 throw new RuntimeException("Unknown character '" + c + "' in base64 at line " 82 + mReader.getLineNumber()); 83 } 84 85 private int getUint8() throws IOException { 86 final int value = peekUint8(); 87 mCharPos++; 88 return value; 89 } 90 91 @UsedForTesting 92 public int readUint8() throws IOException { 93 final int value1, value2; 94 switch (mByteCount % 3) { 95 case 0: 96 value1 = getUint8() << 2; 97 value2 = value1 | (peekUint8() >> 4); 98 break; 99 case 1: 100 value1 = (getUint8() & 0x0f) << 4; 101 value2 = value1 | (peekUint8() >> 2); 102 break; 103 default: 104 value1 = (getUint8() & 0x03) << 6; 105 value2 = value1 | getUint8(); 106 break; 107 } 108 mByteCount++; 109 return value2; 110 } 111 112 @UsedForTesting 113 public short readInt16() throws IOException { 114 final int data = readUint8() << 8; 115 return (short)(data | readUint8()); 116 } 117} 118