| package com.coremedia.iso.boxes.apple; |
| |
| import com.coremedia.iso.IsoTypeReader; |
| import com.coremedia.iso.IsoTypeWriter; |
| import com.coremedia.iso.Utf8; |
| import com.googlecode.mp4parser.AbstractBox; |
| import com.coremedia.iso.boxes.Box; |
| import com.coremedia.iso.boxes.ContainerBox; |
| import com.googlecode.mp4parser.util.ByteBufferByteChannel; |
| |
| import java.io.IOException; |
| import java.math.BigInteger; |
| import java.nio.ByteBuffer; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.logging.Logger; |
| |
| /** |
| * |
| */ |
| public abstract class AbstractAppleMetaDataBox extends AbstractBox implements ContainerBox { |
| private static Logger LOG = Logger.getLogger(AbstractAppleMetaDataBox.class.getName()); |
| AppleDataBox appleDataBox = new AppleDataBox(); |
| |
| public List<Box> getBoxes() { |
| return Collections.singletonList((Box) appleDataBox); |
| } |
| |
| public void setBoxes(List<Box> boxes) { |
| if (boxes.size() == 1 && boxes.get(0) instanceof AppleDataBox) { |
| appleDataBox = (AppleDataBox) boxes.get(0); |
| } else { |
| throw new IllegalArgumentException("This box only accepts one AppleDataBox child"); |
| } |
| } |
| |
| public <T extends Box> List<T> getBoxes(Class<T> clazz) { |
| return getBoxes(clazz, false); |
| } |
| |
| public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) { |
| //todo recursive? |
| if (clazz.isAssignableFrom(appleDataBox.getClass())) { |
| return (List<T>) Collections.singletonList(appleDataBox); |
| } |
| return null; |
| } |
| |
| public AbstractAppleMetaDataBox(String type) { |
| super(type); |
| } |
| |
| @Override |
| public void _parseDetails(ByteBuffer content) { |
| long dataBoxSize = IsoTypeReader.readUInt32(content); |
| String thisShouldBeData = IsoTypeReader.read4cc(content); |
| assert "data".equals(thisShouldBeData); |
| appleDataBox = new AppleDataBox(); |
| try { |
| appleDataBox.parse(new ByteBufferByteChannel(content), null, content.remaining(), null); |
| } catch (IOException e) { |
| throw new RuntimeException(e); |
| } |
| appleDataBox.setParent(this); |
| } |
| |
| |
| protected long getContentSize() { |
| return appleDataBox.getSize(); |
| } |
| |
| protected void getContent(ByteBuffer byteBuffer) { |
| try { |
| appleDataBox.getBox(new ByteBufferByteChannel(byteBuffer)); |
| } catch (IOException e) { |
| throw new RuntimeException("The Channel is based on a ByteBuffer and therefore it shouldn't throw any exception"); |
| } |
| } |
| |
| public long getNumOfBytesToFirstChild() { |
| return getSize() - appleDataBox.getSize(); |
| } |
| |
| @Override |
| public String toString() { |
| return this.getClass().getSimpleName() + "{" + |
| "appleDataBox=" + getValue() + |
| '}'; |
| } |
| |
| static long toLong(byte b) { |
| return b < 0 ? b + 256 : b; |
| } |
| |
| public void setValue(String value) { |
| if (appleDataBox.getFlags() == 1) { |
| appleDataBox = new AppleDataBox(); |
| appleDataBox.setVersion(0); |
| appleDataBox.setFlags(1); |
| appleDataBox.setFourBytes(new byte[4]); |
| appleDataBox.setData(Utf8.convert(value)); |
| } else if (appleDataBox.getFlags() == 21) { |
| byte[] content = appleDataBox.getData(); |
| appleDataBox = new AppleDataBox(); |
| appleDataBox.setVersion(0); |
| appleDataBox.setFlags(21); |
| appleDataBox.setFourBytes(new byte[4]); |
| |
| ByteBuffer bb = ByteBuffer.allocate(content.length); |
| if (content.length == 1) { |
| IsoTypeWriter.writeUInt8(bb, (Byte.parseByte(value) & 0xFF)); |
| } else if (content.length == 2) { |
| IsoTypeWriter.writeUInt16(bb, Integer.parseInt(value)); |
| } else if (content.length == 4) { |
| IsoTypeWriter.writeUInt32(bb, Long.parseLong(value)); |
| } else if (content.length == 8) { |
| IsoTypeWriter.writeUInt64(bb, Long.parseLong(value)); |
| } else { |
| throw new Error("The content length within the appleDataBox is neither 1, 2, 4 or 8. I can't handle that!"); |
| } |
| appleDataBox.setData(bb.array()); |
| } else if (appleDataBox.getFlags() == 0) { |
| appleDataBox = new AppleDataBox(); |
| appleDataBox.setVersion(0); |
| appleDataBox.setFlags(0); |
| appleDataBox.setFourBytes(new byte[4]); |
| appleDataBox.setData(hexStringToByteArray(value)); |
| |
| } else { |
| LOG.warning("Don't know how to handle appleDataBox with flag=" + appleDataBox.getFlags()); |
| } |
| } |
| |
| public String getValue() { |
| if (appleDataBox.getFlags() == 1) { |
| return Utf8.convert(appleDataBox.getData()); |
| } else if (appleDataBox.getFlags() == 21) { |
| byte[] content = appleDataBox.getData(); |
| long l = 0; |
| int current = 1; |
| int length = content.length; |
| for (byte b : content) { |
| l += toLong(b) << (8 * (length - current++)); |
| } |
| return "" + l; |
| } else if (appleDataBox.getFlags() == 0) { |
| return String.format("%x", new BigInteger(appleDataBox.getData())); |
| } else { |
| return "unknown"; |
| } |
| } |
| |
| public static byte[] hexStringToByteArray(String s) { |
| int len = s.length(); |
| byte[] data = new byte[len / 2]; |
| for (int i = 0; i < len; i += 2) { |
| data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) |
| + Character.digit(s.charAt(i + 1), 16)); |
| } |
| return data; |
| } |
| |
| |
| } |