package com.coremedia.iso.boxes.apple; import com.coremedia.iso.*; import com.coremedia.iso.boxes.AbstractBox; import com.coremedia.iso.boxes.Box; import com.coremedia.iso.boxes.ContainerBox; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.lang.reflect.Array; import java.math.BigInteger; 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(IsoFile.fourCCtoBytes(type)); } public void parse(IsoBufferWrapper in, long size, BoxParser boxParser, Box lastMovieFragmentBox) throws IOException { long sp = in.position(); long dataBoxSize = in.readUInt32(); String thisShouldBeData = in.readString(4); assert "data".equals(thisShouldBeData); appleDataBox = new AppleDataBox(); appleDataBox.parse(in, dataBoxSize - 8, boxParser, lastMovieFragmentBox); appleDataBox.setParent(this); appleDataBox.offset = sp; } protected long getContentSize() { return appleDataBox.getSize(); } protected void getContent(IsoOutputStream os) throws IOException { appleDataBox.getBox(os); } 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.setContent(Utf8.convert(value)); } else if (appleDataBox.getFlags() == 21) { byte[] content = appleDataBox.getContent(); appleDataBox = new AppleDataBox(); appleDataBox.setVersion(0); appleDataBox.setFlags(21); appleDataBox.setFourBytes(new byte[4]); ByteArrayOutputStream baos = new ByteArrayOutputStream(); IsoOutputStream isoOutputStream = new IsoOutputStream(baos); try { if (content.length == 1) { isoOutputStream.writeUInt8((Byte.parseByte(value) & 0xFF)); } else if (content.length == 2) { isoOutputStream.writeUInt16(Integer.parseInt(value)); } else if (content.length == 4) { isoOutputStream.writeUInt32(Long.parseLong(value)); } else if (content.length == 8) { isoOutputStream.writeUInt64(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!"); } } catch (IOException e) { throw new Error(e); } appleDataBox.setContent(baos.toByteArray()); } else if (appleDataBox.getFlags() == 0) { appleDataBox = new AppleDataBox(); appleDataBox.setVersion(0); appleDataBox.setFlags(0); appleDataBox.setFourBytes(new byte[4]); appleDataBox.setContent(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.getContent()); } else if (appleDataBox.getFlags() == 21) { byte[] content = appleDataBox.getContent(); 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.getContent())); } 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; } }