/**
* This file is part of jFlvTool.
*
* jFlvTool is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* jFlvTool is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* file name : BufferHelper.java
* authors : Jon Keys
* created : July 3, 2007, 5:51 PM
* copyright : Sony Digital Authoring Services
*
* modifications:
* Date: Name: Description:
* ---------- --------------- ----------------------------------------------
* July 3, 2007 Jon Keys Creation
*/
package edu.washington.cs.oneswarm.ui.gwt.server.ffmpeg.jflv.io;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import edu.washington.cs.oneswarm.ui.gwt.server.ffmpeg.jflv.metadata.AMFObject;
import edu.washington.cs.oneswarm.ui.gwt.server.ffmpeg.jflv.metadata.AMFTime;
/**
*
* @author Jon Keys
*/
public class BufferHelper {
private byte[] mbb;
private int pos;
private boolean debug;
private String str;
private byte[] buf;
/** Creates a new instance of BufferHelper */
public BufferHelper() {
mbb = null;
pos = 0;
debug = false;
str = null;
buf = null;
}
public void reset() {
mbb = null;
pos = 0;
str = null;
buf = null;
}
public ByteBuffer byte2buffer(byte[] bytes) {
ByteBuffer bbuf = ByteBuffer.allocate(bytes.length);
bbuf.put(bytes);
bbuf.rewind();
return bbuf;
}// byte2buffer()
public int bit2uint(char[] bits) {
int uint = 0;
for (int i = 0; i < bits.length; i++) {
if (bits[i] == '1') {
uint += Math.pow(2, (bits.length - i - 1));
}
}
return uint;
}// bit2uint
// read uint from existing byte[]
public int readUint(byte[] mpb, int start, int len) {
int uint = 0;
for (int i = 0; i < len; i++) {
uint += (mpb[i + start] & 0xFF) << ((len - i - 1) * 8);
}
return uint;
}// readUint()
// read int from existing byte[]
public int readInt(byte[] mpb, int start, int len) {
int uint = 0;
for (int i = 0; i < len; i++) {
uint += mpb[i + start];
}
return uint;
}// readUint()
// read binary string from existing byte[]
public String readBinaryString(byte[] mpb, int start, int len) {
buf = new byte[len];
System.arraycopy(mpb, start, buf, 0, len);
return new BigInteger(buf).toString(2);
} // readBinaryString()
// read String from existing byte[]
public String readString(byte[] mpb, int start, int len) {
buf = new byte[len];
str = null;
try {
System.arraycopy(mpb, start, buf, 0, len);
str = new String(buf);
buf = null;
} catch (Exception e) {
System.out.println("Error - could not read string from given bytes");
if (debug) {
e.printStackTrace();
}
str = "";
}
return str;
}// readString()
// read uint from existing byte[]
public double readDouble(byte[] mpb, int start, int len) {
ByteBuffer bbuf = ByteBuffer.allocate(len);
buf = new byte[len];
System.arraycopy(mpb, start, buf, 0, len);
bbuf.put(buf);
bbuf.rewind();
buf = null;
return bbuf.getDouble();
}// readDouble()
public void reverseByteArray(byte[] b) {
int left = 0;
int right = b.length - 1;
while (left < right) {
byte temp = b[left];
b[left] = b[right];
b[right] = temp;
left++;
right--;
}// while
}// reverse
public Object getAMFData() {
int amfSwtch = readUint(mbb, pos, 1);
pos += 1;
return getAMFData(amfSwtch);
}// getAMFData()
public Object getAMFData(int amfSwtch) {
Object amfData = null;
switch (amfSwtch) {
case 0:
amfData = getAMFDouble();
break;
case 1:
amfData = getAMFBoolean();
break;
case 2:
amfData = getAMFString();
break;
case 3:
amfData = getAMFObject();
break;
case 8:
amfData = getAMFMixedArray();
break;
case 10:
amfData = getAMFArray();
break;
case 11:
amfData = getAMFTime();
break;
}
return amfData;
}// getAMFData()
public Double getAMFDouble() {
double dbl = readDouble(mbb, pos, 8);
pos += 8;
return new Double(dbl);
}// getAMFDouble()
public Boolean getAMFBoolean() {
int val = readUint(mbb, pos, 1);
pos += 1;
return new Boolean((val == 1));
}// getAMFBoolean()
public String getAMFString() {
int bytes2read = readUint(mbb, pos, 2);
pos += 2;
String str = readString(mbb, pos, bytes2read);
pos += bytes2read;
return str;
}// getAMFString()
public AMFObject getAMFObject() {
AMFObject amfObj = new AMFObject();
String key = "";
int type = 0;
do {
if (pos >= mbb.length) {
break;
}
key = getAMFString();
type = readUint(mbb, pos, 1);
pos += 1;
amfObj.put(key, getAMFData(type));
} while (!(key.length() < 1 && type == 9));
return amfObj;
}// getAMFObject()
public HashMap<String, Object> getAMFMixedArray() {
// just skip 4 bytes
pos += 4;
HashMap<String, Object> amfMap = new HashMap<String, Object>();
String key = "";
int type = 0;
do {
if (pos >= mbb.length) {
break;
}
key = getAMFString();
type = readUint(mbb, pos, 1);
pos += 1;
amfMap.put(key, getAMFData(type));
} while (!(key.length() < 1 && type == 9));
return amfMap;
}// getAMFMixedArray()
public ArrayList<Object> getAMFArray() {
int size = readUint(mbb, pos, 4);
pos += 4;
ArrayList<Object> afmArray = new ArrayList<Object>();
for (int i = 0; i < size; i++) {
afmArray.add(getAMFData());
}
return afmArray;
}// getAMFArray()
public AMFTime getAMFTime() {
// get time in milliseconds
long time = (long) getAMFDouble().doubleValue();
byte[] buf = new byte[2];
System.arraycopy(mbb, pos, buf, 0, 2);
pos += 2;
reverseByteArray(buf);
// get gmt offset in milliseconds
int gmtOff = 0;
for (int i = 0; i < 2; i++) {
gmtOff += (buf[i] & 0xFF) << ((1 - i) * 8);
}
buf = null;
int gmt = gmtOff * 60 * 1000;
return new AMFTime(time, gmt);
}// getAMFTime()
public void clearData() {
this.mbb = null;
}
public byte[] getBuffer() {
return mbb;
}
public void setBuffer(byte[] mbb) {
this.mbb = mbb;
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}// BufferHelper