package com.mercandalli.android.apps.files.file.audio.metadata.read; // // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // import android.support.annotation.NonNull; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.Vector; /* package */ class MyID3v2Read { private static final String LEGAL_FRAME_ID_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; private static final int kHIGH_BIT = 128; private final InputStream mInputStream; private final boolean async; private boolean complete = false; private boolean error = false; private boolean no_tag = false; private boolean stream_complete = false; private boolean header_read = false; private boolean tagRead = false; private int index = 0; private int last = -1; private byte versionMajor; private byte versionMinor; private boolean tagUnsynchronization = false; private boolean tagCompression = false; private boolean tagExtendedHeader = false; private boolean tagExperimentalIndicator = false; private boolean tagFooterPresent = false; @NonNull private final Vector mTags = new Vector(); @NonNull private final ByteArrayOutputStream mByteArrayOutputStream = new ByteArrayOutputStream(); private long mBytesRead = 0L; private int tagLength = 0; @NonNull private final byte[] mBuffer = new byte[1024]; private String errorMessage = null; public MyID3v2Read(final InputStream inputStream, final boolean async) { this.mInputStream = inputStream; this.async = async; } public void dump() { } public boolean isComplete() { return this.complete || this.error || this.no_tag; } public boolean isError() { return this.error; } public boolean hasTags() { return !this.error && this.complete && !this.no_tag; } public boolean iteration() { if (this.isComplete()) { return true; } if (!this.read()) { return false; } if (this.isComplete()) { return true; } if (!this.header_read) { if (this.mBytesRead < 10L) { if (this.stream_complete) { this.error = true; } return true; } this.readHeader(); } if (!this.tagRead) { if (this.mBytesRead < (long) this.tagLength) { if (this.stream_complete) { this.error = true; } return true; } this.readTag(); this.complete = true; } return true; } private int readInt3(byte[] bytes, boolean check_tagLength) { if (this.index + 2 >= this.tagLength && check_tagLength) { this.setError("readInt3(index: " + this.index + ", tagLength: " + this.tagLength); return -1; } else if (this.index + 3 >= bytes.length) { this.setError("readInt3(index: " + this.index + ", bytes.length: " + bytes.length); return -1; } else { int[] array = new int[]{255 & bytes[this.index++], 255 & bytes[this.index++], 255 & bytes[this.index++]}; return array[0] << 16 | array[1] << 8 | array[2] << 0; } } public static Number readSynchsafeInt(byte[] bytes, int start) { if (start + 3 >= bytes.length) { return null; } else { int[] var10000 = new int[4]; int index = start + 1; var10000[0] = 255 & bytes[start]; var10000[1] = 255 & bytes[index++]; var10000[2] = 255 & bytes[index++]; var10000[3] = 255 & bytes[index++]; int[] array = var10000; int result; for (result = 0; result < array.length; ++result) { if ((array[result] & 128) > 0) { array[result] &= 128; } } result = array[0] << 21 | array[1] << 14 | array[2] << 7 | array[3] << 0; return new Integer(result); } } private int readSynchsafeInt(byte[] bytes, boolean check_tagLength) { if (this.index + 3 >= this.tagLength && check_tagLength) { this.setError("readSynchsafeInt(index: " + this.index + ", tagLength: " + this.tagLength); return -1; } else if (this.index + 3 >= bytes.length) { this.setError("readSynchsafeInt(index: " + this.index + ", bytes.length: " + bytes.length); return -1; } else { int[] array = new int[]{255 & bytes[this.index++], 255 & bytes[this.index++], 255 & bytes[this.index++], 255 & bytes[this.index++]}; int result; for (result = 0; result < array.length; ++result) { if ((array[result] & 128) > 0) { array[result] &= 128; } } result = array[0] << 21 | array[1] << 14 | array[2] << 7 | array[3] << 0; return result; } } private int readInt(byte[] bytes, boolean check_tagLength) { if (this.index + 3 >= this.tagLength && check_tagLength) { this.setError("readInt(index: " + this.index + ", tagLength: " + this.tagLength); return -1; } else if (this.index + 3 >= bytes.length) { this.setError("readInt(index: " + this.index + ", bytes.length: " + bytes.length); return -1; } else { int[] array = new int[]{255 & bytes[this.index++], 255 & bytes[this.index++], 255 & bytes[this.index++], 255 & bytes[this.index++]}; return array[0] << 24 | array[1] << 16 | array[2] << 8 | array[3] << 0; } } private int readShort(byte[] bytes) { if (this.index + 1 < this.tagLength && this.index + 1 < bytes.length) { byte[] array = new byte[]{bytes[this.index++], bytes[this.index++]}; return array[0] << 8 | array[1] << 0; } else { this.setError("readShort(index: " + this.index + ", tagLength: " + this.tagLength + ", bytes.length: " + bytes.length); return -1; } } private void readHeader() { byte[] bytes = this.mByteArrayOutputStream.toByteArray(); if (bytes.length < 10) { this.setError("missing header"); } else { if (bytes[this.index++] != 73) { this.no_tag = true; } else if (bytes[this.index++] != 68) { this.no_tag = true; } else if (bytes[this.index++] != 51) { this.no_tag = true; } if (!this.error && !this.no_tag) { this.versionMajor = bytes[this.index++]; this.versionMinor = bytes[this.index++]; if (this.versionMajor >= 2 && this.versionMajor <= 4) { long flags = (long) bytes[this.index++]; long workingFlags = flags; if (this.versionMajor == 2) { if ((flags & 128L) > 0L) { this.tagUnsynchronization = true; workingFlags = flags ^ 128L; } if ((workingFlags & 64L) > 0L) { this.tagCompression = true; workingFlags ^= 64L; } } else if (this.versionMajor == 3) { if ((flags & 128L) > 0L) { this.tagUnsynchronization = true; workingFlags = flags ^ 128L; } if ((workingFlags & 64L) > 0L) { this.tagExtendedHeader = true; workingFlags ^= 64L; } if ((workingFlags & 32L) > 0L) { this.tagExperimentalIndicator = true; workingFlags ^= 32L; } if ((workingFlags & 16L) > 0L) { workingFlags ^= 16L; } } else { if (this.versionMajor != 4) { this.setError("Unknown id3v2 Major Version: " + this.versionMajor); return; } if ((flags & 128L) > 0L) { this.tagUnsynchronization = true; workingFlags = flags ^ 128L; } if ((workingFlags & 64L) > 0L) { this.tagExtendedHeader = true; workingFlags ^= 64L; } if ((workingFlags & 32L) > 0L) { this.tagExperimentalIndicator = true; workingFlags ^= 32L; } if ((workingFlags & 16L) > 0L) { this.tagFooterPresent = true; workingFlags ^= 16L; } } if (workingFlags > 0L) { this.setError("Unknown id3v2 tag flags(id3v2 version: " + this.versionMajor + "): " + Long.toHexString(flags)); } else { this.tagLength = this.readSynchsafeInt(bytes, false); this.tagLength += 10; this.last = this.tagLength; if (this.tagFooterPresent) { this.tagLength += 10; } this.header_read = true; if (this.index != 10) { this.setError("index!=kHEADER_SIZE"); } } } else { this.setError("Unknown id3v2 Major Version: " + this.versionMajor); } } } } private byte[] ununsynchronize(byte[] bytes) { final ByteArrayOutputStream result = new ByteArrayOutputStream(); int i = 0; while (i < bytes.length) { byte b = bytes[i++]; result.write(b); if ((255 & b) == 255) { if (i >= bytes.length) { break; } byte b1 = bytes[i]; if ((255 & b1) == 0) { ++i; } } } bytes = result.toByteArray(); return bytes; } private String parseFrameID(byte[] bytes) { for (final byte aByte : bytes) { int b = 255 & aByte; char c = (char) b; if ("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".indexOf(c) < 0) { this.setError("invalid id3v2 frame id byte: " + Integer.toHexString(b)); return null; } } return new String(bytes); } private boolean isZeroFrameId(byte[] bytes) { for (final byte aByte : bytes) { if ((255 & aByte) > 0) { return false; } } return true; } private void readTag() { byte[] bytes = this.mByteArrayOutputStream.toByteArray(); if (bytes.length < this.tagLength) { this.setError("missing tag"); } else { if (this.tagUnsynchronization) { bytes = this.ununsynchronize(bytes); } if (this.tagExtendedHeader) { this.index += 4; } for (int tag_num = 0; this.index + 7 < this.last && !this.error && this.index + 7 < this.last; ++tag_num) { byte[] frameID; if (this.versionMajor >= 3) { frameID = new byte[]{bytes[this.index++], bytes[this.index++], bytes[this.index++], bytes[this.index++]}; } else { frameID = new byte[]{bytes[this.index++], bytes[this.index++], bytes[this.index++]}; } if (this.isZeroFrameId(frameID)) { break; } String frameIDString = this.parseFrameID(frameID); if (frameIDString == null) { break; } int frameLength; if (this.versionMajor >= 4) { frameLength = this.readSynchsafeInt(bytes, true); } else if (this.versionMajor >= 3) { frameLength = this.readInt(bytes, true); } else { frameLength = this.readInt3(bytes, true); } int maxTagLength = this.tagLength - this.index; if (this.versionMajor >= 3) { maxTagLength += 2; } if (frameLength == 0) { break; } if (frameLength > maxTagLength || frameLength < 0) { this.setError("bad frame length(" + tag_num + ": " + frameIDString + "): " + frameLength + " (" + new String(frameID)); break; } final ID3v2FrameFlags flags = new ID3v2FrameFlags(); int dataLengthIndicator; if (this.versionMajor != 3 && this.versionMajor != 4) { if (this.versionMajor != 2) { this.setError("Unknown ID3v2 version: " + this.versionMajor); return; } } else { dataLengthIndicator = this.readShort(bytes); int frameBytes = dataLengthIndicator; if (this.versionMajor == 3) { if ((dataLengthIndicator & '耀') > 0) { flags.setTagAlterPreservation(true); frameBytes = dataLengthIndicator ^ '耀'; } if ((frameBytes & 16384) > 0) { flags.setFileAlterPreservation(true); frameBytes ^= 16384; } if ((frameBytes & 8192) > 0) { flags.setReadOnly(true); frameBytes ^= 8192; } if ((frameBytes & 32) > 0) { flags.setGroupingIdentity(true); frameBytes ^= 32; } if ((frameBytes & 128) > 0) { flags.setCompression(true); frameBytes ^= 128; } if ((frameBytes & 64) > 0) { flags.setEncryption(true); frameBytes ^= 64; } } else if (this.versionMajor == 4) { if ((dataLengthIndicator & 16384) > 0) { flags.setTagAlterPreservation(true); frameBytes = dataLengthIndicator ^ 16384; } if ((frameBytes & 8192) > 0) { flags.setFileAlterPreservation(true); frameBytes ^= 8192; } if ((frameBytes & 4096) > 0) { flags.setReadOnly(true); frameBytes ^= 4096; } if ((frameBytes & 64) > 0) { flags.setGroupingIdentity(true); frameBytes ^= 64; } if ((frameBytes & 8) > 0) { flags.setCompression(true); frameBytes ^= 8; } if ((frameBytes & 4) > 0) { flags.setEncryption(true); frameBytes ^= 4; } if ((frameBytes & 2) > 0) { flags.setUnsynchronisation(true); frameBytes ^= 2; } if ((frameBytes & 1) > 0) { flags.setDataLengthIndicator(true); frameBytes ^= 1; } } if (frameBytes > 0) { this.setError("Unknown id3v2 frame flags(id3v2 version: " + this.versionMajor + "): " + Long.toHexString((long) dataLengthIndicator)); return; } } if (frameLength > 0) { if (flags.isDataLengthIndicator()) { dataLengthIndicator = this.readSynchsafeInt(bytes, true); frameLength -= 4; } byte[] var14 = new byte[frameLength]; System.arraycopy(bytes, this.index, var14, 0, frameLength); this.index += frameLength; if (flags.isUnsynchronisation()) { var14 = this.ununsynchronize(var14); } try { if (frameID[0] == 84) { this.readTextTag(frameLength, frameID, var14, frameIDString); } else { this.readDataTag(frameLength, frameID, var14, frameIDString, flags); } } catch (IOException var12) { this.setError(var12.getMessage()); return; } } } this.tagRead = true; } } private void readDataTag( final int frameLength, final byte[] frameID, final byte[] frameBytes, final String frameIDString, final ID3v2FrameFlags flags) throws IOException { byte frameIndex; int ownerIdentifier; int var15; if (!frameIDString.equals("COMM") && !frameIDString.equals("COM")) { int var18; if (!frameIDString.equals("PIC") && !frameIDString.equals("APIC")) { if (frameIDString.equals("PRIV")) { frameIndex = 0; byte var19 = 0; String var16 = this.readString(frameBytes, frameIndex, var19); var18 = this.findStringDataLength(frameBytes, frameIndex, var19); int var10000 = frameIndex + var18; if (var16.startsWith("WM/")) { return; } } else { this.mTags.add(new MyID3v2FrameData(frameIDString, frameBytes, flags)); } } else { frameIndex = 0; var15 = frameIndex + 1; ownerIdentifier = 255 & frameBytes[frameIndex]; int imageData; String var17; if (frameIDString.equals("PIC")) { var18 = 255 & frameBytes[var15++]; int var20 = 255 & frameBytes[var15++]; imageData = 255 & frameBytes[var15++]; String var23 = "" + (char) var18 + (char) var20 + (char) imageData; var17 = var23.toLowerCase(); if (!var17.startsWith("image/")) { var17 = "image/" + var17; } } else { var17 = this.readString(frameBytes, var15, ownerIdentifier); var18 = this.findStringDataLength(frameBytes, var15, ownerIdentifier); var15 += var18; } var18 = 255 & frameBytes[var15++]; String var21 = this.readString(frameBytes, var15, ownerIdentifier); imageData = this.findStringDataLength(frameBytes, var15, ownerIdentifier); var15 += imageData; byte[] var22 = new byte[frameBytes.length - var15]; System.arraycopy(frameBytes, var15, var22, 0, var22.length); this.mTags.add(new MyID3v2FrameImage(frameIDString, frameBytes, flags, var22, var17, var21, var18)); } } else { if (frameBytes.length < 5) { this.setError("Unexpected COMM frame length(1): " + frameLength + " (" + new String(frameID)); return; } frameIndex = 0; var15 = frameIndex + 1; ownerIdentifier = 255 & frameBytes[frameIndex]; this.readString(frameBytes, var15, ownerIdentifier); int extension = this.findStringDataLength(frameBytes, var15, ownerIdentifier); var15 += extension; final String comment = this.readString(frameBytes, var15, ownerIdentifier); this.mTags.add(new MyID3v2FrameText(frameIDString, frameBytes, comment)); } } private void readTextTag(int frameLength, byte[] frameID, byte[] frameBytes, String frameIDString) throws IOException { if (frameLength != 1) { if (frameLength < 2) { this.setError("Unexpected frame length(1): " + frameLength + " (" + new String(frameID)); } else { int charEncodingCode = 255 & frameBytes[0]; byte frameIndex = 1; String value = this.readString(frameBytes, frameIndex, charEncodingCode); String value2 = null; MyID3v2FrameText tag; if (frameIDString.equals("TXXX")) { int stringDataLength = this.findStringDataLength(frameBytes, frameIndex, charEncodingCode); int frameIndex1 = frameIndex + stringDataLength; value2 = this.readString(frameBytes, frameIndex1, charEncodingCode); tag = new MyID3v2FrameText(frameIDString, frameBytes, value, value2); } else { tag = new MyID3v2FrameText(frameIDString, frameBytes, value); } this.mTags.add(tag); } } } private String getCharacterEncodingName(final int charEncodingCode) throws IOException { switch (charEncodingCode) { case 0: return "ISO-8859-1"; case 1: return "UTF-16"; case 2: return "UTF-16"; case 3: return "UTF-8"; default: throw new IOException("Unknown charEncodingCode: " + charEncodingCode); } } private String readString(byte[] bytes, int start, int charEncodingCode) throws IOException { UnicodeMetrics unicodeMetrics = UnicodeMetrics.getInstance(charEncodingCode); int unicodeMetricsEnd = unicodeMetrics.findEndWithoutTerminator(bytes, start); int unicodeMetricsLength = unicodeMetricsEnd - start; String charsetName = this.getCharacterEncodingName(charEncodingCode); return new String(bytes, start, unicodeMetricsLength, charsetName); } private int findStringDataLength(byte[] bytes, int start, int charEncodingCode) throws IOException { UnicodeMetrics unicodeMetrics = UnicodeMetrics.getInstance(charEncodingCode); int unicodeMetricsEnd = unicodeMetrics.findEndWithTerminator(bytes, start); return unicodeMetricsEnd - start; } private boolean read() { try { if (mInputStream.available() < 0) { this.stream_complete = true; return true; } else if (!this.async && mInputStream.available() < 1) { this.stream_complete = true; return true; } else if (mInputStream.available() < 1) { return false; } else { final int e = mInputStream.read(this.mBuffer); if (e < 1) { this.setError("unexpected stream closed"); return true; } else { this.mByteArrayOutputStream.write(this.mBuffer, 0, e); this.mBytesRead += (long) e; return true; } } } catch (IOException var2) { this.setError(var2.getMessage()); return true; } } private void setError(String s) { this.error = true; this.errorMessage = s; } public Vector getTags() { return this.mTags; } public byte getVersionMajor() { return this.versionMajor; } public byte getVersionMinor() { return this.versionMinor; } }