Submitter.java
Source code for the submit program.
Size 26.4 kB - File type text/x-javaFile contents
import java.awt.* ;
import javax.swing.* ;
import java.util.* ;
import java.awt.event.* ;
import java.io.* ;
// import sun.misc.* ;
/*
*
*/
@SuppressWarnings("serial") class Submitter
extends JFrame
{
static final boolean debugging = false ;
JScrollPane fileList, messageScrollPane ;
JList files ;
Vector<String> fileVector ;
JFileChooser jfc ;
JTextField sname, sclass, sass ;
JTextArea messageArea ;
JButton doit, quit ;
JMenu cmenu, cmenu1 ;
String whichClass = null ;
String whichAss = null ;
Color oopsColor = new Color(255,100, 200) ;
static public void main (String[] args)
{
try {
new Submitter() ;
}
catch (OutOfMemoryError oe)
{
System.out.println("Out of memory. Try again with a larger heap size.") ;
System.out.println("For example: java -Xmx512M Submitter.jar") ;
}
}
Submitter ()
{
super("Homework Formatter and Submitter - 2") ;
fileVector = new Vector<String>() ;
GridBagLayout gbl = new GridBagLayout() ;
setLayout(gbl) ;
GridBagConstraints c = new GridBagConstraints() ;
c.fill = GridBagConstraints.BOTH ;
// name (just to be sure) on top line
c.gridx = 0 ;
c.gridy = 5 ;
c.gridwidth = 1;
c.gridheight = 1 ;
c.weightx = 1 ;
c.weighty = 1 ;
c.fill = GridBagConstraints.HORIZONTAL ;
JLabel lab = new JLabel("Your Name : ") ;
lab.setHorizontalAlignment(SwingConstants.LEFT) ;
this.add(lab) ;
gbl.setConstraints(lab, c) ;
c.gridx = 1;
c.gridy = 5 ;
c.gridwidth = 3 ;
c.gridheight = 1 ;
c.weightx = 10;
c.weighty = 1 ;
c.fill = GridBagConstraints.HORIZONTAL ;
sname = new JTextField(30) ;
this.add(sname) ;
gbl.setConstraints(sname, c) ;
// class and homework number
JMenuBar jmb = new JMenuBar() ;
c.gridx = 0 ;
c.gridy = 6 ;
c.gridwidth = 1 ;
c.gridheight = 1 ;
c.weightx = 10;
c.weighty = 1;
c.fill = GridBagConstraints.HORIZONTAL ;
this.add(jmb) ;
gbl.setConstraints(jmb, c) ;
cmenu = new JMenu("Class ") ;
ClassMenuAction class1action = new ClassMenuAction("OS(340)") ;
cmenu.add(class1action) ;
ClassMenuAction class2action = new ClassMenuAction("Languages(435)") ;
cmenu.add(class2action) ;
ClassMenuAction class4action = new ClassMenuAction("Other") ;
cmenu.add(class4action) ;
jmb.add(cmenu) ;
jmb = new JMenuBar() ;
c.gridx = 1 ;
c.gridy = 6 ;
c.gridwidth = 1 ;
c.gridheight = 1 ;
c.weightx = 10;
c.weighty = 1;
c.fill = GridBagConstraints.HORIZONTAL ;
this.add(jmb) ;
gbl.setConstraints(jmb, c) ;
cmenu1 = new JMenu("Assignment ") ;
AssMenuAction class21action = new AssMenuAction("1") ;
cmenu1.add(class21action) ;
AssMenuAction class22action = new AssMenuAction("2") ;
cmenu1.add(class22action) ;
AssMenuAction class23action = new AssMenuAction("3") ;
cmenu1.add(class23action) ;
AssMenuAction class24action = new AssMenuAction("4") ;
cmenu1.add(class24action) ;
AssMenuAction class25action = new AssMenuAction("5") ;
cmenu1.add(class25action) ;
AssMenuAction class26action = new AssMenuAction("6") ;
cmenu1.add(class26action) ;
AssMenuAction class27action = new AssMenuAction("7") ;
cmenu1.add(class27action) ;
AssMenuAction class28action = new AssMenuAction("8") ;
cmenu1.add(class28action) ;
AssMenuAction class29action = new AssMenuAction("9") ;
cmenu1.add(class29action) ;
AssMenuAction class2Aaction = new AssMenuAction("10") ;
cmenu1.add(class2Aaction) ;
AssMenuAction class210action = new AssMenuAction("PostMortem") ;
cmenu1.add(class210action) ;
jmb.add(cmenu1) ;
// message area
c.gridx = 0 ;
c.gridy = 0 ;
c.gridwidth = 4 ;
c.gridheight = 4;
c.weightx = 10 ;
c.weighty = 3 ;
c.fill = GridBagConstraints.BOTH ;
messageArea = new JTextArea() ;
messageArea.setBackground(new Color(255,255,200));
messageArea . setEditable(false) ;
messageScrollPane = new JScrollPane(messageArea) ;
// messageArea.setSize(300,300);
this.add(messageScrollPane) ;
gbl.setConstraints(messageScrollPane, c) ;
messageArea.append("Don't forget to select a Makefile and a README file.\n If this is a group project, please include a TEXT file\"names\" \nwith the names of everyone in the group, one per line") ;
// file chooser - big fucker - all the middle of the left
c.gridx = 5 ;
c.gridy = 0 ;
c.gridwidth = 4 ;
c.gridheight = 4 ;
c.weightx = 1 ;
c.weighty = 1 ;
c.fill = GridBagConstraints.BOTH ;
jfc = new JFileChooser() ;
this.add(jfc);
gbl.setConstraints(jfc, c) ;
jfc.addActionListener(new FileChooseAction() ) ;
// list of files
c.gridx = 5 ;
c.gridy = 5 ;
c.gridwidth = 4 ;
c.gridheight = 4 ;
c.weightx = 10 ;
c.weighty = 10 ;
c.fill = GridBagConstraints.BOTH ;
fileVector = new Vector<String>() ;
files = new JList() ;
files.setListData(fileVector) ;
files.setSize(400, 400) ;
fileList = new JScrollPane(files) ;
fileList.setSize(300,600) ;
this.add(fileList) ;
gbl.setConstraints(fileList, c) ;
// submit button
c.gridx = 0 ;
c.gridy = 7 ;
c.gridwidth = 2 ;
c.gridheight = 1 ;
c.weightx = 5;
c.weighty = 1 ;
c.fill = GridBagConstraints.HORIZONTAL ;
doit = new JButton("Make Assignment File") ;
// doit = new JButton("") ;
this.add(doit) ;
gbl.setConstraints(doit, c) ;
doit.addActionListener(new MakeAction()) ;
c.gridx = 2 ;
c.gridy = 7 ;
c.gridwidth = 1 ;
c.gridheight = 1 ;
c.weightx = 5 ;
c.weighty = 1 ;
c.fill = GridBagConstraints.HORIZONTAL ;
quit = new JButton("Exit") ;
this.add(quit) ;
gbl.setConstraints(quit, c) ;
quit.addActionListener(new QuitAction()) ;
setSize(1000,600) ;
setVisible(true) ;
}
String makeField(String name, String innards)
{
return "<" + name + ">" + innards + "</" + name + ">\n" ;
}
String makeCDATAField(String name, String innards)
{
return "<" + name + "><![CDATA[" + innards + "]]></" + name + ">\n" ;
}
boolean empty(String x)
{
return x == null || x == "" || x.length() == 0 ;
}
String crunchName(String sname)
{
int start = 0 ;
while (sname.charAt(start) == ' ') start++ ;
int sp = 1 + sname.indexOf(" ", start+1) ;
if (sp <= 0) sp = 2 ;
String res = sname.substring(start, start+2) + sname.substring(sp, sp+2) ;
return res ;
}
void logError(String mess)
{
messageArea.append("\n");
messageArea.append(mess);
}
void buildSubmission()
{
boolean hasMakefile ;
boolean hasReadme ;
boolean needMore = false ;
// there aint no sanity clause
if (fileVector.isEmpty())
{
logError("No Files!");
needMore = true ;
}
if (empty(whichClass))
{
logError("You need to specify a class.");
needMore = true ;
}
if (empty(whichAss))
{
logError("You need to specify an assignment.");
needMore = true ;
}
if (empty(sname.getText()))
{
logError("You need to specify your name.");
needMore = true ;
}
if (needMore) return ;
String assFileName = "ass-" + whichClass + "-" + whichAss + "-" + crunchName(sname.getText()) + ".submit" ;
String outstr = "\n\nBuilt assignment submission file in \"" + assFileName + "\"" ;
outstr += "\nYou should submit that file to me through blackboard." ;
messageArea . replaceRange("", 0, messageArea.getText().length()) ;
StringBuffer submit = new StringBuffer(20000) ;
submit.append(makeField("class", whichClass)) ;
submit.append(makeField("assignment", whichAss)) ;
submit.append(makeCDATAField("student-name", sname.getText())) ;
String filestring = "" ;
for (Object o:fileVector)
{
String filename = (String) o ;
String fn = makeCDATAField("file-name",filename);
String fileContents = makeField("file-contents", b64(filename)) ;
filestring += makeField("file", fn + fileContents) ;
messageArea.append("\n" + filename) ;
if (fn.endsWith("Makefile"))
{
hasMakefile = true ;
messageArea.append("*") ;
outstr = outstr + "\nMakefile: ok" ;
}
if (fn.endsWith("readme"))
{
messageArea.append("*") ;
hasReadme = true ;
outstr = outstr + "\nReadme: ok" ;
}
}
submit.append(makeField("files", filestring)) ;
String submission = makeField("submission", new String(submit)) ;
try
{
FileOutputStream fos = new FileOutputStream(assFileName) ;
fos.write(submission.getBytes()) ;
}
catch (Exception e)
{
messageArea.setBackground(oopsColor) ;
messageArea.replaceRange("Failed to write output.", 0, messageArea.getText().length()) ;
try
{
Thread.sleep(30) ;
}
catch (Exception e1)
{
e1.printStackTrace() ;
}
// System.exit(1) ;
}
messageArea.append(outstr) ;
try
{
Thread.sleep(30) ;
}
catch (Exception e1)
{
e1.printStackTrace() ;
// System.exit(0) ;
}
System.out.println("wrote assignment submission file in \"" + assFileName + "\"") ; ;
}
String b64(String filename)
{
BASE64Encoder encer = new BASE64Encoder() ;
try
{
FileInputStream fis = new FileInputStream(filename) ;
int available = fis.available() ;
byte[] dataArray = new byte[available];
int i = fis.read(dataArray) ;
return encer.encode(dataArray);
}
catch (Exception e)
{
messageArea.setBackground(oopsColor) ;
messageArea.append("Failed to read " + filename) ;
System.out.println("Failure in reading " + filename ) ;
e.printStackTrace() ;
}
return "" ;
}
class MakeAction
implements ActionListener
{
public void actionPerformed(ActionEvent ev)
{
if (debugging)
{
System.out.println("make button pushed") ;
}
try
{
buildSubmission() ;
}
catch (OutOfMemoryError e)
{
messageArea.setBackground(oopsColor) ;
messageArea.append("---------------!!!!!!!!!!!!!!!!-----------------\n");
messageArea.append("Out of memory. Try again with a larger heap size.\n") ;
messageArea.append("For example: java -Xmx512M Submitter.jar\n") ;
}
}
}
class QuitAction
implements ActionListener
{
public void actionPerformed(ActionEvent ev)
{
System.exit(0) ;
}
}
class FileChooseAction
implements ActionListener
{
public void actionPerformed(ActionEvent ev)
{
if (debugging)
{
System.out.println("got file choose action ") ;
System.out.println("command was " + ev.getActionCommand()) ;
System.out.println( "file was "
+ jfc.getSelectedFile().getName()) ;
}
if (ev.getActionCommand().equals("CancelSelection")) return ;
if (fileVector.contains(jfc.getSelectedFile().getPath())) return ;
fileVector.add(jfc.getSelectedFile().getPath());
files.setListData(fileVector) ;
}
}
class ClassMenuAction
extends AbstractAction
{
String who ;
public ClassMenuAction(String text)
{
super(text) ;
who = text ;
}
public void actionPerformed(ActionEvent e)
{
if (debugging)
{
System.out.println("action performed " + e) ;
System.out.println("source is " + e.getSource()) ;
System.out.println("cmenu is " + cmenu) ;
System.out.println("this is " + this) ;
}
whichClass = who ;
messageArea.append("\nclass is : " + whichClass) ;
cmenu.setText("Class: " + who) ;
// cmenu.setBackground(new Color(200,255,200));
}
}
class AssMenuAction
extends AbstractAction
{
String who ;
public AssMenuAction(String text)
{
super(text) ;
who = text ;
}
public void actionPerformed(ActionEvent e)
{
if (debugging)
{
System.out.println("action performed " + e) ;
System.out.println("source is " + e.getSource()) ;
System.out.println("cmenu is " + cmenu) ;
System.out.println("this is " + this) ;
}
whichAss = who ;
messageArea.append("\nAssignment is : " + whichAss) ;
cmenu1.setText("Assignment: " + who);
}
}
}
/*
* all the following was shamelessly stolen from the internet
* I could have used the sun.misc stuff except that it is
* undocumented and not guaranteed to be anywhere. Seems
* odd, but there you have it.
*
* original source at:
* http://show.docjava.com:8086/book/cgij/doc/net/proxy/BASE64Encoder.java.html
*/
/**
* Utility class to do Base64 encoding, as defined by RFC 2045,
* section 6.8 (http://www.ietf.org/rfc/rfc2045.txt)
* Uses the same class and function names as Sun's implementation from
* sun.misc
*/
class BASE64Encoder {
/**
* Convert a byte to an integer. Needed because in Java bytes
* are signed, and for Base64 purposes they are not. If not done
* this way, when converted to an int, 0xFF will become -127
* @param b Byte value to be converted
* @return Value as an integer, as if byte was unsigned
*/
private int uByteToInt(byte b) {
if (b >= 0) {
return (int) b;
}
return 256 + b;
}
/**
* Encode an array of bytes using Base64
* @param data[] The bytes to be encoded
* @return A valid Base64 representation of the input
*/
public String encode(byte data[]) {
// Base64 encoding yields a String that is 33% longer than the byte array
int charCount = ((data.length * 4) / 3) + 4;
// New lines will also be needed for every 76 charactesr, so allocate a
// StringBuffer that is long enough to hold the full result without
// having to expand later
StringBuffer result = new StringBuffer(
(charCount * 77) / 76);
int byteArrayLength = data.length;
int byteArrayIndex = 0;
int byteTriplet = 0;
while (byteArrayIndex < byteArrayLength - 2) {
byteArrayIndex = processData(
data, byteArrayIndex, result);
}
byteArrayIndex = checkIfWeHave1ByteLeftOver(
byteArrayIndex, byteArrayLength, data, result);
checkIfWeHaveTwoBytesLeftOver(
byteArrayIndex, byteArrayLength, data, result);
return result.toString();
}
private int processData(
byte[] data, int index,
StringBuffer result) {
int byteTriplet;
// Build the 24 bit byte triplet from the input data
byteTriplet = uByteToInt(data[index++]);
// Each input byte contributes 8 bits to the triplet
byteTriplet <<= 8;
byteTriplet |= uByteToInt(data[index++]);
byteTriplet <<= 8;
byteTriplet |= uByteToInt(data[index++]);
// Look at the lowest order six bits and remember them
byte b4 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
// Move the byte triplet to get the next 6 bit value
byteTriplet >>= 6;
byte b3 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
byteTriplet >>= 6;
byte b2 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
byteTriplet >>= 6;
byte b1 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
// Add the Base64 encoded character to the result String
result.append(byteToChar(b1));
result.append(byteToChar(b2));
result.append(byteToChar(b3));
result.append(byteToChar(b4));
// There are 57 bytes for every 76 characters, so wrap the line when needed
if (index % 57 == 0) {
result.append("\n");
}
return index;
}
private void checkIfWeHaveTwoBytesLeftOver(
int index,
int length,
byte[] byteArray,
StringBuffer sb) {
int byteTriplet;
if (index == length - 2) {
// Convert our two bytes to an int
byteTriplet = twoBytesToInt(byteArray, index);
// Right pad the third 6 bit value with zeros
byteTriplet <<= 2;
byte b3 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
byteTriplet >>= 6;
byte b2 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
byteTriplet >>= 6;
byte b1 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
sb.append(byteToChar(b1));
sb.append(byteToChar(b2));
sb.append(byteToChar(b3));
// Add "==" to the output to make it a multiple of 4 Base64 characters
sb.append("=");
}
}
private int checkIfWeHave1ByteLeftOver(
int index,
int length,
byte[] byteArray,
StringBuffer sb) {
int byteTriplet;
if (index == length - 1) {
// Convert our one byte to an int
byteTriplet = uByteToInt(byteArray[index++]);
// Right pad the second 6 bit value with zeros
byteTriplet <<= 4;
byte b2 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
byteTriplet >>= 6;
byte b1 = (byte) (Constants.SIX_BIT_MASK & byteTriplet);
sb.append(byteToChar(b1));
sb.append(byteToChar(b2));
// Add "==" to the output to make it a multiple of 4 Base64 characters
sb.append("==");
}
return index;
}
private int twoBytesToInt(byte[] data, int byteArrayIndex) {
int byteTriplet;
byteTriplet =
uByteToInt(data[byteArrayIndex++]);
byteTriplet <<= 8;
byteTriplet |= uByteToInt(data[byteArrayIndex++]);
return byteTriplet;
}
/**
* Convert a byte between 0 and 63 to its Base64 character equivalent
* @param b Byte value to be converted
* @return Base64 char value
*/
private char byteToChar(byte b) {
if (b < Constants.LOWER_CASE_A_VALUE) {
return (char) ('A' + b);
}
if (b < Constants.ZERO_VALUE) {
return (char) ('a' + (b - Constants.LOWER_CASE_A_VALUE));
}
if (b < Constants.PLUS_VALUE) {
return (char) ('0' + (b - Constants.ZERO_VALUE));
}
if (b == Constants.PLUS_VALUE) {
return '+';
}
if (b == Constants.SLASH_VALUE) {
return '/';
}
throw
new IllegalArgumentException(
"Byte " +
new Integer(b) +
" is not a valid Base64 value");
}
/**
* Simple test method to make sure everything works correctly
* Creates 100 randomly sized arrays of random bytes, encodes them,
* decodes them, and checks to make sure the result matches the input
*/
public static void main(String args[]) throws Exception {
testCodec();
}
private static void testCodec() {
// sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
// sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
for (int j = 0; j < 100; j++)
test(new BASE64Encoder(), new BASE64Decoder());
}
private static void test(BASE64Encoder encoder, BASE64Decoder decoder) {
byte test[] = new byte[(int) (100000 * Math.random())];
for (int i = 0; i < test.length; i++) {
test[i] = (byte) (256 * Math.random());
}
String string = encoder.encode(test);
byte result[] = decoder.decodeBuffer(string);
if (!Arrays.equals(test, result) || test.length != result.length) {
System.out.println("ARRAYS DO NOT MATCH!");
}
}
}
/**
* Utility class to do Base64 decoding, as defined by RFC 2045,
* section 6.8 (http://www.ietf.org/rfc/rfc2045.txt)
* Uses the same class and function names as Sun's implementation from
* sun.misc
*/
class BASE64Decoder
{
/**
* Bit mask for one byte worth of bits in Base64 encoding.
* Equivalent to binary value 11111111b.
*/
private static final int EIGHT_BIT_MASK = 0xFF;
/**
* Decode an input String using Base64
* @param data The String to be decoded
* @return The appropriate byte array
*/
public byte[] decodeBuffer(String data) {
// Create a wrapper around the input to screen out non-Base64 characters
StringWrapper wrapper = new StringWrapper(data);
// A Base64 byte array is 75% the size of its String representation
int length = wrapper.getUsefulLength() * 3 / 4;
byte byteArray[] = new byte[length];
int byteTriplet = 0;
int index = 0;
// Continue until we have less than 4 full characters left to
// decode in the input.
while (index + 2 < length) {
index = processByteArray(
wrapper,
byteArray,
index);
}
checkIfWeHave1ByteLeft(
index,
length,
wrapper, byteArray);
checkIfWeHave2BytesLeft(index,
length,
wrapper,
byteArray);
return byteArray;
}
private void checkIfWeHave2BytesLeft(int index, int length, StringWrapper wrapper, byte[] byteArray) {
int byteTriplet;
if (index == length - 2) {
// Take out the last three characters from the String
byteTriplet = charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
// Remove the padded zeros
byteTriplet >>= 2;
byteArray[index + 1] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteTriplet >>= 8;
byteArray[index] = (byte) (byteTriplet & EIGHT_BIT_MASK);
}
}
private void checkIfWeHave1ByteLeft(int byteIndex, int byteArrayLength, StringWrapper wrapper, byte[] result) {
int byteTriplet;
if (byteIndex == byteArrayLength - 1) {
// Take out the last two characters from the String
byteTriplet = charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
// Remove the padded zeros
byteTriplet >>= 4;
result[byteIndex] = (byte) (byteTriplet & EIGHT_BIT_MASK);
}
}
private int processByteArray(StringWrapper wrapper, byte[] result, int byteIndex) {
int byteTriplet;
// Package a set of four characters into a byte triplet
// Each character contributes 6 bits of useful information
byteTriplet = charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
byteTriplet <<= 6;
byteTriplet |= charToInt(wrapper.getNextUsefulChar());
// Grab a normal byte (eight bits) out of the byte triplet
// and put it in the byte array
result[byteIndex + 2] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteTriplet >>= 8;
result[byteIndex + 1] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteTriplet >>= 8;
result[byteIndex] = (byte) (byteTriplet & EIGHT_BIT_MASK);
byteIndex += 3;
return byteIndex;
}
/**
* Convert a Base64 character to its 6 bit value as defined by the mapping.
* @param c Base64 character to decode
* @return int representation of 6 bit value
*/
private int charToInt(char c) {
if (c >= 'A' && c <= 'Z') {
return c - 'A';
}
if (c >= 'a' && c <= 'z') {
return (c - 'a') + Constants.LOWER_CASE_A_VALUE;
}
if (c >= '0' && c <= '9') {
return (c - '0') + Constants.ZERO_VALUE;
}
if (c == '+') {
return Constants.PLUS_VALUE;
}
if (c == '/') {
return Constants.SLASH_VALUE;
}
throw new IllegalArgumentException(c + " is not a valid Base64 character.");
}
/**
* Simple class to wrap around the String input to ignore all of the
* non-Base64 characters in the input. Note that although '=' is
* a valid character, it does not contribute to the total number
* of output bytes, and is therefore ignored
*/
private class StringWrapper {
/**
* The input String to be decoded
*/
private String mString;
/**
* Current position in the String
*/
private int mIndex = 0;
/**
* Total number of Base64 characters in the input
*/
private int mUsefulLength;
/**
* @param c Character to be examined
* @return Whether or not the character is a Base64 character
*/
private boolean isUsefulChar(char c) {
return (c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
(c == '+') ||
(c == '/');
}
/**
* Create the wrapper and determine the number of Base64 characters in
* the input
* @param s Input String to be decoded
*/
public StringWrapper(String s) {
mString = s;
mUsefulLength = 0;
int length = mString.length();
for (int i = 0; i < length; i++) {
if (isUsefulChar(mString.charAt(i))) {
mUsefulLength++;
}
}
}
/**
* @return Total number of Base64 characters in the input. Does
* not include '='
*/
public int getUsefulLength() {
return mUsefulLength;
}
/**
* Traverse the String until hitting the next Base64 character.
* Assumes that there is still another valid Base64 character
* left in the String.
*/
public char getNextUsefulChar() {
char result = '_'; // Start with a non-Base64 character
while (!isUsefulChar(result)) {
result = mString.charAt(mIndex++);
}
return result;
}
}
}
class Constants {
/**
* Byte value that maps to 'a' in Base64 encoding
*/
final static int LOWER_CASE_A_VALUE = 26;
/**
* Byte value that maps to '0' in Base64 encoding
*/
final static int ZERO_VALUE = 52;
/**
* Byte value that maps to '+' in Base64 encoding
*/
final static int PLUS_VALUE = 62;
/**
* Byte value that maps to '/' in Base64 encoding
*/
final static int SLASH_VALUE = 63;
/**
* Bit mask for one character worth of bits in Base64 encoding.
* Equivalent to binary value 111111b.
*/
final static int SIX_BIT_MASK = 63;
}
Click here to get the file