Home | History | Annotate | Download | only in apple
      1 package com.coremedia.iso.boxes.apple;
      2 
      3 import com.coremedia.iso.IsoTypeReader;
      4 import com.coremedia.iso.IsoTypeWriter;
      5 import com.coremedia.iso.Utf8;
      6 import com.googlecode.mp4parser.AbstractBox;
      7 import com.coremedia.iso.boxes.Box;
      8 import com.coremedia.iso.boxes.ContainerBox;
      9 import com.googlecode.mp4parser.util.ByteBufferByteChannel;
     10 
     11 import java.io.IOException;
     12 import java.math.BigInteger;
     13 import java.nio.ByteBuffer;
     14 import java.util.Collections;
     15 import java.util.List;
     16 import java.util.logging.Logger;
     17 
     18 /**
     19  *
     20  */
     21 public abstract class AbstractAppleMetaDataBox extends AbstractBox implements ContainerBox {
     22     private static Logger LOG = Logger.getLogger(AbstractAppleMetaDataBox.class.getName());
     23     AppleDataBox appleDataBox = new AppleDataBox();
     24 
     25     public List<Box> getBoxes() {
     26         return Collections.singletonList((Box) appleDataBox);
     27     }
     28 
     29     public void setBoxes(List<Box> boxes) {
     30         if (boxes.size() == 1 && boxes.get(0) instanceof AppleDataBox) {
     31             appleDataBox = (AppleDataBox) boxes.get(0);
     32         } else {
     33             throw new IllegalArgumentException("This box only accepts one AppleDataBox child");
     34         }
     35     }
     36 
     37     public <T extends Box> List<T> getBoxes(Class<T> clazz) {
     38         return getBoxes(clazz, false);
     39     }
     40 
     41     public <T extends Box> List<T> getBoxes(Class<T> clazz, boolean recursive) {
     42         //todo recursive?
     43         if (clazz.isAssignableFrom(appleDataBox.getClass())) {
     44             return (List<T>) Collections.singletonList(appleDataBox);
     45         }
     46         return null;
     47     }
     48 
     49     public AbstractAppleMetaDataBox(String type) {
     50         super(type);
     51     }
     52 
     53     @Override
     54     public void _parseDetails(ByteBuffer content) {
     55         long dataBoxSize = IsoTypeReader.readUInt32(content);
     56         String thisShouldBeData = IsoTypeReader.read4cc(content);
     57         assert "data".equals(thisShouldBeData);
     58         appleDataBox = new AppleDataBox();
     59         try {
     60             appleDataBox.parse(new ByteBufferByteChannel(content), null, content.remaining(), null);
     61         } catch (IOException e) {
     62             throw new RuntimeException(e);
     63         }
     64         appleDataBox.setParent(this);
     65     }
     66 
     67 
     68     protected long getContentSize() {
     69         return appleDataBox.getSize();
     70     }
     71 
     72     protected void getContent(ByteBuffer byteBuffer) {
     73         try {
     74             appleDataBox.getBox(new ByteBufferByteChannel(byteBuffer));
     75         } catch (IOException e) {
     76             throw new RuntimeException("The Channel is based on a ByteBuffer and therefore it shouldn't throw any exception");
     77         }
     78     }
     79 
     80     public long getNumOfBytesToFirstChild() {
     81         return getSize() - appleDataBox.getSize();
     82     }
     83 
     84     @Override
     85     public String toString() {
     86         return this.getClass().getSimpleName() + "{" +
     87                 "appleDataBox=" + getValue() +
     88                 '}';
     89     }
     90 
     91     static long toLong(byte b) {
     92         return b < 0 ? b + 256 : b;
     93     }
     94 
     95     public void setValue(String value) {
     96         if (appleDataBox.getFlags() == 1) {
     97             appleDataBox = new AppleDataBox();
     98             appleDataBox.setVersion(0);
     99             appleDataBox.setFlags(1);
    100             appleDataBox.setFourBytes(new byte[4]);
    101             appleDataBox.setData(Utf8.convert(value));
    102         } else if (appleDataBox.getFlags() == 21) {
    103             byte[] content = appleDataBox.getData();
    104             appleDataBox = new AppleDataBox();
    105             appleDataBox.setVersion(0);
    106             appleDataBox.setFlags(21);
    107             appleDataBox.setFourBytes(new byte[4]);
    108 
    109             ByteBuffer bb = ByteBuffer.allocate(content.length);
    110             if (content.length == 1) {
    111                 IsoTypeWriter.writeUInt8(bb, (Byte.parseByte(value) & 0xFF));
    112             } else if (content.length == 2) {
    113                 IsoTypeWriter.writeUInt16(bb, Integer.parseInt(value));
    114             } else if (content.length == 4) {
    115                 IsoTypeWriter.writeUInt32(bb, Long.parseLong(value));
    116             } else if (content.length == 8) {
    117                 IsoTypeWriter.writeUInt64(bb, Long.parseLong(value));
    118             } else {
    119                 throw new Error("The content length within the appleDataBox is neither 1, 2, 4 or 8. I can't handle that!");
    120             }
    121             appleDataBox.setData(bb.array());
    122         } else if (appleDataBox.getFlags() == 0) {
    123             appleDataBox = new AppleDataBox();
    124             appleDataBox.setVersion(0);
    125             appleDataBox.setFlags(0);
    126             appleDataBox.setFourBytes(new byte[4]);
    127             appleDataBox.setData(hexStringToByteArray(value));
    128 
    129         } else {
    130             LOG.warning("Don't know how to handle appleDataBox with flag=" + appleDataBox.getFlags());
    131         }
    132     }
    133 
    134     public String getValue() {
    135         if (appleDataBox.getFlags() == 1) {
    136             return Utf8.convert(appleDataBox.getData());
    137         } else if (appleDataBox.getFlags() == 21) {
    138             byte[] content = appleDataBox.getData();
    139             long l = 0;
    140             int current = 1;
    141             int length = content.length;
    142             for (byte b : content) {
    143                 l += toLong(b) << (8 * (length - current++));
    144             }
    145             return "" + l;
    146         } else if (appleDataBox.getFlags() == 0) {
    147             return String.format("%x", new BigInteger(appleDataBox.getData()));
    148         } else {
    149             return "unknown";
    150         }
    151     }
    152 
    153     public static byte[] hexStringToByteArray(String s) {
    154         int len = s.length();
    155         byte[] data = new byte[len / 2];
    156         for (int i = 0; i < len; i += 2) {
    157             data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
    158                     + Character.digit(s.charAt(i + 1), 16));
    159         }
    160         return data;
    161     }
    162 
    163 
    164 }
    165