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    
019    import java.io.IOException;
020    import java.io.RandomAccessFile;
021    
022    /**
023     * Atoms are self-contained data units in that contain information about an MP4
024     * movie file.
025     *
026     * @author Juan Gonz??lez
027     * @see    JQTFastStart
028     */
029    public class Atom {
030    
031            public static final String CMOV = "cmov";
032    
033            public static final String CO64 = "co64";
034    
035            public static final String FREE = "free";
036    
037            public static final String FTYP = "ftyp";
038    
039            public static final String JUNK = "junk";
040    
041            public static final String MDAT = "mdat";
042    
043            public static final String MOOV = "moov";
044    
045            public static final String PICT = "PICT";
046    
047            public static final String PNOT = "pnot";
048    
049            public static final String SKIP = "skip";
050    
051            public static final String STCO = "stco";
052    
053            public static final String[] TOP_LEVEL_ATOMS = {
054                    FREE, FTYP, JUNK, MDAT, MOOV, PICT, PNOT, SKIP, Atom.WIDE
055            };
056    
057            public static final String WIDE = "wide";
058    
059            public Atom(RandomAccessFile randomAccessFile) throws IOException {
060                    _offset = randomAccessFile.getFilePointer();
061                    _size = randomAccessFile.readInt();
062    
063                    byte[] bytes = new byte[4];
064    
065                    randomAccessFile.readFully(bytes);
066    
067                    _type = new String(bytes);
068    
069                    if (_size == 1) {
070                            _size = randomAccessFile.readLong();
071                    }
072    
073                    randomAccessFile.seek(_offset);
074            }
075    
076            public void fillBuffer(RandomAccessFile randomAccessFile)
077                    throws IOException {
078    
079                    _buffer = new byte[(int)_size];
080    
081                    randomAccessFile.readFully(_buffer);
082            }
083    
084            public byte[] getBuffer() {
085                    return _buffer;
086            }
087    
088            public long getOffset() {
089                    return _offset;
090            }
091    
092            public long getSize() {
093                    return _size;
094            }
095    
096            public String getType() {
097                    return _type;
098            }
099    
100            public boolean isFTYP() {
101                    return _type.equalsIgnoreCase(FTYP);
102            }
103    
104            public boolean isMDAT() {
105                    return _type.equalsIgnoreCase(MDAT);
106            }
107    
108            public boolean isMOOV() {
109                    return _type.equalsIgnoreCase(MOOV);
110            }
111    
112            public boolean isTopLevelAtom() {
113                    for (String topLevelAtom : TOP_LEVEL_ATOMS) {
114                            if (_type.equalsIgnoreCase(topLevelAtom)) {
115                                    return true;
116                            }
117                    }
118    
119                    return false;
120            }
121    
122            public void patchAtom() {
123                    for (int index = 4; index < _size - 4; index++) {
124                            String type = new String(
125                                    ArrayUtil.clone(_buffer, index, index + 4));
126    
127                            if (type.equalsIgnoreCase(Atom.STCO)) {
128                                    index += patchStcoAtom(index) - 4;
129                            }
130                            else if (type.equalsIgnoreCase(Atom.CO64)) {
131                                    index += patchCo64Atom(index) - 4;
132                            }
133                    }
134            }
135    
136            public void setBuffer(byte[] buffer) {
137                    _buffer = buffer;
138            }
139    
140            public void setOffset(long offset) {
141                    _offset = offset;
142            }
143    
144            public void setSize(long size) {
145                    _size = size;
146            }
147    
148            public void setType(String type) {
149                    _type = type;
150            }
151    
152            protected long bytesToLong(byte[] buffer) {
153                    long value = 0;
154    
155                    for (int i = 0; i < buffer.length; i++) {
156                            value += ((buffer[i] & _BITMASK) << 8 * (buffer.length - i - 1));
157                    }
158    
159                    return value;
160            }
161    
162            protected boolean hasCompressedMoovAtom() {
163                    String type = new String(ArrayUtil.clone(_buffer, 12, 15));
164    
165                    if (type.equalsIgnoreCase(Atom.CMOV)) {
166                            return true;
167                    }
168                    else {
169                            return false;
170                    }
171            }
172    
173            protected int patchCo64Atom(int index) {
174                    int size = (int)bytesToLong(ArrayUtil.clone(_buffer, index - 4, index));
175    
176                    int offsetCount = (int)bytesToLong(
177                            ArrayUtil.clone(_buffer, index + 8, index + 12));
178    
179                    for (int i = 0; i < offsetCount; i++) {
180                            int offsetIndex = index + 12 + i * 8;
181    
182                            long offset = bytesToLong(
183                                    ArrayUtil.clone(_buffer, offsetIndex, offsetIndex + 8));
184    
185                            offset += _size;
186    
187                            _buffer[offsetIndex + 0] = (byte)((offset >> 56) & 0xFF);
188                            _buffer[offsetIndex + 1] = (byte)((offset >> 48) & 0xFF);
189                            _buffer[offsetIndex + 2] = (byte)((offset >> 40) & 0xFF);
190                            _buffer[offsetIndex + 3] = (byte)((offset >> 32) & 0xFF);
191                            _buffer[offsetIndex + 4] = (byte)((offset >> 24) & 0xFF);
192                            _buffer[offsetIndex + 5] = (byte)((offset >> 16) & 0xFF);
193                            _buffer[offsetIndex + 6] = (byte)((offset >> 8) & 0xFF);
194                            _buffer[offsetIndex + 7] = (byte)((offset >> 0) & 0xFF);
195                    }
196    
197                    return size;
198            }
199    
200            protected int patchStcoAtom(int index) {
201                    int size = (int)bytesToLong(ArrayUtil.clone(_buffer, index - 4, index));
202    
203                    int offsetCount = (int)bytesToLong(
204                            ArrayUtil.clone(_buffer, index + 8, index + 12));
205    
206                    for (int i = 0; i < offsetCount; i++) {
207                            int offsetIndex = index + 12 + i * 4;
208    
209                            int offset = (int)bytesToLong(
210                                    ArrayUtil.clone(_buffer, offsetIndex, offsetIndex + 4));
211    
212                            offset += _size;
213    
214                            _buffer[offsetIndex + 0] = (byte)((offset >> 24) & 0xFF);
215                            _buffer[offsetIndex + 1] = (byte)((offset >> 16) & 0xFF);
216                            _buffer[offsetIndex + 2] = (byte)((offset >> 8) & 0xFF);
217                            _buffer[offsetIndex + 3] = (byte)((offset >> 0) & 0xFF);
218                    }
219    
220                    return size;
221            }
222    
223            private static final int _BITMASK = 0x00000000000000FF;
224    
225            private byte[] _buffer;
226            private long _offset;
227            private long _size;
228            private String _type;
229    
230    }