add pure-kotlin decoder

PiperOrigin-RevId: 608917286
This commit is contained in:
Evgenii Kliuchnikov 2024-02-21 02:32:23 -08:00 committed by Copybara-Service
parent c1362a7903
commit ccec9628e4
12 changed files with 2134 additions and 74 deletions

View File

@ -320,8 +320,9 @@ jobs:
export MAVEN_OPTS=-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn export MAVEN_OPTS=-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn
cd java/org/brotli cd java/org/brotli
mvn -B install mvn -B install
cd integration # TODO(eustas): nuke maven build?
mvn -B verify # cd integration
# mvn -B verify
- uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
if: ${{ matrix.build_system == 'python' }} if: ${{ matrix.build_system == 'python' }}

View File

@ -9,6 +9,8 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file"
RULES_JVM_EXTERNAL_TAG = "4.0" RULES_JVM_EXTERNAL_TAG = "4.0"
RULES_JVM_EXTERNAL_SHA = "31701ad93dbfe544d597dbe62c9a1fdd76d81d8a9150c2bf1ecf928ecdf97169" RULES_JVM_EXTERNAL_SHA = "31701ad93dbfe544d597dbe62c9a1fdd76d81d8a9150c2bf1ecf928ecdf97169"
RULES_KOTLIN_VERSION = "1.9.0"
RULES_KOTLIN_SHA = "5766f1e599acf551aa56f49dab9ab9108269b03c557496c54acaf41f98e2b8d6"
http_archive( http_archive(
name = "rules_jvm_external", name = "rules_jvm_external",
@ -19,6 +21,18 @@ http_archive(
load("@rules_jvm_external//:defs.bzl", "maven_install") load("@rules_jvm_external//:defs.bzl", "maven_install")
http_archive(
name = "rules_kotlin",
urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/v%s/rules_kotlin-v%s.tar.gz" % (RULES_KOTLIN_VERSION, RULES_KOTLIN_VERSION)],
sha256 = RULES_KOTLIN_SHA,
)
load("@rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories")
kotlin_repositories() # if you want the default. Otherwise see custom kotlinc distribution below
load("@rules_kotlin//kotlin:core.bzl", "kt_register_toolchains")
kt_register_toolchains() # to use the default toolchain, otherwise see toolchains below
maven_install( maven_install(
artifacts = ["junit:junit:4.12"], artifacts = ["junit:junit:4.12"],
repositories = [ repositories = [

View File

@ -9,6 +9,7 @@ licenses(["notice"]) # MIT
TEST_DEPS = [ TEST_DEPS = [
":dec", ":dec",
":test_utils",
"@maven//:junit_junit", "@maven//:junit_junit",
] ]
@ -25,6 +26,12 @@ java_library(
resources = ["//:license"], resources = ["//:license"],
) )
java_library(
name = "test_utils",
srcs = ["TestUtils.java"],
deps = [":dec"],
)
brotli_java_test( brotli_java_test(
name = "BitReaderTest", name = "BitReaderTest",
srcs = ["BitReaderTest.java"], srcs = ["BitReaderTest.java"],
@ -34,6 +41,7 @@ brotli_java_test(
brotli_java_test( brotli_java_test(
name = "DecodeTest", name = "DecodeTest",
srcs = ["DecodeTest.java"], srcs = ["DecodeTest.java"],
test_kotlin = True,
deps = TEST_DEPS, deps = TEST_DEPS,
) )
@ -52,6 +60,7 @@ brotli_java_test(
brotli_java_test( brotli_java_test(
name = "SynthTest", name = "SynthTest",
srcs = ["SynthTest.java"], srcs = ["SynthTest.java"],
test_kotlin = True,
deps = TEST_DEPS, deps = TEST_DEPS,
) )

View File

@ -6,34 +6,27 @@
package org.brotli.dec; package org.brotli.dec;
import static org.brotli.dec.TestUtils.newBrotliInputStream;
import static org.brotli.dec.TestUtils.readUniBytes;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
/** /** Tests for {@link BrotliInputStream}. */
* Tests for {@link Decode}.
*/
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class DecodeTest { public class DecodeTest {
static byte[] readUniBytes(String uniBytes) {
byte[] result = new byte[uniBytes.length()];
for (int i = 0; i < result.length; ++i) {
result[i] = (byte) uniBytes.charAt(i);
}
return result;
}
private byte[] decompress(byte[] data, boolean byByte) throws IOException { private byte[] decompress(byte[] data, boolean byByte) throws IOException {
byte[] buffer = new byte[65536]; byte[] buffer = new byte[65536];
ByteArrayInputStream input = new ByteArrayInputStream(data); ByteArrayInputStream input = new ByteArrayInputStream(data);
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
BrotliInputStream brotliInput = new BrotliInputStream(input); InputStream brotliInput = newBrotliInputStream(input);
if (byByte) { if (byByte) {
byte[] oneByte = new byte[1]; byte[] oneByte = new byte[1];
while (true) { while (true) {
@ -68,16 +61,12 @@ public class DecodeTest {
@Test @Test
public void testEmpty() throws IOException { public void testEmpty() throws IOException {
checkDecodeResource( checkDecodeResource("", "\u0006");
"",
"\u0006");
} }
@Test @Test
public void testX() throws IOException { public void testX() throws IOException {
checkDecodeResource( checkDecodeResource("X", "\u000B\u0000\u0080X\u0003");
"X",
"\u000B\u0000\u0080X\u0003");
} }
@Test @Test
@ -91,54 +80,53 @@ public class DecodeTest {
public void testX64() throws IOException { public void testX64() throws IOException {
checkDecodeResource( checkDecodeResource(
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"\u001B\u003F\u0000\u0000$\u00B0\u00E2\u0099\u0080\u0012"); "\u001B?\u0000\u0000$\u00B0\u00E2\u0099\u0080\u0012");
} }
@Test @Test
public void testUkkonooa() throws IOException { public void testUkkonooa() throws IOException {
checkDecodeResource( checkDecodeResource(
"ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, " "ukko nooa, ukko nooa oli kunnon mies, kun han meni saunaan, "
+ "pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies.", + "pisti laukun naulaan, ukko nooa, ukko nooa oli kunnon mies.",
"\u001Bv\u0000\u0000\u0014J\u00AC\u009Bz\u00BD\u00E1\u0097\u009D\u007F\u008E\u00C2\u0082" "\u001Bv\u0000\u0000\u0014J\u00AC\u009Bz\u00BD\u00E1\u0097\u009D\u007F\u008E\u00C2\u0082"
+ "6\u000E\u009C\u00E0\u0090\u0003\u00F7\u008B\u009E8\u00E6\u00B6\u0000\u00AB\u00C3\u00CA" + "6\u000E\u009C\u00E0\u0090\u0003\u00F7\u008B\u009E8\u00E6\u00B6\u0000\u00AB\u00C3\u00CA"
+ "\u00A0\u00C2\u00DAf6\u00DC\u00CD\u0080\u008D.!\u00D7n\u00E3\u00EAL\u00B8\u00F0\u00D2" + "\u00A0\u00C2\u00DAf6\u00DC\u00CD\u0080\u008D.!\u00D7n\u00E3\u00EAL\u00B8\u00F0\u00D2"
+ "\u00B8\u00C7\u00C2pM:\u00F0i~\u00A1\u00B8Es\u00AB\u00C4W\u001E"); + "\u00B8\u00C7\u00C2pM:\u00F0i~\u00A1\u00B8Es\u00AB\u00C4W\u001E");
} }
@Test @Test
public void testMonkey() throws IOException { public void testMonkey() throws IOException {
checkDecodeResource( checkDecodeResource(
"znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmz" "znxcvnmz,xvnm.,zxcnv.,xcn.z,vn.zvn.zxcvn.,zxcn.vn.v,znm.,vnzx.,vnzxc.vn.z,vnz.,nv.z,nvmz"
+ "xc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxc" + "xc,nvzxcvcnm.,vczxvnzxcnvmxc.zmcnvzm.,nvmc,nzxmc,vn.mnnmzxc,vnxcnmv,znvzxcnmv,.xcnvm,zxc"
+ "nzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqeriou" + "nzxv.zx,qweryweurqioweupropqwutioweupqrioweutiopweuriopweuriopqwurioputiopqwuriowuqeriou"
+ "pqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyio" + "pqweropuweropqwurweuqriopuropqwuriopuqwriopuqweopruioqweurqweuriouqweopruioupqiytioqtyio"
+ "wtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuri" + "wtyqptypryoqweutioioqtweqruowqeytiowquiourowetyoqwupiotweuqiorweuqroipituqwiorqwtioweuri"
+ "ouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwot" + "ouytuioerytuioweryuitoweytuiweyuityeruirtyuqriqweuropqweiruioqweurioqwuerioqwyuituierwot"
+ "ueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfh" + "ueryuiotweyrtuiwertyioweryrueioqptyioruyiopqwtjkasdfhlafhlasdhfjklashjkfhasjklfhklasjdfh"
+ "klasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfa" + "klasdhfjkalsdhfklasdhjkflahsjdkfhklasfhjkasdfhasfjkasdhfklsdhalghhaf;hdklasfhjklashjklfa"
+ "sdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjka" + "sdhfasdjklfhsdjklafsd;hkldadfjjklasdhfjasddfjklfhakjklasdjfkl;asdjfasfljasdfhjklasdfhjka"
+ "ghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj", + "ghjkashf;djfklasdjfkljasdklfjklasdjfkljasdfkljaklfj",
"\u001BJ\u0003\u0000\u008C\u0094n\u00DE\u00B4\u00D7\u0096\u00B1x\u0086\u00F2-\u00E1\u001A" "\u001BJ\u0003\u0000\u008C\u0094n\u00DE\u00B4\u00D7\u0096\u00B1x\u0086\u00F2-\u00E1\u001A"
+ "\u00BC\u000B\u001C\u00BA\u00A9\u00C7\u00F7\u00CCn\u00B2B4QD\u008BN\u0013\b\u00A0\u00CDn" + "\u00BC\u000B\u001C\u00BA\u00A9\u00C7\u00F7\u00CCn\u00B2B4QD\u008BN\u0013\b\u00A0\u00CDn"
+ "\u00E8,\u00A5S\u00A1\u009C],\u001D#\u001A\u00D2V\u00BE\u00DB\u00EB&\u00BA\u0003e|\u0096j" + "\u00E8,\u00A5S\u00A1\u009C],\u001D#\u001A\u00D2V\u00BE\u00DB\u00EB&\u00BA\u0003e|\u0096j"
+ "\u00A2v\u00EC\u00EF\u0087G3\u00D6\'\u000Ec\u0095\u00E2\u001D\u008D,\u00C5\u00D1(\u009F`" + "\u00A2v\u00EC\u00EF\u0087G3\u00D6\'\u000Ec\u0095\u00E2\u001D\u008D,\u00C5\u00D1(\u009F`"
+ "\u0094o\u0002\u008B\u00DD\u00AAd\u0094,\u001E;e|\u0007EZ\u00B2\u00E2\u00FCI\u0081,\u009F" + "\u0094o\u0002\u008B\u00DD\u00AAd\u0094,\u001E;e|\u0007EZ\u00B2\u00E2\u00FCI\u0081,\u009F"
+ "@\u00AE\u00EFh\u0081\u00AC\u0016z\u000F\u00F5;m\u001C\u00B9\u001E-_\u00D5\u00C8\u00AF^" + "@\u00AE\u00EFh\u0081\u00AC\u0016z\u000F\u00F5;m\u001C\u00B9\u001E-_\u00D5\u00C8\u00AF^"
+ "\u0085\u00AA\u0005\u00BESu\u00C2\u00B0\"\u008A\u0015\u00C6\u00A3\u00B1\u00E6B\u0014" + "\u0085\u00AA\u0005\u00BESu\u00C2\u00B0\"\u008A\u0015\u00C6\u00A3\u00B1\u00E6B\u0014"
+ "\u00F4\u0084TS\u0019_\u00BE\u00C3\u00F2\u001D\u00D1\u00B7\u00E5\u00DD\u00B6\u00D9#\u00C6" + "\u00F4\u0084TS\u0019_\u00BE\u00C3\u00F2\u001D\u00D1\u00B7\u00E5\u00DD\u00B6\u00D9#\u00C6"
+ "\u00F6\u009F\u009E\u00F6Me0\u00FB\u00C0qE\u0004\u00AD\u0003\u00B5\u00BE\u00C9\u00CB" + "\u00F6\u009F\u009E\u00F6Me0\u00FB\u00C0qE\u0004\u00AD\u0003\u00B5\u00BE\u00C9\u00CB\u00FD\u00E2PZFt\u0004\r"
+ "\u00FD\u00E2PZFt\u0004\r\u00FF \u0004w\u00B2m\'\u00BFG\u00A9\u009D\u001B\u0096,b\u0090#" + "\u00FF \u0004w\u00B2m\'\u00BFG\u00A9\u009D\u001B\u0096,b\u0090#"
+ "\u008B\u00E0\u00F8\u001D\u00CF\u00AF\u001D=\u00EE\u008A\u00C8u#f\u00DD\u00DE\u00D6m" + "\u008B\u00E0\u00F8\u001D\u00CF\u00AF\u001D=\u00EE\u008A\u00C8u#f\u00DD\u00DE\u00D6m\u00E3*\u0082\u008Ax\u008A\u00DB\u00E6"
+ "\u00E3*\u0082\u008Ax\u008A\u00DB\u00E6 L\u00B7\\c\u00BA0\u00E3?\u00B6\u00EE\u008C\"" + " L\u00B7\\c\u00BA0\u00E3?\u00B6\u00EE\u008C\"\u00A2*\u00B0\"\n"
+ "\u00A2*\u00B0\"\n\u0099\u00FF=bQ\u00EE\b\u00F6=J\u00E4\u00CC\u00EF\"\u0087\u0011\u00E2" + "\u0099\u00FF=bQ\u00EE\b\u00F6=J\u00E4\u00CC\u00EF\"\u0087\u0011\u00E2"
+ "\u0083(\u00E4\u00F5\u008F5\u0019c[\u00E1Z\u0092s\u00DD\u00A1P\u009D8\\\u00EB\u00B5\u0003" + "\u0083(\u00E4\u00F5\u008F5\u0019c[\u00E1Z\u0092s\u00DD\u00A1P\u009D8\\\u00EB\u00B5\u0003jd\u0090\u0094\u00C8\u008D\u00FB/\u008A\u0086\"\u00CC\u001D\u0087\u00E0H\n"
+ "jd\u0090\u0094\u00C8\u008D\u00FB/\u008A\u0086\"\u00CC\u001D\u0087\u00E0H\n\u0096w\u00909" + "\u0096w\u00909\u00C6##H\u00FB\u0011GV\u00CA"
+ "\u00C6##H\u00FB\u0011GV\u00CA \u00E3B\u0081\u00F7w2\u00C1\u00A5\\@!e\u0017@)\u0017\u0017" + " \u00E3B\u0081\u00F7w2\u00C1\u00A5\\@!e\u0017@)\u0017\u0017lV2\u00988\u0006\u00DC\u0099M3)\u00BB\u0002\u00DFL&\u0093l\u0017\u0082\u0086"
+ "lV2\u00988\u0006\u00DC\u0099M3)\u00BB\u0002\u00DFL&\u0093l\u0017\u0082\u0086 \u00D7" + " \u00D7"
+ "\u0003y}\u009A\u0000\u00D7\u0087\u0000\u00E7\u000Bf\u00E3Lfqg\b2\u00F9\b>\u00813\u00CD" + "\u0003y}\u009A\u0000\u00D7\u0087\u0000\u00E7\u000Bf\u00E3Lfqg\b2\u00F9\b>\u00813\u00CD\u0017r1\u00F0\u00B8\u0094RK\u00901\u008Eh\u00C1\u00EF\u0090\u00C9\u00E5\u00F2a"
+ "\u0017r1\u00F0\u00B8\u0094RK\u00901\u008Eh\u00C1\u00EF\u0090\u00C9\u00E5\u00F2a\tr%" + "\tr%\u00AD\u00EC\u00C5b\u00C0\u000B\u0012\u0005\u00F7\u0091u\r"
+ "\u00AD\u00EC\u00C5b\u00C0\u000B\u0012\u0005\u00F7\u0091u\r\u00EEa..\u0019\t\u00C2\u0003" + "\u00EEa..\u0019\t\u00C2\u0003");
);
} }
@Test @Test
@ -146,8 +134,8 @@ public class DecodeTest {
checkDecodeResource( checkDecodeResource(
"The quick brown fox jumps over the lazy dog", "The quick brown fox jumps over the lazy dog",
"\u001B*\u0000\u0000\u0004\u0004\u00BAF:\u0085\u0003\u00E9\u00FA\f\u0091\u0002H\u0011," "\u001B*\u0000\u0000\u0004\u0004\u00BAF:\u0085\u0003\u00E9\u00FA\f\u0091\u0002H\u0011,"
+ "\u00F3\u008A:\u00A3V\u007F\u001A\u00AE\u00BF\u00A4\u00AB\u008EM\u00BF\u00ED\u00E2\u0004K" + "\u00F3\u008A:\u00A3V\u007F\u001A\u00AE\u00BF\u00A4\u00AB\u008EM\u00BF\u00ED\u00E2\u0004K"
+ "\u0091\u00FF\u0087\u00E9\u001E"); + "\u0091\u00FF\u0087\u00E9\u001E");
} }
@Test @Test

View File

@ -6,6 +6,8 @@
package org.brotli.dec; package org.brotli.dec;
import static org.brotli.dec.TestUtils.newBrotliInputStream;
import static org.brotli.dec.TestUtils.readUniBytes;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
@ -13,29 +15,20 @@ import static org.junit.Assume.assumeTrue;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.JUnit4; import org.junit.runners.JUnit4;
/** /** Tests for {@link BrotliInputStream}. */
* Tests for {@link Decode}.
*/
@RunWith(JUnit4.class) @RunWith(JUnit4.class)
public class SynthTest { public class SynthTest {
static byte[] readUniBytes(String uniBytes) {
byte[] result = new byte[uniBytes.length()];
for (int i = 0; i < result.length; ++i) {
result[i] = (byte) uniBytes.charAt(i);
}
return result;
}
private byte[] decompress(byte[] data) throws IOException { private byte[] decompress(byte[] data) throws IOException {
byte[] buffer = new byte[65536]; byte[] buffer = new byte[65536];
ByteArrayInputStream input = new ByteArrayInputStream(data); ByteArrayInputStream input = new ByteArrayInputStream(data);
ByteArrayOutputStream output = new ByteArrayOutputStream(); ByteArrayOutputStream output = new ByteArrayOutputStream();
BrotliInputStream brotliInput = new BrotliInputStream(input); InputStream brotliInput = newBrotliInputStream(input);
while (true) { while (true) {
int len = brotliInput.read(buffer, 0, buffer.length); int len = brotliInput.read(buffer, 0, buffer.length);
if (len <= 0) { if (len <= 0) {
@ -47,8 +40,7 @@ public class SynthTest {
return output.toByteArray(); return output.toByteArray();
} }
private void checkSynth(byte[] compressed, boolean expectSuccess, private void checkSynth(byte[] compressed, boolean expectSuccess, String expectedOutput) {
String expectedOutput) {
byte[] expected = readUniBytes(expectedOutput); byte[] expected = readUniBytes(expectedOutput);
try { try {
byte[] actual = decompress(compressed); byte[] actual = decompress(compressed);

View File

@ -0,0 +1,35 @@
package org.brotli.dec;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
/**
* Common utility methods.
*/
public final class TestUtils {
public static InputStream newBrotliInputStream(InputStream input) throws IOException {
String brotliClass = System.getProperty("BROTLI_INPUT_STREAM");
if (brotliClass == null) {
return new BrotliInputStream(input);
}
try {
Class<?> clazz = Class.forName(brotliClass);
Constructor<?> ctor = clazz.getConstructor(InputStream.class);
return (InputStream) ctor.newInstance(new Object[] { input });
} catch (Exception e) {
throw new RuntimeException(e);
}
}
static byte[] readUniBytes(String uniBytes) {
byte[] result = new byte[uniBytes.length()];
for (int i = 0; i < result.length; ++i) {
result[i] = (byte) uniBytes.charAt(i);
}
return result;
}
private TestUtils() {}
}

View File

@ -4,13 +4,19 @@ _TEST_JVM_FLAGS = [
"-DBROTLI_ENABLE_ASSERTS=true", "-DBROTLI_ENABLE_ASSERTS=true",
] ]
def brotli_java_test(name, main_class = None, jvm_flags = None, **kwargs): _KOTLIN_DECODER_DEPS = [
"//org/brotli/dec/kt:dec",
]
def brotli_java_test(name, main_class = None, jvm_flags = None, test_kotlin = False, runtime_deps = [], **kwargs):
"""test duplication rule that creates 32/64-bit test pair. """test duplication rule that creates 32/64-bit test pair.
Args: Args:
name: target name prefix name: target name prefix
main_class: override for test_class main_class: override for test_class
jvm_flags: base Java VM options jvm_flags: base Java VM options
test_kotlin: add target for Kotlin BrotliInputStream
runtime_deps: runtime target dependencies
**kwargs: pass-through **kwargs: pass-through
""" """
@ -31,6 +37,7 @@ def brotli_java_test(name, main_class = None, jvm_flags = None, **kwargs):
test_class = test_class, test_class = test_class,
jvm_flags = jvm_flags + ["-DBROTLI_32_BIT_CPU=true"], jvm_flags = jvm_flags + ["-DBROTLI_32_BIT_CPU=true"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
runtime_deps = runtime_deps,
**kwargs **kwargs
) )
@ -40,5 +47,17 @@ def brotli_java_test(name, main_class = None, jvm_flags = None, **kwargs):
test_class = test_class, test_class = test_class,
jvm_flags = jvm_flags + ["-DBROTLI_32_BIT_CPU=false"], jvm_flags = jvm_flags + ["-DBROTLI_32_BIT_CPU=false"],
visibility = ["//visibility:private"], visibility = ["//visibility:private"],
runtime_deps = runtime_deps,
**kwargs **kwargs
) )
if test_kotlin:
native.java_test(
name = name + "_kt",
main_class = main_class,
test_class = test_class,
jvm_flags = jvm_flags + ["-DBROTLI_INPUT_STREAM=org.brotli.dec.kt.BrotliInputStream"],
visibility = ["//visibility:private"],
runtime_deps = runtime_deps + _KOTLIN_DECODER_DEPS,
**kwargs
)

View File

@ -0,0 +1,17 @@
# Description:
# Korlin port of Brotli decoder.
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
package(default_visibility = ["//visibility:public"])
licenses(["notice"]) # MIT
kt_jvm_library(
name = "dec",
srcs = [
"BrotliInputStream.kt",
"Decode.kt",
],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,138 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
package org.brotli.dec.kt
import java.io.IOException
import java.io.InputStream
/**
* [InputStream] decorator that decompresses brotli data.
*
* Not thread-safe.
*/
class BrotliInputStream
@JvmOverloads
constructor(source: InputStream, byteReadBufferSize: Int = DEFAULT_INTERNAL_BUFFER_SIZE) :
InputStream() {
/** Internal buffer used for efficient byte-by-byte reading. */
private val buffer: ByteArray
/** Number of decoded but still unused bytes in internal buffer. */
private var remainingBufferBytes: Int
/** Next unused byte offset. */
private var bufferOffset: Int
/** Decoder state. */
private val state: State = State()
/**
* Creates a [InputStream] wrapper that decompresses brotli data.
*
* For byte-by-byte reading ([.read]) internal buffer with [.DEFAULT_INTERNAL_BUFFER_SIZE] size is
* allocated and used.
*
* Will block the thread until first [BitReader.CAPACITY] bytes of data of source are available.
*
* @param source underlying data source
* @throws IOException in case of corrupted data or source stream problems
*/
init {
require(byteReadBufferSize > 0) { "Bad buffer size:$byteReadBufferSize" }
buffer = ByteArray(byteReadBufferSize)
remainingBufferBytes = 0
bufferOffset = 0
try {
state.input = source
initState(state)
} catch (ex: BrotliRuntimeException) {
throw IOException("Brotli decoder initialization failed", ex)
}
}
fun attachDictionaryChunk(data: ByteArray) {
attachDictionaryChunk(state, data)
}
fun enableEagerOutput() {
enableEagerOutput(state)
}
fun enableLargeWindow() {
enableLargeWindow(state)
}
/** {@inheritDoc} */
@Throws(IOException::class)
override fun close() {
close(state)
}
/** {@inheritDoc} */
@Throws(IOException::class)
override fun read(): Int {
if (bufferOffset >= remainingBufferBytes) {
remainingBufferBytes = read(buffer, 0, buffer.size)
bufferOffset = 0
if (remainingBufferBytes == END_OF_STREAM_MARKER) {
// Both Java and C# return the same value for EOF on single-byte read.
return -1
}
}
return buffer[bufferOffset++].toInt() and 0xFF
}
/** {@inheritDoc} */
@Throws(IOException::class)
override fun read(destBuffer: ByteArray, destOffset: Int, destLen: Int): Int {
require(destOffset >= 0) { "Bad offset: $destOffset" }
require(destLen >= 0) { "Bad length: $destLen" }
require(destOffset + destLen <= destBuffer.size) {
"Buffer overflow: " + (destOffset + destLen) + " > " + destBuffer.size
}
if (destLen == 0) {
return 0
}
var copyLen = Math.max(remainingBufferBytes - bufferOffset, 0)
var offset = destOffset
var len = destLen
if (copyLen != 0) {
copyLen = Math.min(copyLen, len)
System.arraycopy(buffer, bufferOffset, destBuffer, offset, copyLen)
bufferOffset += copyLen
offset += copyLen
len -= copyLen
if (len == 0) {
return copyLen
}
}
return try {
state.output = destBuffer
state.outputOffset = offset
state.outputLength = len
state.outputUsed = 0
decompress(state)
copyLen += state.outputUsed
copyLen = if (copyLen > 0) copyLen else END_OF_STREAM_MARKER
copyLen
} catch (ex: BrotliRuntimeException) {
throw IOException("Brotli stream decoding failed", ex)
}
}
companion object {
const val DEFAULT_INTERNAL_BUFFER_SIZE = 256
/**
* Value expected by InputStream contract when stream is over.
*
* In Java it is -1. In C# it is 0 (should be patched during transpilation).
*/
private const val END_OF_STREAM_MARKER = -1
}
}

File diff suppressed because one or more lines are too long

View File

@ -23,9 +23,10 @@ java_library(
java_library( java_library(
name = "bundle_checker", name = "bundle_checker",
srcs = ["BundleChecker.java"], srcs = ["BundleChecker.java"],
runtime_deps = ["//org/brotli/dec"],
deps = [ deps = [
":bundle_helper", ":bundle_helper",
"//org/brotli/dec", "//org/brotli/dec:test_utils",
], ],
) )

View File

@ -6,7 +6,8 @@
package org.brotli.integration; package org.brotli.integration;
import org.brotli.dec.BrotliInputStream; import static org.brotli.dec.TestUtils.newBrotliInputStream;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FilterInputStream; import java.io.FilterInputStream;
@ -45,7 +46,7 @@ public class BundleChecker implements Runnable {
public void close() {} public void close() {}
}; };
BrotliInputStream decompressedStream = new BrotliInputStream(entryStream); InputStream decompressedStream = newBrotliInputStream(entryStream);
long crc; long crc;
try { try {
crc = BundleHelper.fingerprintStream(decompressedStream); crc = BundleHelper.fingerprintStream(decompressedStream);