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