1dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/* 2dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Copyright 2012 Sebastian Annies, Hamburg 3dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 4dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Licensed under the Apache License, Version 2.0 (the License); 5dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * you may not use this file except in compliance with the License. 6dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * You may obtain a copy of the License at 7dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 8dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * http://www.apache.org/licenses/LICENSE-2.0 9dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 10dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Unless required by applicable law or agreed to in writing, software 11dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * distributed under the License is distributed on an AS IS BASIS, 12dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * See the License for the specific language governing permissions and 14dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * limitations under the License. 15dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 16dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 17dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupackage com.googlecode.mp4parser; 18dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 19dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.BoxParser; 20dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.ChannelHelper; 21dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.Hex; 22dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoFile; 23dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.IsoTypeWriter; 24dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.Box; 25dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.ContainerBox; 26dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.coremedia.iso.boxes.UserBox; 27dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport com.googlecode.mp4parser.annotations.DoNotParseDetail; 28dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 29dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.io.IOException; 30dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.ByteBuffer; 31dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.FileChannel; 32dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.ReadableByteChannel; 33dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.nio.channels.WritableByteChannel; 34dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport java.util.logging.Logger; 35dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 36dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhuimport static com.googlecode.mp4parser.util.CastUtils.l2i; 37dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 38dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu/** 39dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * A basic on-demand parsing box. Requires the implementation of three methods to become a fully working box: 40dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <ol> 41dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>{@link #_parseDetails(java.nio.ByteBuffer)}</li> 42dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>{@link #getContent(java.nio.ByteBuffer)}</li> 43dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <li>{@link #getContentSize()}</li> 44dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * </ol> 45dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * additionally this new box has to be put into the <code>isoparser-default.properties</code> file so that 46dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * it is accessible by the <code>PropertyBoxParserImpl</code> 47dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 48dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhupublic abstract class AbstractBox implements Box { 49dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public static int MEM_MAP_THRESHOLD = 100 * 1024; 50dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private static Logger LOG = Logger.getLogger(AbstractBox.class.getName()); 51dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 52dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected String type; 53dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private byte[] userType; 54dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private ContainerBox parent; 55dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 56dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private ByteBuffer content; 57dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private ByteBuffer deadBytes = null; 58dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 59dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 60dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected AbstractBox(String type) { 61dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.type = type; 62dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 63dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 64dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected AbstractBox(String type, byte[] userType) { 65dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.type = type; 66dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.userType = userType; 67dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 68dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 69dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 70dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Get the box's content size without its header. This must be the exact number of bytes 71dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * that <code>getContent(ByteBuffer)</code> writes. 72dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 73dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return Gets the box's content size in bytes 74dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @see #getContent(java.nio.ByteBuffer) 75dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 76dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected abstract long getContentSize(); 77dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 78dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 79dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Write the box's content into the given <code>ByteBuffer</code>. This must include flags 80dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * and version in case of a full box. <code>byteBuffer</code> has been initialized with 81dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * <code>getSize()</code> bytes. 82dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 83dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param byteBuffer the sink for the box's content 84dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 85dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected abstract void getContent(ByteBuffer byteBuffer); 86dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 87dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 88dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Parse the box's fields and child boxes if any. 89dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 90dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param content the box's raw content beginning after the 4-cc field. 91dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 92dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected abstract void _parseDetails(ByteBuffer content); 93dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 94dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 95dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Read the box's content from a byte channel without parsing it. Parsing is done on-demand. 96dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 97dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param readableByteChannel the (part of the) iso file to parse 98dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param contentSize expected contentSize of the box 99dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param boxParser creates inner boxes 100dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @throws IOException in case of an I/O error. 101dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 102dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 103dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void parse(ReadableByteChannel readableByteChannel, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { 104dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (readableByteChannel instanceof FileChannel && contentSize > MEM_MAP_THRESHOLD) { 105dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // todo: if I map this here delayed I could use transferFrom/transferTo in the getBox method 106dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // todo: potentially this could speed up writing. 107dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // 108dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu // It's quite expensive to map a file into the memory. Just do it when the box is larger than a MB. 109dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu content = ((FileChannel) readableByteChannel).map(FileChannel.MapMode.READ_ONLY, ((FileChannel) readableByteChannel).position(), contentSize); 110dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ((FileChannel) readableByteChannel).position(((FileChannel) readableByteChannel).position() + contentSize); 111dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 112dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert contentSize < Integer.MAX_VALUE; 113dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu content = ChannelHelper.readFully(readableByteChannel, contentSize); 114dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 1159fcbbdafbb20691e1d519ee1ab35f8a5889bef15Teng-Hui Zhu if (isParsed() == false) { 1169fcbbdafbb20691e1d519ee1ab35f8a5889bef15Teng-Hui Zhu parseDetails(); 1179fcbbdafbb20691e1d519ee1ab35f8a5889bef15Teng-Hui Zhu } 1189fcbbdafbb20691e1d519ee1ab35f8a5889bef15Teng-Hui Zhu 119dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 120dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 121dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void getBox(WritableByteChannel os) throws IOException { 122dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer bb = ByteBuffer.allocate(l2i(getSize())); 123dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu getHeader(bb); 124dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (content == null) { 125dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu getContent(bb); 126dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (deadBytes != null) { 127dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu deadBytes.rewind(); 128dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu while (deadBytes.remaining() > 0) { 129dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.put(deadBytes); 130dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 131dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 132dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 133dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu content.rewind(); 134dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.put(content); 135dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 136dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.rewind(); 137dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu os.write(bb); 138dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 139dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 140dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 141dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 142dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Parses the raw content of the box. It surrounds the actual parsing 143dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * which is done 144dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 145dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu synchronized final void parseDetails() { 146dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (content != null) { 147dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer content = this.content; 148dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.content = null; 149dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu content.rewind(); 150dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu _parseDetails(content); 151dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (content.remaining() > 0) { 152dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu deadBytes = content.slice(); 153dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 154dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu assert verify(content); 155dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 156dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 157dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 158dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 159dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Sets the 'dead' bytes. These bytes are left if the content of the box 160dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * has been parsed but not all bytes have been used up. 161dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 162dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param newDeadBytes the unused bytes with no meaning but required for bytewise reconstruction 163dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 164dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu protected void setDeadBytes(ByteBuffer newDeadBytes) { 165dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu deadBytes = newDeadBytes; 166dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 167dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 168dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 169dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 170dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Gets the full size of the box including header and content. 171dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 172dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return the box's size 173dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 174dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public long getSize() { 175dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu long size = (content == null ? getContentSize() : content.limit()); 176dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size += (8 + // size|type 177dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu (size >= ((1L << 32) - 8) ? 8 : 0) + // 32bit - 8 byte size and type 178dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu (UserBox.TYPE.equals(getType()) ? 16 : 0)); 179dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu size += (deadBytes == null ? 0 : deadBytes.limit()); 180dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return size; 181dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 182dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 183dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 184dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public String getType() { 185dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return type; 186dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 187dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 188dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 189dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public byte[] getUserType() { 190dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return userType; 191dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 192dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 193dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 194dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public ContainerBox getParent() { 195dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return parent; 196dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 197dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 198dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 199dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public void setParent(ContainerBox parent) { 200dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu this.parent = parent; 201dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 202dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 203dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu @DoNotParseDetail 204dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public IsoFile getIsoFile() { 205dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return parent.getIsoFile(); 206dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 207dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 208dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 209dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Check if details are parsed. 210dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 211dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return <code>true</code> whenever the content <code>ByteBuffer</code> is not <code>null</code> 212dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 213dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu public boolean isParsed() { 214dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return content == null; 215dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 216dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 217dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 218dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu /** 219dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * Verifies that a box can be reconstructed byte-exact after parsing. 220dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * 221dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @param content the raw content of the box 222dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu * @return <code>true</code> if raw content exactly matches the reconstructed content 223dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu */ 224dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private boolean verify(ByteBuffer content) { 225dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu ByteBuffer bb = ByteBuffer.allocate(l2i(getContentSize() + (deadBytes != null ? deadBytes.limit() : 0))); 226dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu getContent(bb); 227dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (deadBytes != null) { 228dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu deadBytes.rewind(); 229dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu while (deadBytes.remaining() > 0) { 230dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.put(deadBytes); 231dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 232dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 233dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu content.rewind(); 234dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.rewind(); 235dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 236dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 237dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (content.remaining() != bb.remaining()) { 238dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.severe(this.getType() + ": remaining differs " + content.remaining() + " vs. " + bb.remaining()); 239dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return false; 240dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 241dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu int p = content.position(); 242dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu for (int i = content.limit() - 1, j = bb.limit() - 1; i >= p; i--, j--) { 243dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byte v1 = content.get(i); 244dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byte v2 = bb.get(j); 245dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (v1 != v2) { 246dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu LOG.severe(String.format("%s: buffers differ at %d: %2X/%2X", this.getType(), i, v1, v2)); 247dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byte[] b1 = new byte[content.remaining()]; 248dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byte[] b2 = new byte[bb.remaining()]; 249dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu content.get(b1); 250dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu bb.get(b2); 251dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu System.err.println("original : " + Hex.encodeHex(b1, 4)); 252dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu System.err.println("reconstructed : " + Hex.encodeHex(b2, 4)); 253dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return false; 254dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 255dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 256dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return true; 257dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 258dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 259dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 260dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private boolean isSmallBox() { 261dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu return (content == null ? (getContentSize() + (deadBytes != null ? deadBytes.limit() : 0) + 8) : content.limit()) < 1L << 32; 262dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 263dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 264dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu private void getHeader(ByteBuffer byteBuffer) { 265dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (isSmallBox()) { 266dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(byteBuffer, this.getSize()); 267dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byteBuffer.put(IsoFile.fourCCtoBytes(getType())); 268dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } else { 269dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt32(byteBuffer, 1); 270dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byteBuffer.put(IsoFile.fourCCtoBytes(getType())); 271dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu IsoTypeWriter.writeUInt64(byteBuffer, getSize()); 272dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 273dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu if (UserBox.TYPE.equals(getType())) { 274dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu byteBuffer.put(getUserType()); 275dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 276dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 277dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu 278dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu } 279dd9eb897ee7c7b507cbdcf80263bb4b5de6966bfTeng-Hui Zhu} 280