Fix some categories of error prone warnings

When switching from Stack to ArrayDeque, calls to add() need to be replaced by
calls to push() because ArrayDeque treats the first element in the list as the
top of the stack.

String.split() has counterintuitive default behavior; see
https://github.com/google/error-prone/blob/master/docs/bugpattern/StringSplitter.md.
I've switched usages to pass limit = -1 argument, which means empty elements are
no longer removed from the end of the returned array.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=199472592
This commit is contained in:
andrewlewis 2018-06-06 08:55:07 -07:00 committed by Oliver Woodman
parent 879f689488
commit ef8a47ba7d
35 changed files with 169 additions and 77 deletions

View File

@ -1543,6 +1543,7 @@ import java.util.Collections;
}
}
@SuppressWarnings("ParameterNotNullable")
private void updatePlayingPeriodRenderers(@Nullable MediaPeriodHolder oldPlayingPeriodHolder)
throws ExoPlaybackException {
MediaPeriodHolder newPlayingPeriodHolder = queue.getPlayingPeriod();

View File

@ -17,7 +17,7 @@ package com.google.android.exoplayer2.decoder;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import java.util.LinkedList;
import java.util.ArrayDeque;
/**
* Base class for {@link Decoder}s that use their own decode thread.
@ -28,8 +28,8 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
private final Thread decodeThread;
private final Object lock;
private final LinkedList<I> queuedInputBuffers;
private final LinkedList<O> queuedOutputBuffers;
private final ArrayDeque<I> queuedInputBuffers;
private final ArrayDeque<O> queuedOutputBuffers;
private final I[] availableInputBuffers;
private final O[] availableOutputBuffers;
@ -48,8 +48,8 @@ public abstract class SimpleDecoder<I extends DecoderInputBuffer, O extends Outp
*/
protected SimpleDecoder(I[] inputBuffers, O[] outputBuffers) {
lock = new Object();
queuedInputBuffers = new LinkedList<>();
queuedOutputBuffers = new LinkedList<>();
queuedInputBuffers = new ArrayDeque<>();
queuedOutputBuffers = new ArrayDeque<>();
availableInputBuffers = inputBuffers;
availableInputBufferCount = inputBuffers.length;
for (int i = 0; i < availableInputBufferCount; i++) {

View File

@ -108,7 +108,8 @@ public final class HttpMediaDrmCallback implements MediaDrmCallback {
@Override
public byte[] executeProvisionRequest(UUID uuid, ProvisionRequest request) throws IOException {
String url = request.getDefaultUrl() + "&signedRequest=" + new String(request.getData());
String url =
request.getDefaultUrl() + "&signedRequest=" + Util.fromUtf8Bytes(request.getData());
return executePost(dataSourceFactory, url, new byte[0], null);
}

View File

@ -24,7 +24,7 @@ import java.io.EOFException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Stack;
import java.util.ArrayDeque;
/**
* Default implementation of {@link EbmlReader}.
@ -46,15 +46,21 @@ import java.util.Stack;
private static final int VALID_FLOAT32_ELEMENT_SIZE_BYTES = 4;
private static final int VALID_FLOAT64_ELEMENT_SIZE_BYTES = 8;
private final byte[] scratch = new byte[8];
private final Stack<MasterElement> masterElementsStack = new Stack<>();
private final VarintReader varintReader = new VarintReader();
private final byte[] scratch;
private final ArrayDeque<MasterElement> masterElementsStack;
private final VarintReader varintReader;
private EbmlReaderOutput output;
private @ElementState int elementState;
private int elementId;
private long elementContentSize;
public DefaultEbmlReader() {
scratch = new byte[8];
masterElementsStack = new ArrayDeque<>();
varintReader = new VarintReader();
}
@Override
public void init(EbmlReaderOutput eventHandler) {
this.output = eventHandler;
@ -100,7 +106,7 @@ import java.util.Stack;
case EbmlReaderOutput.TYPE_MASTER:
long elementContentPosition = input.getPosition();
long elementEndPosition = elementContentPosition + elementContentSize;
masterElementsStack.add(new MasterElement(elementId, elementEndPosition));
masterElementsStack.push(new MasterElement(elementId, elementEndPosition));
output.startMasterElement(elementId, elementContentPosition, elementContentSize);
elementState = ELEMENT_STATE_READ_ID;
return true;

View File

@ -78,8 +78,9 @@ import java.io.IOException;
return false;
}
if (size != 0) {
input.advancePeekPosition((int) size);
peekLength += size;
int sizeInt = (int) size;
input.advancePeekPosition(sizeInt);
peekLength += sizeInt;
}
}
return peekLength == headerStart + headerSize;

View File

@ -108,4 +108,7 @@ import com.google.android.exoplayer2.util.Util;
return new Results(offsets, sizes, maximumSize, timestamps, flags, duration);
}
private FixedSampleSizeRechunker() {
// Prevent instantiation.
}
}

View File

@ -50,7 +50,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.UUID;
/**
@ -141,7 +140,7 @@ public final class FragmentedMp4Extractor implements Extractor {
// Parser state.
private final ParsableByteArray atomHeader;
private final byte[] extendedTypeScratch;
private final Stack<ContainerAtom> containerAtoms;
private final ArrayDeque<ContainerAtom> containerAtoms;
private final ArrayDeque<MetadataSampleInfo> pendingMetadataSampleInfos;
private final @Nullable TrackOutput additionalEmsgTrackOutput;
@ -257,7 +256,7 @@ public final class FragmentedMp4Extractor implements Extractor {
nalPrefix = new ParsableByteArray(5);
nalBuffer = new ParsableByteArray();
extendedTypeScratch = new byte[16];
containerAtoms = new Stack<>();
containerAtoms = new ArrayDeque<>();
pendingMetadataSampleInfos = new ArrayDeque<>();
trackBundles = new SparseArray<>();
durationUs = C.TIME_UNSET;
@ -390,7 +389,7 @@ public final class FragmentedMp4Extractor implements Extractor {
if (shouldParseContainerAtom(atomType)) {
long endPosition = input.getPosition() + atomSize - Atom.HEADER_SIZE;
containerAtoms.add(new ContainerAtom(atomType, endPosition));
containerAtoms.push(new ContainerAtom(atomType, endPosition));
if (atomSize == atomHeaderBytesRead) {
processAtomEnded(endPosition);
} else {

View File

@ -37,9 +37,9 @@ import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* Extracts data from the MP4 container format.
@ -101,7 +101,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
private final ParsableByteArray nalLength;
private final ParsableByteArray atomHeader;
private final Stack<ContainerAtom> containerAtoms;
private final ArrayDeque<ContainerAtom> containerAtoms;
@State private int parserState;
private int atomType;
@ -137,7 +137,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
public Mp4Extractor(@Flags int flags) {
this.flags = flags;
atomHeader = new ParsableByteArray(Atom.LONG_HEADER_SIZE);
containerAtoms = new Stack<>();
containerAtoms = new ArrayDeque<>();
nalStartCode = new ParsableByteArray(NalUnitUtil.NAL_START_CODE);
nalLength = new ParsableByteArray(4);
sampleTrackIndex = C.INDEX_UNSET;
@ -303,7 +303,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
if (shouldParseContainerAtom(atomType)) {
long endPosition = input.getPosition() + atomSize - atomHeaderBytesRead;
containerAtoms.add(new ContainerAtom(atomType, endPosition));
containerAtoms.push(new ContainerAtom(atomType, endPosition));
if (atomSize == atomHeaderBytesRead) {
processAtomEnded(endPosition);
} else {

View File

@ -49,6 +49,7 @@ public final class PsshAtomUtil {
* @param data The scheme specific data.
* @return The PSSH atom.
*/
@SuppressWarnings("ParameterNotNullable")
public static byte[] buildPsshAtom(
UUID systemId, @Nullable UUID[] keyIds, @Nullable byte[] data) {
boolean buildV1Atom = keyIds != null;

View File

@ -130,6 +130,6 @@ import java.util.List;
} else {
length = 10000 << length;
}
return frames * length;
return (long) frames * length;
}
}

View File

@ -357,12 +357,12 @@ import java.util.Arrays;
for (int i = 0; i < lengthMap.length; i++) {
if (isSparse) {
if (bitArray.readBit()) {
lengthMap[i] = bitArray.readBits(5) + 1;
lengthMap[i] = (long) (bitArray.readBits(5) + 1);
} else { // entry unused
lengthMap[i] = 0;
}
} else { // not sparse
lengthMap[i] = bitArray.readBits(5) + 1;
lengthMap[i] = (long) (bitArray.readBits(5) + 1);
}
}
} else {
@ -392,7 +392,7 @@ import java.util.Arrays;
lookupValuesCount = 0;
}
} else {
lookupValuesCount = entries * dimensions;
lookupValuesCount = (long) entries * dimensions;
}
// discard (no decoding required yet)
bitArray.skipBits((int) (lookupValuesCount * valueBits));
@ -407,6 +407,10 @@ import java.util.Arrays;
return (long) Math.floor(Math.pow(entries, 1.d / dimension));
}
private VorbisUtil() {
// Prevent instantiation.
}
public static final class CodeBook {
public final int dimensions;

View File

@ -25,7 +25,7 @@ import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
/** Reads a {@code WavHeader} from an input stream; supports resuming from input failures. */
/*package*/ final class WavHeaderReader {
/* package */ final class WavHeaderReader {
private static final String TAG = "WavHeaderReader";
@ -158,6 +158,10 @@ import java.io.IOException;
wavHeader.setDataBounds(input.getPosition(), chunkHeader.size);
}
private WavHeaderReader() {
// Prevent instantiation.
}
/** Container for a WAV chunk header. */
private static final class ChunkHeader {

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2.offline;
package com.google.android.exoplayer2.offline;
import android.net.Uri;
import com.google.android.exoplayer2.C;

View File

@ -201,6 +201,8 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M, K>, K>
throws InterruptedException, IOException;
/** Initializes the download, returning a list of {@link Segment}s that need to be downloaded. */
// Writes to downloadedSegments and downloadedBytes are safe. See the comment on download().
@SuppressWarnings("NonAtomicVolatileUpdate")
private List<Segment> initDownload() throws IOException, InterruptedException {
M manifest = getManifest(dataSource, manifestUri);
if (!streamKeys.isEmpty()) {

View File

@ -72,11 +72,14 @@ public final class TrackGroup implements Parcelable {
}
/**
* Returns the index of the track with the given format in the group.
* Returns the index of the track with the given format in the group. The format is located by
* identity so, for example, {@code group.indexOf(group.getFormat(index)) == index} even if
* multiple tracks have formats that contain the same values.
*
* @param format The format.
* @return The index of the track, or {@link C#INDEX_UNSET} if no such track exists.
*/
@SuppressWarnings("ReferenceEquality")
public int indexOf(Format format) {
for (int i = 0; i < formats.length; i++) {
if (format == formats[i]) {

View File

@ -38,7 +38,6 @@ import com.google.android.exoplayer2.util.ParsableBitArray;
import com.google.android.exoplayer2.util.ParsableByteArray;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
@ -196,7 +195,10 @@ public final class Cea708Decoder extends CeaDecoder {
@Override
protected void decode(SubtitleInputBuffer inputBuffer) {
ccData.reset(inputBuffer.data.array(), inputBuffer.data.limit());
// Subtitle input buffers are non-direct and the position is zero, so calling array() is safe.
@SuppressWarnings("ByteBufferBackingArray")
byte[] inputBufferData = inputBuffer.data.array();
ccData.reset(inputBufferData, inputBuffer.data.limit());
while (ccData.bytesLeft() >= 3) {
int ccTypeAndValid = (ccData.readUnsignedByte() & 0x07);
@ -879,7 +881,7 @@ public final class Cea708Decoder extends CeaDecoder {
private int row;
public CueBuilder() {
rolledUpCaptions = new LinkedList<>();
rolledUpCaptions = new ArrayList<>();
captionStringBuilder = new SpannableStringBuilder();
reset();
}

View File

@ -24,7 +24,7 @@ import com.google.android.exoplayer2.text.SubtitleDecoderException;
import com.google.android.exoplayer2.text.SubtitleInputBuffer;
import com.google.android.exoplayer2.text.SubtitleOutputBuffer;
import com.google.android.exoplayer2.util.Assertions;
import java.util.LinkedList;
import java.util.ArrayDeque;
import java.util.PriorityQueue;
/**
@ -35,8 +35,8 @@ import java.util.PriorityQueue;
private static final int NUM_INPUT_BUFFERS = 10;
private static final int NUM_OUTPUT_BUFFERS = 2;
private final LinkedList<CeaInputBuffer> availableInputBuffers;
private final LinkedList<SubtitleOutputBuffer> availableOutputBuffers;
private final ArrayDeque<CeaInputBuffer> availableInputBuffers;
private final ArrayDeque<SubtitleOutputBuffer> availableOutputBuffers;
private final PriorityQueue<CeaInputBuffer> queuedInputBuffers;
private CeaInputBuffer dequeuedInputBuffer;
@ -44,11 +44,11 @@ import java.util.PriorityQueue;
private long queuedInputBufferCount;
public CeaDecoder() {
availableInputBuffers = new LinkedList<>();
availableInputBuffers = new ArrayDeque<>();
for (int i = 0; i < NUM_INPUT_BUFFERS; i++) {
availableInputBuffers.add(new CeaInputBuffer());
}
availableOutputBuffers = new LinkedList<>();
availableOutputBuffers = new ArrayDeque<>();
for (int i = 0; i < NUM_OUTPUT_BUFFERS; i++) {
availableOutputBuffers.add(new CeaOutputBuffer());
}

View File

@ -62,7 +62,7 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
super("SsaDecoder");
if (initializationData != null && !initializationData.isEmpty()) {
haveInitializationData = true;
String formatLine = new String(initializationData.get(0));
String formatLine = Util.fromUtf8Bytes(initializationData.get(0));
Assertions.checkArgument(formatLine.startsWith(FORMAT_LINE_PREFIX));
parseFormatLine(formatLine);
parseHeader(new ParsableByteArray(initializationData.get(1)));

View File

@ -26,8 +26,8 @@ import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.util.XmlPullParserUtil;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -109,13 +109,13 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes, 0, length);
xmlParser.setInput(inputStream, null);
TtmlSubtitle ttmlSubtitle = null;
LinkedList<TtmlNode> nodeStack = new LinkedList<>();
ArrayDeque<TtmlNode> nodeStack = new ArrayDeque<>();
int unsupportedNodeDepth = 0;
int eventType = xmlParser.getEventType();
FrameAndTickRate frameAndTickRate = DEFAULT_FRAME_AND_TICK_RATE;
CellResolution cellResolution = DEFAULT_CELL_RESOLUTION;
while (eventType != XmlPullParser.END_DOCUMENT) {
TtmlNode parent = nodeStack.peekLast();
TtmlNode parent = nodeStack.peek();
if (unsupportedNodeDepth == 0) {
String name = xmlParser.getName();
if (eventType == XmlPullParser.START_TAG) {
@ -131,7 +131,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
} else {
try {
TtmlNode node = parseNode(xmlParser, parent, regionMap, frameAndTickRate);
nodeStack.addLast(node);
nodeStack.push(node);
if (parent != null) {
parent.addChild(node);
}
@ -145,9 +145,9 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
parent.addChild(TtmlNode.buildTextNode(xmlParser.getText()));
} else if (eventType == XmlPullParser.END_TAG) {
if (xmlParser.getName().equals(TtmlNode.TAG_TT)) {
ttmlSubtitle = new TtmlSubtitle(nodeStack.getLast(), globalStyles, regionMap);
ttmlSubtitle = new TtmlSubtitle(nodeStack.peek(), globalStyles, regionMap);
}
nodeStack.removeLast();
nodeStack.pop();
}
} else {
if (eventType == XmlPullParser.START_TAG) {
@ -178,7 +178,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
float frameRateMultiplier = 1;
String frameRateMultiplierString = xmlParser.getAttributeValue(TTP, "frameRateMultiplier");
if (frameRateMultiplierString != null) {
String[] parts = frameRateMultiplierString.split(" ");
String[] parts = Util.split(frameRateMultiplierString, " ");
if (parts.length != 2) {
throw new SubtitleDecoderException("frameRateMultiplier doesn't have 2 parts");
}
@ -354,7 +354,8 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
}
private String[] parseStyleIds(String parentStyleIds) {
return parentStyleIds.split("\\s+");
parentStyleIds = parentStyleIds.trim();
return parentStyleIds.isEmpty() ? new String[0] : Util.split(parentStyleIds, "\\s+");
}
private TtmlStyle parseStyleAttributes(XmlPullParser parser, TtmlStyle style) {
@ -531,7 +532,7 @@ public final class TtmlDecoder extends SimpleSubtitleDecoder {
private static void parseFontSize(String expression, TtmlStyle out) throws
SubtitleDecoderException {
String[] expressions = expression.split("\\s+");
String[] expressions = Util.split(expression, "\\s+");
Matcher matcher;
if (expressions.length == 1) {
matcher = FONT_SIZE.matcher(expression);

View File

@ -92,7 +92,8 @@ public final class Tx3gDecoder extends SimpleSubtitleDecoder {
| ((initializationBytes[27] & 0xFF) << 16)
| ((initializationBytes[28] & 0xFF) << 8)
| (initializationBytes[29] & 0xFF);
String fontFamily = new String(initializationBytes, 43, initializationBytes.length - 43);
String fontFamily =
Util.fromUtf8Bytes(initializationBytes, 43, initializationBytes.length - 43);
defaultFontFamily = TX3G_SERIF.equals(fontFamily) ? C.SERIF_NAME : C.SANS_SERIF_NAME;
//font size (initializationBytes[25]) is 5% of video height
calculatedVideoTrackHeight = 20 * initializationBytes[25];

View File

@ -18,6 +18,7 @@ package com.google.android.exoplayer2.text.webvtt;
import android.text.TextUtils;
import com.google.android.exoplayer2.util.ColorParser;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -314,7 +315,7 @@ import java.util.regex.Pattern;
}
selector = selector.substring(0, voiceStartIndex);
}
String[] classDivision = selector.split("\\.");
String[] classDivision = Util.split(selector, "\\.");
String tagAndIdDivision = classDivision[0];
int idPrefixIndex = tagAndIdDivision.indexOf('#');
if (idPrefixIndex != -1) {

View File

@ -78,7 +78,8 @@ public final class Mp4WebvttDecoder extends SimpleSubtitleDecoder {
int boxType = sampleData.readInt();
remainingCueBoxBytes -= BOX_HEADER_SIZE;
int payloadLength = boxSize - BOX_HEADER_SIZE;
String boxPayload = new String(sampleData.data, sampleData.getPosition(), payloadLength);
String boxPayload =
Util.fromUtf8Bytes(sampleData.data, sampleData.getPosition(), payloadLength);
sampleData.skipBytes(payloadLength);
remainingCueBoxBytes -= payloadLength;
if (boxType == TYPE_sttg) {

View File

@ -34,11 +34,12 @@ import android.text.style.UnderlineSpan;
import android.util.Log;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -157,7 +158,7 @@ public final class WebvttCueParser {
/* package */ static void parseCueText(String id, String markup, WebvttCue.Builder builder,
List<WebvttCssStyle> styles) {
SpannableStringBuilder spannedText = new SpannableStringBuilder();
Stack<StartTag> startTagStack = new Stack<>();
ArrayDeque<StartTag> startTagStack = new ArrayDeque<>();
List<StyleMatch> scratchStyleMatches = new ArrayList<>();
int pos = 0;
while (pos < markup.length()) {
@ -456,7 +457,7 @@ public final class WebvttCueParser {
if (tagExpression.isEmpty()) {
return null;
}
return tagExpression.split("[ \\.]")[0];
return Util.splitAtFirst(tagExpression, "[ \\.]")[0];
}
private static void getApplicableStyles(List<WebvttCssStyle> declaredStyles, String id,
@ -518,7 +519,7 @@ public final class WebvttCueParser {
voice = fullTagExpression.substring(voiceStartIndex).trim();
fullTagExpression = fullTagExpression.substring(0, voiceStartIndex);
}
String[] nameAndClasses = fullTagExpression.split("\\.");
String[] nameAndClasses = Util.split(fullTagExpression, "\\.");
String name = nameAndClasses[0];
String[] classes;
if (nameAndClasses.length > 1) {

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.text.webvtt;
import com.google.android.exoplayer2.text.SubtitleDecoderException;
import com.google.android.exoplayer2.util.ParsableByteArray;
import com.google.android.exoplayer2.util.Util;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -53,8 +54,8 @@ public final class WebvttParserUtil {
*/
public static long parseTimestampUs(String timestamp) throws NumberFormatException {
long value = 0;
String[] parts = timestamp.split("\\.", 2);
String[] subparts = parts[0].split(":");
String[] parts = Util.splitAtFirst(timestamp, "\\.");
String[] subparts = Util.split(parts[0], ":");
for (String subpart : subparts) {
value = (value * 60) + Long.parseLong(subpart);
}

View File

@ -110,6 +110,7 @@ public abstract class BaseTrackSelection implements TrackSelection {
}
@Override
@SuppressWarnings("ReferenceEquality")
public final int indexOf(Format format) {
for (int i = 0; i < length; i++) {
if (formats[i] == format) {
@ -183,7 +184,9 @@ public abstract class BaseTrackSelection implements TrackSelection {
return hashCode;
}
// Track groups are compared by identity not value, as distinct groups may have the same value.
@Override
@SuppressWarnings("ReferenceEquality")
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;

View File

@ -91,7 +91,9 @@ public interface TrackSelection {
int getIndexInTrackGroup(int index);
/**
* Returns the index in the selection of the track with the specified format.
* Returns the index in the selection of the track with the specified format. The format is
* located by identity so, for example, {@code selection.indexOf(selection.getFormat(index)) ==
* index} even if multiple selected tracks have formats that contain the same values.
*
* @param format The format.
* @return The index in the selection, or {@link C#INDEX_UNSET} if the track with the specified

View File

@ -19,6 +19,7 @@ import android.net.Uri;
import android.util.Base64;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.net.URLDecoder;
@ -41,8 +42,8 @@ public final class DataSchemeDataSource implements DataSource {
if (!SCHEME_DATA.equals(scheme)) {
throw new ParserException("Unsupported scheme: " + scheme);
}
String[] uriParts = uri.getSchemeSpecificPart().split(",");
if (uriParts.length > 2) {
String[] uriParts = Util.split(uri.getSchemeSpecificPart(), ",");
if (uriParts.length != 2) {
throw new ParserException("Unexpected URI format: " + uri);
}
String dataString = uriParts[1];

View File

@ -20,7 +20,7 @@ import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
/** Helper classes to easily access and modify internal metadata values. */
/*package*/ final class ContentMetadataInternal {
/* package */ final class ContentMetadataInternal {
private static final String PREFIX = ContentMetadata.INTERNAL_METADATA_NAME_PREFIX;
private static final String METADATA_NAME_REDIRECTED_URI = PREFIX + "redir";
@ -59,4 +59,8 @@ import com.google.android.exoplayer2.C;
public static void removeRedirectedUri(ContentMetadataMutations mutations) {
mutations.remove(METADATA_NAME_REDIRECTED_URI);
}
private ContentMetadataInternal() {
// Prevent instantiation.
}
}

View File

@ -16,6 +16,7 @@
package com.google.android.exoplayer2.upstream.crypto;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@ -49,7 +50,9 @@ public final class AesFlushingCipher {
flushedBlock = new byte[blockSize];
long counter = offset / blockSize;
int startPadding = (int) (offset % blockSize);
cipher.init(mode, new SecretKeySpec(secretKey, cipher.getAlgorithm().split("/")[0]),
cipher.init(
mode,
new SecretKeySpec(secretKey, Util.splitAtFirst(cipher.getAlgorithm(), "/")[0]),
new IvParameterSpec(getInitializationVector(nonce, counter)));
if (startPadding != 0) {
updateInPlace(new byte[startPadding], 0, startPadding);

View File

@ -26,7 +26,7 @@ import java.util.regex.Pattern;
*
* @see <a href="https://w3c.github.io/webvtt/#styling">WebVTT CSS Styling</a>
* @see <a href="https://www.w3.org/TR/ttml2/">Timed Text Markup Language 2 (TTML2) - 10.3.5</a>
**/
*/
public final class ColorParser {
private static final String RGB = "rgb";
@ -271,4 +271,7 @@ public final class ColorParser {
COLOR_MAP.put("yellowgreen", 0xFF9ACD32);
}
private ColorParser() {
// Prevent instantiation.
}
}

View File

@ -144,7 +144,7 @@ public final class MimeTypes {
if (codecs == null) {
return null;
}
String[] codecList = codecs.split(",");
String[] codecList = Util.split(codecs, ",");
for (String codec : codecList) {
String mimeType = getMediaMimeType(codec);
if (mimeType != null && isVideo(mimeType)) {
@ -164,7 +164,7 @@ public final class MimeTypes {
if (codecs == null) {
return null;
}
String[] codecList = codecs.split(",");
String[] codecList = Util.split(codecs, ",");
for (String codec : codecList) {
String mimeType = getMediaMimeType(codec);
if (mimeType != null && isAudio(mimeType)) {

View File

@ -175,7 +175,7 @@ public final class ParsableBitArray {
bitOffset -= 8;
returnValue |= (data[byteOffset++] & 0xFF) << bitOffset;
}
returnValue |= (data[byteOffset] & 0xFF) >> 8 - bitOffset;
returnValue |= (data[byteOffset] & 0xFF) >> (8 - bitOffset);
returnValue &= 0xFFFFFFFF >>> (32 - numBits);
if (bitOffset == 8) {
bitOffset = 0;
@ -199,17 +199,18 @@ public final class ParsableBitArray {
int to = offset + (numBits >> 3) /* numBits / 8 */;
for (int i = offset; i < to; i++) {
buffer[i] = (byte) (data[byteOffset++] << bitOffset);
buffer[i] |= (data[byteOffset] & 0xFF) >> (8 - bitOffset);
buffer[i] = (byte) (buffer[i] | ((data[byteOffset] & 0xFF) >> (8 - bitOffset)));
}
// Trailing bits.
int bitsLeft = numBits & 7 /* numBits % 8 */;
if (bitsLeft == 0) {
return;
}
buffer[to] &= 0xFF >> bitsLeft; // Set to 0 the bits that are going to be overwritten.
// Set bits that are going to be overwritten to 0.
buffer[to] = (byte) (buffer[to] & (0xFF >> bitsLeft));
if (bitOffset + bitsLeft > 8) {
// We read the rest of data[byteOffset] and increase byteOffset.
buffer[to] |= (byte) ((data[byteOffset++] & 0xFF) << bitOffset);
buffer[to] = (byte) (buffer[to] | ((data[byteOffset++] & 0xFF) << bitOffset));
bitOffset -= 8;
}
bitOffset += bitsLeft;
@ -280,9 +281,10 @@ public final class ParsableBitArray {
int firstByteReadSize = Math.min(8 - bitOffset, numBits);
int firstByteRightPaddingSize = 8 - bitOffset - firstByteReadSize;
int firstByteBitmask = (0xFF00 >> bitOffset) | ((1 << firstByteRightPaddingSize) - 1);
data[byteOffset] &= firstByteBitmask;
data[byteOffset] = (byte) (data[byteOffset] & firstByteBitmask);
int firstByteInputBits = value >>> (numBits - firstByteReadSize);
data[byteOffset] |= firstByteInputBits << firstByteRightPaddingSize;
data[byteOffset] =
(byte) (data[byteOffset] | (firstByteInputBits << firstByteRightPaddingSize));
remainingBitsToRead -= firstByteReadSize;
int currentByteIndex = byteOffset + 1;
while (remainingBitsToRead > 8) {
@ -290,9 +292,11 @@ public final class ParsableBitArray {
remainingBitsToRead -= 8;
}
int lastByteRightPaddingSize = 8 - remainingBitsToRead;
data[currentByteIndex] &= (1 << lastByteRightPaddingSize) - 1;
data[currentByteIndex] =
(byte) (data[currentByteIndex] & ((1 << lastByteRightPaddingSize) - 1));
int lastByteInput = value & ((1 << remainingBitsToRead) - 1);
data[currentByteIndex] |= lastByteInput << lastByteRightPaddingSize;
data[currentByteIndex] =
(byte) (data[currentByteIndex] | (lastByteInput << lastByteRightPaddingSize));
skipBits(numBits);
assertValidOffset();
}

View File

@ -470,7 +470,7 @@ public final class ParsableByteArray {
if (lastIndex < limit && data[lastIndex] == 0) {
stringLength--;
}
String result = new String(data, position, stringLength);
String result = Util.fromUtf8Bytes(data, position, stringLength);
position += length;
return result;
}
@ -489,7 +489,7 @@ public final class ParsableByteArray {
while (stringLimit < limit && data[stringLimit] != 0) {
stringLimit++;
}
String string = new String(data, position, stringLimit - position);
String string = Util.fromUtf8Bytes(data, position, stringLimit - position);
position = stringLimit;
if (position < limit) {
position++;
@ -520,7 +520,7 @@ public final class ParsableByteArray {
// There's a byte order mark at the start of the line. Discard it.
position += 3;
}
String line = new String(data, position, lineLimit - position);
String line = Util.fromUtf8Bytes(data, position, lineLimit - position);
position = lineLimit;
if (position == limit) {
return line;

View File

@ -140,7 +140,7 @@ public final class ParsableNalUnitBitArray {
returnValue |= (data[byteOffset] & 0xFF) << bitOffset;
byteOffset += shouldSkipByte(byteOffset + 1) ? 2 : 1;
}
returnValue |= (data[byteOffset] & 0xFF) >> 8 - bitOffset;
returnValue |= (data[byteOffset] & 0xFF) >> (8 - bitOffset);
returnValue &= 0xFFFFFFFF >>> (32 - numBits);
if (bitOffset == 8) {
bitOffset = 0;

View File

@ -332,6 +332,18 @@ public final class Util {
return new String(bytes, Charset.forName(C.UTF8_NAME));
}
/**
* Returns a new {@link String} constructed by decoding UTF-8 encoded bytes in a subarray.
*
* @param bytes The UTF-8 encoded bytes to decode.
* @param offset The index of the first byte to decode.
* @param length The number of bytes to decode.
* @return The string.
*/
public static String fromUtf8Bytes(byte[] bytes, int offset, int length) {
return new String(bytes, offset, length, Charset.forName(C.UTF8_NAME));
}
/**
* Returns a new byte array containing the code points of a {@link String} encoded using UTF-8.
*
@ -342,6 +354,33 @@ public final class Util {
return value.getBytes(Charset.forName(C.UTF8_NAME));
}
/**
* Splits a string using {@code value.split(regex, -1}). Note: this is is similar to {@link
* String#split(String)} but empty matches at the end of the string will not be omitted from the
* returned array.
*
* @param value The string to split.
* @param regex A delimiting regular expression.
* @return The array of strings resulting from splitting the string.
*/
public static String[] split(String value, String regex) {
return value.split(regex, /* limit= */ -1);
}
/**
* Splits the string at the first occurrence of the delimiter {@code regex}. If the delimiter does
* not match, returns an array with one element which is the input string. If the delimiter does
* match, returns an array with the portion of the string before the delimiter and the rest of the
* string.
*
* @param value The string.
* @param regex A delimiting regular expression.
* @return The string split by the first occurrence of the delimiter.
*/
public static String[] splitAtFirst(String value, String regex) {
return value.split(regex, /* limit= */ 2);
}
/**
* Returns whether the given character is a carriage return ('\r') or a line feed ('\n').
*
@ -978,7 +1017,7 @@ public final class Util {
if (TextUtils.isEmpty(codecs)) {
return null;
}
String[] codecArray = codecs.trim().split("(\\s*,\\s*)");
String[] codecArray = split(codecs.trim(), "(\\s*,\\s*)");
StringBuilder builder = new StringBuilder();
for (String codec : codecArray) {
if (trackType == MimeTypes.getTrackTypeOfCodec(codec)) {
@ -1454,7 +1493,7 @@ public final class Util {
// If we managed to read sys.display-size, attempt to parse it.
if (!TextUtils.isEmpty(sysDisplaySize)) {
try {
String[] sysDisplaySizeParts = sysDisplaySize.trim().split("x");
String[] sysDisplaySizeParts = split(sysDisplaySize.trim(), "x");
if (sysDisplaySizeParts.length == 2) {
int width = Integer.parseInt(sysDisplaySizeParts[0]);
int height = Integer.parseInt(sysDisplaySizeParts[1]);