diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 01:06:44 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-07-07 01:06:44 +0000 |
commit | 528201492371d0e43dc1ceaa0cad22c0ae690d36 (patch) | |
tree | 0baa92251e9c2c2d2522d953021138893ae84133 /java/com | |
parent | f8ef2ae5e79b3ca6ed5f1bcae0550ff0491b9933 (diff) | |
parent | d4be1f10b831f4c3774091c74e4b904ec6450c9a (diff) | |
download | turbine-aml_wif_341410080.tar.gz |
Snap for 10447354 from d4be1f10b831f4c3774091c74e4b904ec6450c9a to mainline-wifi-releaseaml_wif_341711020aml_wif_341610000aml_wif_341510000aml_wif_341410080aml_wif_341310010aml_wif_341110010aml_wif_341011010aml_wif_340913010android14-mainline-wifi-release
Change-Id: I99a8d37bfdd2a99732d853191173908eb094c683
Diffstat (limited to 'java/com')
-rw-r--r-- | java/com/google/turbine/binder/FileManagerClassBinder.java | 5 | ||||
-rw-r--r-- | java/com/google/turbine/bytecode/ByteReader.java | 2 | ||||
-rw-r--r-- | java/com/google/turbine/bytecode/ClassReader.java | 20 | ||||
-rw-r--r-- | java/com/google/turbine/main/Main.java | 10 | ||||
-rw-r--r-- | java/com/google/turbine/options/LanguageVersion.java | 2 | ||||
-rw-r--r-- | java/com/google/turbine/parse/ConstExpressionParser.java | 6 | ||||
-rw-r--r-- | java/com/google/turbine/parse/Parser.java | 8 | ||||
-rw-r--r-- | java/com/google/turbine/parse/StreamLexer.java | 162 | ||||
-rw-r--r-- | java/com/google/turbine/processing/TurbineElements.java | 2 | ||||
-rw-r--r-- | java/com/google/turbine/processing/TurbineFiler.java | 7 | ||||
-rw-r--r-- | java/com/google/turbine/processing/TurbineTypes.java | 59 | ||||
-rw-r--r-- | java/com/google/turbine/type/Type.java | 21 | ||||
-rw-r--r-- | java/com/google/turbine/zip/Zip.java | 41 |
13 files changed, 252 insertions, 93 deletions
diff --git a/java/com/google/turbine/binder/FileManagerClassBinder.java b/java/com/google/turbine/binder/FileManagerClassBinder.java index d36d2d8..a807dd7 100644 --- a/java/com/google/turbine/binder/FileManagerClassBinder.java +++ b/java/com/google/turbine/binder/FileManagerClassBinder.java @@ -19,7 +19,6 @@ package com.google.turbine.binder; import com.google.common.base.Joiner; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableMap; -import com.google.common.io.ByteStreams; import com.google.turbine.binder.bound.ModuleInfo; import com.google.turbine.binder.bytecode.BytecodeBoundClass; import com.google.turbine.binder.env.Env; @@ -113,7 +112,7 @@ public final class FileManagerClassBinder { @Override public byte[] get() { try { - return ByteStreams.toByteArray(jfo.openInputStream()); + return jfo.openInputStream().readAllBytes(); } catch (IOException e) { throw new UncheckedIOException(e); } @@ -162,7 +161,7 @@ public final class FileManagerClassBinder { @Override public byte[] get() { try { - return ByteStreams.toByteArray(fileObject.openInputStream()); + return fileObject.openInputStream().readAllBytes(); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/java/com/google/turbine/bytecode/ByteReader.java b/java/com/google/turbine/bytecode/ByteReader.java index a9deff2..5458b49 100644 --- a/java/com/google/turbine/bytecode/ByteReader.java +++ b/java/com/google/turbine/bytecode/ByteReader.java @@ -20,11 +20,9 @@ import static com.google.common.base.Verify.verify; import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteStreams; -import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.ByteArrayInputStream; /** A {@link ByteArrayDataInput} wrapper that tracks the current byte array index. */ -@CanIgnoreReturnValue public class ByteReader { private final byte[] bytes; diff --git a/java/com/google/turbine/bytecode/ClassReader.java b/java/com/google/turbine/bytecode/ClassReader.java index 740026a..da35196 100644 --- a/java/com/google/turbine/bytecode/ClassReader.java +++ b/java/com/google/turbine/bytecode/ClassReader.java @@ -159,7 +159,7 @@ public class ClassReader { /** Reads a JVMS 4.7.9 Signature attribute. */ private String readSignature(ConstantPoolReader constantPool) { String signature; - reader.u4(); // length + int unusedLength = reader.u4(); signature = constantPool.utf8(reader.u2()); return signature; } @@ -167,7 +167,7 @@ public class ClassReader { /** Reads JVMS 4.7.6 InnerClasses attributes. */ private List<ClassFile.InnerClass> readInnerClasses( ConstantPoolReader constantPool, String thisClass) { - reader.u4(); // length + int unusedLength = reader.u4(); int numberOfClasses = reader.u2(); List<ClassFile.InnerClass> innerclasses = new ArrayList<>(); for (int i = 0; i < numberOfClasses; i++) { @@ -197,7 +197,7 @@ public class ClassReader { private void readAnnotations( ImmutableList.Builder<ClassFile.AnnotationInfo> annotations, ConstantPoolReader constantPool) { - reader.u4(); // length + int unusedLength = reader.u4(); int numAnnotations = reader.u2(); for (int n = 0; n < numAnnotations; n++) { annotations.add(readAnnotation(constantPool)); @@ -207,7 +207,7 @@ public class ClassReader { /** Processes a JVMS 4.7.18 RuntimeVisibleParameterAnnotations attribute */ public void readParameterAnnotations( List<ImmutableList.Builder<AnnotationInfo>> annotations, ConstantPoolReader constantPool) { - reader.u4(); // length + int unusedLength = reader.u4(); int numParameters = reader.u1(); while (annotations.size() < numParameters) { annotations.add(ImmutableList.builder()); @@ -223,7 +223,7 @@ public class ClassReader { /** Processes a JVMS 4.7.24 MethodParameters attribute. */ private void readMethodParameters( ImmutableList.Builder<ParameterInfo> parameters, ConstantPoolReader constantPool) { - reader.u4(); // length + int unusedLength = reader.u4(); int numParameters = reader.u1(); for (int i = 0; i < numParameters; i++) { String name = constantPool.utf8(reader.u2()); @@ -239,7 +239,7 @@ public class ClassReader { /** Processes a JVMS 4.7.25 Module attribute. */ private ModuleInfo readModule(ConstantPoolReader constantPool) { - reader.u4(); // length + int unusedLength = reader.u4(); String name = constantPool.moduleInfo(reader.u2()); int flags = reader.u2(); int versionIndex = reader.u2(); @@ -423,7 +423,7 @@ public class ClassReader { signature = readSignature(constantPool); break; case "AnnotationDefault": - reader.u4(); // length + int unusedLength = reader.u4(); defaultValue = readElementValue(constantPool); break; case "RuntimeInvisibleAnnotations": @@ -470,7 +470,7 @@ public class ClassReader { /** Reads an Exceptions attribute. */ private ImmutableList<String> readExceptions(ConstantPoolReader constantPool) { ImmutableList.Builder<String> exceptions = ImmutableList.builder(); - reader.u4(); // length + int unusedLength = reader.u4(); int numberOfExceptions = reader.u2(); for (int exceptionIndex = 0; exceptionIndex < numberOfExceptions; exceptionIndex++) { exceptions.add(constantPool.classInfo(reader.u2())); @@ -496,7 +496,7 @@ public class ClassReader { String attributeName = constantPool.utf8(reader.u2()); switch (attributeName) { case "ConstantValue": - reader.u4(); // length + int unusedLength = reader.u4(); value = constantPool.constant(reader.u2()); break; case "RuntimeInvisibleAnnotations": @@ -525,7 +525,7 @@ public class ClassReader { } private String readTurbineTransitiveJar(ConstantPoolReader constantPool) { - reader.u4(); // length + int unusedLength = reader.u4(); return constantPool.utf8(reader.u2()); } } diff --git a/java/com/google/turbine/main/Main.java b/java/com/google/turbine/main/Main.java index da97bcd..34984a8 100644 --- a/java/com/google/turbine/main/Main.java +++ b/java/com/google/turbine/main/Main.java @@ -58,7 +58,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; -import java.time.ZoneId; import java.util.Arrays; import java.util.Collection; import java.util.Map; @@ -433,16 +432,11 @@ public final class Main { } /** Normalize timestamps. */ - static final long DEFAULT_TIMESTAMP = - LocalDateTime.of(2010, 1, 1, 0, 0, 0) - .atZone(ZoneId.systemDefault()) - .toInstant() - .toEpochMilli(); + static final LocalDateTime DEFAULT_TIMESTAMP = LocalDateTime.of(2010, 1, 1, 0, 0, 0); private static void addEntry(JarOutputStream jos, String name, byte[] bytes) throws IOException { JarEntry je = new JarEntry(name); - // TODO(cushon): switch to setLocalTime after we migrate to JDK 9 - je.setTime(DEFAULT_TIMESTAMP); + je.setTimeLocal(DEFAULT_TIMESTAMP); je.setMethod(ZipEntry.STORED); je.setSize(bytes.length); je.setCrc(Hashing.crc32().hashBytes(bytes).padToLong()); diff --git a/java/com/google/turbine/options/LanguageVersion.java b/java/com/google/turbine/options/LanguageVersion.java index e2b0ea7..d8641b4 100644 --- a/java/com/google/turbine/options/LanguageVersion.java +++ b/java/com/google/turbine/options/LanguageVersion.java @@ -53,7 +53,7 @@ public abstract class LanguageVersion { try { return SourceVersion.valueOf("RELEASE_" + source()); } catch (IllegalArgumentException unused) { - throw new IllegalArgumentException("invalid -source version: " + source()); + return SourceVersion.latestSupported(); } } diff --git a/java/com/google/turbine/parse/ConstExpressionParser.java b/java/com/google/turbine/parse/ConstExpressionParser.java index 8b7466f..e4aad6b 100644 --- a/java/com/google/turbine/parse/ConstExpressionParser.java +++ b/java/com/google/turbine/parse/ConstExpressionParser.java @@ -588,11 +588,11 @@ public class ConstExpressionParser { } eat(); int pos = position; - Tree.ConstVarName constVarName = (Tree.ConstVarName) qualIdent(); - if (constVarName == null) { + Expression constVarName = qualIdent(); + if (!(constVarName instanceof Tree.ConstVarName)) { return null; } - ImmutableList<Ident> name = constVarName.name(); + ImmutableList<Ident> name = ((Tree.ConstVarName) constVarName).name(); ImmutableList.Builder<Tree.Expression> args = ImmutableList.builder(); if (token == Token.LPAREN) { eat(); diff --git a/java/com/google/turbine/parse/Parser.java b/java/com/google/turbine/parse/Parser.java index c370ad8..acf84d7 100644 --- a/java/com/google/turbine/parse/Parser.java +++ b/java/com/google/turbine/parse/Parser.java @@ -547,6 +547,7 @@ public class Parser { switch (token) { case IDENT: { + String javadoc = lexer.javadoc(); Ident name = eatIdent(); if (token == Token.LPAREN) { dropParens(); @@ -569,7 +570,7 @@ public class Parser { ImmutableList.of()), name, Optional.<Expression>empty(), - null)); + javadoc)); annos = ImmutableList.builder(); break; } @@ -719,6 +720,11 @@ public class Parser { case IDENT: Ident ident = ident(); + if (ident.value().equals("sealed")) { + next(); + access.add(TurbineModifier.SEALED); + break; + } if (ident.value().equals("non")) { int pos = position; next(); diff --git a/java/com/google/turbine/parse/StreamLexer.java b/java/com/google/turbine/parse/StreamLexer.java index 2348385..3d46b90 100644 --- a/java/com/google/turbine/parse/StreamLexer.java +++ b/java/com/google/turbine/parse/StreamLexer.java @@ -17,8 +17,11 @@ package com.google.turbine.parse; import static com.google.common.base.Verify.verify; +import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.turbine.parse.UnicodeEscapePreprocessor.ASCII_SUB; +import static java.lang.Math.min; +import com.google.common.collect.ImmutableList; import com.google.turbine.diag.SourceFile; import com.google.turbine.diag.TurbineError; import com.google.turbine.diag.TurbineError.ErrorKind; @@ -399,6 +402,15 @@ public class StreamLexer implements Lexer { case '"': { eat(); + if (ch == '"') { + eat(); + if (ch != '"') { + saveValue(""); + return Token.STRING_LITERAL; + } + eat(); + return textBlock(); + } readFrom(); StringBuilder sb = new StringBuilder(); STRING: @@ -436,6 +448,156 @@ public class StreamLexer implements Lexer { } } + private Token textBlock() { + OUTER: + while (true) { + switch (ch) { + case ' ': + case '\r': + case '\t': + eat(); + break; + default: + break OUTER; + } + } + switch (ch) { + case '\r': + eat(); + if (ch == '\n') { + eat(); + } + break; + case '\n': + eat(); + break; + default: + throw inputError(); + } + readFrom(); + StringBuilder sb = new StringBuilder(); + while (true) { + switch (ch) { + case '"': + eat(); + if (ch != '"') { + sb.append("\""); + continue; + } + eat(); + if (ch != '"') { + sb.append("\"\""); + continue; + } + eat(); + String value = sb.toString(); + value = stripIndent(value); + value = translateEscapes(value); + saveValue(value); + return Token.STRING_LITERAL; + case ASCII_SUB: + if (reader.done()) { + return Token.EOF; + } + // falls through + default: + sb.appendCodePoint(ch); + eat(); + continue; + } + } + } + + static String stripIndent(String value) { + if (value.isEmpty()) { + return value; + } + ImmutableList<String> lines = value.lines().collect(toImmutableList()); + // the amount of whitespace to strip from the beginning of every line + int strip = Integer.MAX_VALUE; + char last = value.charAt(value.length() - 1); + boolean trailingNewline = last == '\n' || last == '\r'; + if (trailingNewline) { + // If the input contains a trailing newline, we have something like: + // + // |String s = """ + // | foo + // |"""; + // + // Because the final """ is unindented, nothing should be stripped. + strip = 0; + } else { + // find the longest common prefix of whitespace across all non-blank lines + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + int nonWhitespaceStart = nonWhitespaceStart(line); + if (nonWhitespaceStart == line.length()) { + continue; + } + strip = min(strip, nonWhitespaceStart); + } + } + StringBuilder result = new StringBuilder(); + boolean first = true; + for (String line : lines) { + if (!first) { + result.append('\n'); + } + int end = trailingWhitespaceStart(line); + if (strip <= end) { + result.append(line, strip, end); + } + first = false; + } + if (trailingNewline) { + result.append('\n'); + } + return result.toString(); + } + + private static int nonWhitespaceStart(String value) { + int i = 0; + while (i < value.length() && Character.isWhitespace(value.charAt(i))) { + i++; + } + return i; + } + + private static int trailingWhitespaceStart(String value) { + int i = value.length() - 1; + while (i >= 0 && Character.isWhitespace(value.charAt(i))) { + i--; + } + return i + 1; + } + + private static String translateEscapes(String value) { + StreamLexer lexer = + new StreamLexer(new UnicodeEscapePreprocessor(new SourceFile(null, value + ASCII_SUB))); + return lexer.translateEscapes(); + } + + private String translateEscapes() { + readFrom(); + StringBuilder sb = new StringBuilder(); + OUTER: + while (true) { + switch (ch) { + case '\\': + eat(); + sb.append(escape()); + continue; + case ASCII_SUB: + break OUTER; + default: + sb.appendCodePoint(ch); + eat(); + continue; + } + } + return sb.toString(); + } + private char escape() { boolean zeroToThree = false; switch (ch) { diff --git a/java/com/google/turbine/processing/TurbineElements.java b/java/com/google/turbine/processing/TurbineElements.java index b5fd7f4..9b3ea26 100644 --- a/java/com/google/turbine/processing/TurbineElements.java +++ b/java/com/google/turbine/processing/TurbineElements.java @@ -384,7 +384,7 @@ public class TurbineElements implements Elements { return false; } TypeMirror a = overrider.asType(); - TypeMirror b = types.asMemberOf((DeclaredType) type.asType(), overridden); + TypeMirror b = types.asMemberOfInternal((DeclaredType) type.asType(), overridden); if (b == null) { return false; } diff --git a/java/com/google/turbine/processing/TurbineFiler.java b/java/com/google/turbine/processing/TurbineFiler.java index 45cdc22..8c522ba 100644 --- a/java/com/google/turbine/processing/TurbineFiler.java +++ b/java/com/google/turbine/processing/TurbineFiler.java @@ -24,7 +24,6 @@ import com.google.common.base.Function; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMap; -import com.google.common.io.ByteStreams; import com.google.turbine.diag.SourceFile; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -232,7 +231,7 @@ public class TurbineFiler implements Filer { @Override public URI toUri() { - return URI.create("file://" + path); + return URI.create("file:///" + path); } @Override @@ -309,7 +308,7 @@ public class TurbineFiler implements Filer { @Override public URI toUri() { - return URI.create("file://" + name + kind.extension); + return URI.create("file:///" + name + kind.extension); } @Override @@ -380,7 +379,7 @@ public class TurbineFiler implements Filer { @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - return new String(ByteStreams.toByteArray(openInputStream()), UTF_8); + return new String(openInputStream().readAllBytes(), UTF_8); } } diff --git a/java/com/google/turbine/processing/TurbineTypes.java b/java/com/google/turbine/processing/TurbineTypes.java index d2068dd..467059c 100644 --- a/java/com/google/turbine/processing/TurbineTypes.java +++ b/java/com/google/turbine/processing/TurbineTypes.java @@ -26,18 +26,11 @@ import com.google.common.collect.ImmutableMap; import com.google.turbine.binder.bound.TypeBoundClass; import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo; import com.google.turbine.binder.sym.ClassSymbol; -import com.google.turbine.binder.sym.FieldSymbol; -import com.google.turbine.binder.sym.MethodSymbol; -import com.google.turbine.binder.sym.ParamSymbol; -import com.google.turbine.binder.sym.RecordComponentSymbol; import com.google.turbine.binder.sym.Symbol; import com.google.turbine.binder.sym.TyVarSymbol; import com.google.turbine.model.TurbineConstantTypeKind; import com.google.turbine.model.TurbineTyKind; -import com.google.turbine.processing.TurbineElement.TurbineExecutableElement; -import com.google.turbine.processing.TurbineElement.TurbineFieldElement; import com.google.turbine.processing.TurbineElement.TurbineTypeElement; -import com.google.turbine.processing.TurbineElement.TurbineTypeParameterElement; import com.google.turbine.processing.TurbineTypeMirror.TurbineDeclaredType; import com.google.turbine.processing.TurbineTypeMirror.TurbineErrorType; import com.google.turbine.processing.TurbineTypeMirror.TurbineTypeVariable; @@ -1127,41 +1120,6 @@ public class TurbineTypes implements Types { .build())); } - private static ClassSymbol enclosingClass(Symbol symbol) { - switch (symbol.symKind()) { - case CLASS: - return (ClassSymbol) symbol; - case TY_PARAM: - return enclosingClass(((TyVarSymbol) symbol).owner()); - case METHOD: - return ((MethodSymbol) symbol).owner(); - case FIELD: - return ((FieldSymbol) symbol).owner(); - case PARAMETER: - return ((ParamSymbol) symbol).owner().owner(); - case RECORD_COMPONENT: - return ((RecordComponentSymbol) symbol).owner(); - case MODULE: - case PACKAGE: - throw new IllegalArgumentException(symbol.symKind().toString()); - } - throw new AssertionError(symbol.symKind()); - } - - private static Type type(Element element) { - switch (element.getKind()) { - case TYPE_PARAMETER: - return TyVar.create(((TurbineTypeParameterElement) element).sym(), ImmutableList.of()); - case FIELD: - return ((TurbineFieldElement) element).info().type(); - case METHOD: - case CONSTRUCTOR: - return ((TurbineExecutableElement) element).info().asType(); - default: - throw new UnsupportedOperationException(element.toString()); - } - } - /** * Returns the {@link TypeMirror} of the given {@code element} as a member of {@code containing}, * or else {@code null} if it is not a member. @@ -1171,13 +1129,24 @@ public class TurbineTypes implements Types { */ @Override public TypeMirror asMemberOf(DeclaredType containing, Element element) { + TypeMirror result = asMemberOfInternal(containing, element); + if (result == null) { + throw new IllegalArgumentException(String.format("asMemberOf(%s, %s)", containing, element)); + } + return result; + } + + public @Nullable TypeMirror asMemberOfInternal(DeclaredType containing, Element element) { ClassTy c = ((TurbineDeclaredType) containing).asTurbineType(); - ClassSymbol symbol = enclosingClass(((TurbineElement) element).sym()); - ImmutableList<ClassTy> path = factory.cha().search(c, enclosingClass(symbol)); + Symbol enclosing = ((TurbineElement) element.getEnclosingElement()).sym(); + if (!enclosing.symKind().equals(Symbol.Kind.CLASS)) { + return null; + } + ImmutableList<ClassTy> path = factory.cha().search(c, (ClassSymbol) enclosing); if (path.isEmpty()) { return null; } - Type type = type(element); + Type type = asTurbineType(element.asType()); for (ClassTy ty : path) { ImmutableMap<TyVarSymbol, Type> mapping = getMapping(ty); if (mapping == null) { diff --git a/java/com/google/turbine/type/Type.java b/java/com/google/turbine/type/Type.java index 085346a..5fbf1b1 100644 --- a/java/com/google/turbine/type/Type.java +++ b/java/com/google/turbine/type/Type.java @@ -17,6 +17,7 @@ package com.google.turbine.type; import static com.google.common.collect.Iterables.getLast; +import static java.lang.Math.max; import static java.util.Objects.requireNonNull; import com.google.auto.value.AutoValue; @@ -144,15 +145,23 @@ public interface Type { StringBuilder sb = new StringBuilder(); boolean first = true; for (SimpleClassTy c : classes()) { - for (AnnoInfo anno : c.annos()) { - sb.append(anno); - sb.append(' '); - } + String binaryName = c.sym().binaryName(); if (!first) { + for (AnnoInfo anno : c.annos()) { + sb.append(anno); + sb.append(' '); + } sb.append('.'); - sb.append(c.sym().binaryName().substring(c.sym().binaryName().lastIndexOf('$') + 1)); + sb.append(binaryName, binaryName.lastIndexOf('$') + 1, binaryName.length()); } else { - sb.append(c.sym().binaryName().replace('/', '.').replace('$', '.')); + int idx = max(binaryName.lastIndexOf('/'), binaryName.lastIndexOf('$')) + 1; + String name = binaryName.replace('/', '.').replace('$', '.'); + sb.append(name, 0, idx); + for (AnnoInfo anno : c.annos()) { + sb.append(anno); + sb.append(' '); + } + sb.append(name, idx, name.length()); } if (!c.targs().isEmpty()) { sb.append('<'); diff --git a/java/com/google/turbine/zip/Zip.java b/java/com/google/turbine/zip/Zip.java index fa0f0e0..c08999b 100644 --- a/java/com/google/turbine/zip/Zip.java +++ b/java/com/google/turbine/zip/Zip.java @@ -18,7 +18,6 @@ package com.google.turbine.zip; import static java.nio.charset.StandardCharsets.UTF_8; -import com.google.common.io.ByteStreams; import com.google.common.primitives.UnsignedInts; import java.io.ByteArrayInputStream; import java.io.Closeable; @@ -65,7 +64,6 @@ import java.util.zip.ZipException; * supported. * <li>UTF-8 is the only supported encoding. * <li>STORED and DEFLATE are the only supported compression methods. - * <li>zip64 extensible data sectors are not supported. * <li>Zip files larger than Integer.MAX_VALUE bytes are not supported. * <li>The only supported ZIP64 field is ENDTOT. This implementation assumes that the ZIP64 end * header is present only if ENDTOT in EOCD header is 0xFFFF. @@ -74,6 +72,7 @@ import java.util.zip.ZipException; public final class Zip { static final int ZIP64_ENDSIG = 0x06064b50; + static final int ZIP64_LOCSIG = 0x07064b50; static final int LOCHDR = 30; // LOC header size static final int CENHDR = 46; // CEN header size @@ -196,20 +195,44 @@ public final class Zip { if (totalEntries == ZIP64_MAGICCOUNT) { // Assume the zip64 EOCD has the usual size; we don't support zip64 extensible data sectors. long zip64eocdOffset = size - ENDHDR - ZIP64_LOCHDR - ZIP64_ENDHDR; - MappedByteBuffer zip64eocd = chan.map(MapMode.READ_ONLY, zip64eocdOffset, ZIP64_ENDHDR); - zip64eocd.order(ByteOrder.LITTLE_ENDIAN); // Note that zip reading is necessarily best-effort, since an archive could contain 0xFFFF // entries and the last entry's data could contain a ZIP64_ENDSIG. Some implementations // read the full EOCD records and compare them. - if (zip64eocd.getInt(0) == ZIP64_ENDSIG) { - cdsize = zip64eocd.getLong(ZIP64_ENDSIZ); + long zip64cdsize = zip64cdsize(chan, zip64eocdOffset); + if (zip64cdsize != -1) { eocdOffset = zip64eocdOffset; + cdsize = zip64cdsize; + } else { + // If we couldn't find a zip64 EOCD at a fixed offset, either it doesn't exist + // or there was a zip64 extensible data sector, so try going through the + // locator. This approach doesn't work if data was prepended to the archive + // without updating the offset in the locator. + MappedByteBuffer zip64loc = + chan.map(MapMode.READ_ONLY, size - ENDHDR - ZIP64_LOCHDR, ZIP64_LOCHDR); + zip64loc.order(ByteOrder.LITTLE_ENDIAN); + if (zip64loc.getInt(0) == ZIP64_LOCSIG) { + zip64eocdOffset = zip64loc.getLong(8); + zip64cdsize = zip64cdsize(chan, zip64eocdOffset); + if (zip64cdsize != -1) { + eocdOffset = zip64eocdOffset; + cdsize = zip64cdsize; + } + } } } this.cd = chan.map(MapMode.READ_ONLY, eocdOffset - cdsize, cdsize); cd.order(ByteOrder.LITTLE_ENDIAN); } + static long zip64cdsize(FileChannel chan, long eocdOffset) throws IOException { + MappedByteBuffer zip64eocd = chan.map(MapMode.READ_ONLY, eocdOffset, ZIP64_ENDHDR); + zip64eocd.order(ByteOrder.LITTLE_ENDIAN); + if (zip64eocd.getInt(0) == ZIP64_ENDSIG) { + return zip64eocd.getLong(ZIP64_ENDSIZ); + } + return -1; + } + @Override public Iterator<Entry> iterator() { return new ZipIterator(path, chan, cd); @@ -308,9 +331,9 @@ public final class Zip { fc.get(bytes); if (deflate) { bytes = - ByteStreams.toByteArray( - new InflaterInputStream( - new ByteArrayInputStream(bytes), new Inflater(/*nowrap=*/ true))); + new InflaterInputStream( + new ByteArrayInputStream(bytes), new Inflater(/*nowrap=*/ true)) + .readAllBytes(); } return bytes; } catch (IOException e) { |