001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.documentlibrary.util;
016    
017    import com.liferay.portal.kernel.util.ArrayUtil;
018    import com.liferay.portal.kernel.util.StringUtil;
019    
020    import java.io.IOException;
021    import java.io.RandomAccessFile;
022    
023    /**
024     * Atoms are self-contained data units in that contain information about an MP4
025     * movie file.
026     *
027     * @author Juan Gonz??lez
028     * @see    JQTFastStart
029     */
030    public class Atom {
031    
032            public static final String CMOV = "cmov";
033    
034            public static final String CO64 = "co64";
035    
036            public static final String FREE = "free";
037    
038            public static final String FTYP = "ftyp";
039    
040            public static final String JUNK = "junk";
041    
042            public static final String MDAT = "mdat";
043    
044            public static final String MOOV = "moov";
045    
046            public static final String PICT = "PICT";
047    
048            public static final String PNOT = "pnot";
049    
050            public static final String SKIP = "skip";
051    
052            public static final String STCO = "stco";
053    
054            public static final String[] TOP_LEVEL_ATOMS = {
055                    FREE, FTYP, JUNK, MDAT, MOOV, PICT, PNOT, SKIP, Atom.WIDE
056            };
057    
058            public static final String WIDE = "wide";
059    
060            public Atom(RandomAccessFile randomAccessFile) throws IOException {
061                    _offset = randomAccessFile.getFilePointer();
062                    _size = randomAccessFile.readInt();
063    
064                    byte[] bytes = new byte[4];
065    
066                    randomAccessFile.readFully(bytes);
067    
068                    _type = new String(bytes);
069    
070                    if (_size == 1) {
071                            _size = randomAccessFile.readLong();
072                    }
073    
074                    randomAccessFile.seek(_offset);
075            }
076    
077            public void fillBuffer(RandomAccessFile randomAccessFile)
078                    throws IOException {
079    
080                    _buffer = new byte[(int)_size];
081    
082                    randomAccessFile.readFully(_buffer);
083            }
084    
085            public byte[] getBuffer() {
086                    return _buffer;
087            }
088    
089            public long getOffset() {
090                    return _offset;
091            }
092    
093            public long getSize() {
094                    return _size;
095            }
096    
097            public String getType() {
098                    return _type;
099            }
100    
101            public boolean isFTYP() {
102                    return StringUtil.equalsIgnoreCase(_type, FTYP);
103            }
104    
105            public boolean isMDAT() {
106                    return StringUtil.equalsIgnoreCase(_type, MDAT);
107            }
108    
109            public boolean isMOOV() {
110                    return StringUtil.equalsIgnoreCase(_type, MOOV);
111            }
112    
113            public boolean isTopLevelAtom() {
114                    for (String topLevelAtom : TOP_LEVEL_ATOMS) {
115                            if (StringUtil.equalsIgnoreCase(_type, topLevelAtom)) {
116                                    return true;
117                            }
118                    }
119    
120                    return false;
121            }
122    
123            public void patchAtom() {
124                    for (int index = 4; index < _size - 4; index++) {
125                            String type = new String(
126                                    ArrayUtil.clone(_buffer, index, index + 4));
127    
128                            if (StringUtil.equalsIgnoreCase(type, Atom.STCO)) {
129                                    index += patchStcoAtom(index) - 4;
130                            }
131                            else if (StringUtil.equalsIgnoreCase(type, Atom.CO64)) {
132                                    index += patchCo64Atom(index) - 4;
133                            }
134                    }
135            }
136    
137            public void setBuffer(byte[] buffer) {
138                    _buffer = buffer;
139            }
140    
141            public void setOffset(long offset) {
142                    _offset = offset;
143            }
144    
145            public void setSize(long size) {
146                    _size = size;
147            }
148    
149            public void setType(String type) {
150                    _type = type;
151            }
152    
153            protected long bytesToLong(byte[] buffer) {
154                    long value = 0;
155    
156                    for (int i = 0; i < buffer.length; i++) {
157                            value += ((buffer[i] & _BITMASK) << 8 * (buffer.length - i - 1));
158                    }
159    
160                    return value;
161            }
162    
163            protected boolean hasCompressedMoovAtom() {
164                    String type = new String(ArrayUtil.clone(_buffer, 12, 15));
165    
166                    if (StringUtil.equalsIgnoreCase(type, Atom.CMOV)) {
167                            return true;
168                    }
169                    else {
170                            return false;
171                    }
172            }
173    
174            protected int patchCo64Atom(int index) {
175                    int size = (int)bytesToLong(ArrayUtil.clone(_buffer, index - 4, index));
176    
177                    int offsetCount = (int)bytesToLong(
178                            ArrayUtil.clone(_buffer, index + 8, index + 12));
179    
180                    for (int i = 0; i < offsetCount; i++) {
181                            int offsetIndex = index + 12 + i * 8;
182    
183                            long offset = bytesToLong(
184                                    ArrayUtil.clone(_buffer, offsetIndex, offsetIndex + 8));
185    
186                            offset += _size;
187    
188                            _buffer[offsetIndex + 0] = (byte)((offset >> 56) & 0xFF);
189                            _buffer[offsetIndex + 1] = (byte)((offset >> 48) & 0xFF);
190                            _buffer[offsetIndex + 2] = (byte)((offset >> 40) & 0xFF);
191                            _buffer[offsetIndex + 3] = (byte)((offset >> 32) & 0xFF);
192                            _buffer[offsetIndex + 4] = (byte)((offset >> 24) & 0xFF);
193                            _buffer[offsetIndex + 5] = (byte)((offset >> 16) & 0xFF);
194                            _buffer[offsetIndex + 6] = (byte)((offset >> 8) & 0xFF);
195                            _buffer[offsetIndex + 7] = (byte)((offset >> 0) & 0xFF);
196                    }
197    
198                    return size;
199            }
200    
201            protected int patchStcoAtom(int index) {
202                    int size = (int)bytesToLong(ArrayUtil.clone(_buffer, index - 4, index));
203    
204                    int offsetCount = (int)bytesToLong(
205                            ArrayUtil.clone(_buffer, index + 8, index + 12));
206    
207                    for (int i = 0; i < offsetCount; i++) {
208                            int offsetIndex = index + 12 + i * 4;
209    
210                            int offset = (int)bytesToLong(
211                                    ArrayUtil.clone(_buffer, offsetIndex, offsetIndex + 4));
212    
213                            offset += _size;
214    
215                            _buffer[offsetIndex + 0] = (byte)((offset >> 24) & 0xFF);
216                            _buffer[offsetIndex + 1] = (byte)((offset >> 16) & 0xFF);
217                            _buffer[offsetIndex + 2] = (byte)((offset >> 8) & 0xFF);
218                            _buffer[offsetIndex + 3] = (byte)((offset >> 0) & 0xFF);
219                    }
220    
221                    return size;
222            }
223    
224            private static final int _BITMASK = 0x00000000000000FF;
225    
226            private byte[] _buffer;
227            private long _offset;
228            private long _size;
229            private String _type;
230    
231    }