Inverse bazel project/workspace tree (#677)

* Inverse bazel workspace tree.

Now each subproject directly depends on root (c) project.

This helps to mitigate Bazel bug bazelbuild/bazel#2391; short summary:
Bazel does not work if referenced subproject `WORKSPACE` uses any
repositories that embedding project does not.

Bright side: building C project is much faster;
no need to download closure, go and JDK...
diff --git a/.gitignore b/.gitignore
index a6d1d90..e3a69e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 buildfiles/
 **/obj/
 dist/
+**/bazel-*
 
 # Python
 __pycache__/
diff --git a/BUILD b/BUILD
index cfdd516..4ce4ad4 100644
--- a/BUILD
+++ b/BUILD
@@ -9,8 +9,6 @@
 
 exports_files(["LICENSE"])
 
-# >>> JNI headers
-
 config_setting(
     name = "darwin",
     values = {"cpu": "darwin"},
@@ -47,38 +45,6 @@
     visibility = ["//visibility:public"],
 )
 
-genrule(
-    name = "copy_link_jni_header",
-    srcs = ["@openjdk_linux//:jni_h"],
-    outs = ["jni/jni.h"],
-    cmd = "cp -f $< $@",
-)
-
-genrule(
-    name = "copy_link_jni_md_header",
-    srcs = select({
-        ":darwin": ["@openjdk_macos//:jni_md_h"],
-        ":darwin_x86_64": ["@openjdk_macos//:jni_md_h"],
-        ":windows_msys": ["@openjdk_win//:jni_md_h"],
-        ":windows_msvc": ["@openjdk_win//:jni_md_h"],
-        ":windows": ["@openjdk_win//:jni_md_h"],
-        "//conditions:default": ["@openjdk_linux//:jni_md_h"],
-    }),
-    outs = ["jni/jni_md.h"],
-    cmd = "cp -f $< $@",
-)
-
-cc_library(
-    name = "jni_inc",
-    hdrs = [
-        ":jni/jni.h",
-        ":jni/jni_md.h",
-    ],
-    includes = ["jni"],
-)
-
-# <<< JNI headers
-
 STRICT_C_OPTIONS = select({
     ":msvc": [],
     "//conditions:default": [
@@ -174,60 +140,7 @@
     ],
 )
 
-########################################################
-# WARNING: do not (transitively) depend on this target!
-########################################################
-cc_binary(
-    name = "brotli_jni.dll",
-    srcs = [
-        ":common_headers",
-        ":common_sources",
-        ":dec_headers",
-        ":dec_sources",
-        ":enc_headers",
-        ":enc_sources",
-        "//java/org/brotli/wrapper/common:jni_src",
-        "//java/org/brotli/wrapper/dec:jni_src",
-        "//java/org/brotli/wrapper/enc:jni_src",
-    ],
-    deps = [
-        ":brotli_inc",
-        ":jni_inc",
-    ],
-    linkshared = 1,
-)
-
-########################################################
-# WARNING: do not (transitively) depend on this target!
-########################################################
-cc_binary(
-    name = "brotli_jni_no_dictionary_data.dll",
-    srcs = [
-        ":common_headers",
-        ":common_sources",
-        ":dec_headers",
-        ":dec_sources",
-        ":enc_headers",
-        ":enc_sources",
-        "//java/org/brotli/wrapper/common:jni_src",
-        "//java/org/brotli/wrapper/dec:jni_src",
-        "//java/org/brotli/wrapper/enc:jni_src",
-    ],
-    defines = [
-        "BROTLI_EXTERNAL_DICTIONARY_DATA=",
-    ],
-    deps = [
-        ":brotli_inc",
-        ":jni_inc",
-    ],
-    linkshared = 1,
-)
-
 filegroup(
     name = "dictionary",
     srcs = ["c/common/dictionary.bin"],
 )
-
-load("@io_bazel_rules_go//go:def.bzl", "go_prefix")
-
-go_prefix("github.com/google/brotli")
diff --git a/WORKSPACE b/WORKSPACE
index 178e3a6..75f3768 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,96 +1,21 @@
-# Description:
-#   Bazel workspace file for Brotli.
-
 workspace(name = "org_brotli")
 
-maven_jar(
-    name = "junit_junit",
-    artifact = "junit:junit:4.12",
+local_repository(
+    name = "ignore_org_brotli_go",
+    path = "go",
 )
 
-http_archive(
-    name = "io_bazel_rules_go",
-    urls = ["https://github.com/bazelbuild/rules_go/releases/download/0.12.0/rules_go-0.12.0.tar.gz"],
-    sha256 = "c1f52b8789218bb1542ed362c4f7de7052abcf254d865d96fb7ba6d44bc15ee3",
+local_repository(
+    name = "ignore_org_brotli_java",
+    path = "java",
 )
 
-http_archive(
-    name = "io_bazel_rules_closure",
-    sha256 = "a80acb69c63d5f6437b099c111480a4493bad4592015af2127a2f49fb7512d8d",
-    strip_prefix = "rules_closure-0.7.0",
-    urls = [
-        "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/0.7.0.tar.gz",
-        "https://github.com/bazelbuild/rules_closure/archive/0.7.0.tar.gz",
-    ],
+local_repository(
+    name = "ignore_org_brotli_js",
+    path = "js",
 )
 
-new_http_archive(
-    name = "openjdk_linux",
-    urls = [
-        "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
-        "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
-        "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
-    ],
-    sha256 = "7e6284739c0e5b7142bc7a9adc61ced70dc5bb26b130b582b18e809013bcb251",
-    build_file_content = """
-package(
-    default_visibility = ["//visibility:public"],
+local_repository(
+    name = "ignore_org_brotli_research",
+    path = "research",
 )
-filegroup(
-    name = "jni_h",
-    srcs = ["zulu8.23.0.3-jdk8.0.144-linux_x64/include/jni.h"],
-)
-filegroup(
-    name = "jni_md_h",
-    srcs = ["zulu8.23.0.3-jdk8.0.144-linux_x64/include/linux/jni_md.h"],
-)""",
-)
-
-new_http_archive(
-    name = "openjdk_macos",
-    urls = [
-        "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
-        "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
-        "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
-    ],
-    sha256 = "ff533364c9cbd3b271ab5328efe28e2dd6d7bae5b630098a5683f742ecf0709d",
-    build_file_content = """
-package(
-    default_visibility = ["//visibility:public"],
-)
-filegroup(
-    name = "jni_md_h",
-    srcs = ["zulu8.23.0.3-jdk8.0.144-macosx_x64/include/darwin/jni_md.h"],
-)""",
-)
-
-new_http_archive(
-    name = "openjdk_win",
-    urls = [
-        "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
-        "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
-        "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
-    ],
-    sha256 = "f1d9d3341ef7c8c9baff3597953e99a6a7c64f8608ee62c03fdd7574b7655c02",
-    build_file_content = """
-package(
-    default_visibility = ["//visibility:public"],
-)
-filegroup(
-    name = "jni_md_h",
-    srcs = ["zulu8.23.0.3-jdk8.0.144-win_x64/include/win32/jni_md.h"],
-)""",
-)
-
-new_local_repository(
-    name = "divsufsort",
-    build_file = "//research:BUILD.libdivsufsort",
-    path = "research/libdivsufsort",
-)
-
-load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
-closure_repositories()
-
-load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
-go_rules_dependencies()
-go_register_toolchains()
diff --git a/c/common/transform.h b/c/common/transform.h
index 456c12d..83f401c 100755
--- a/c/common/transform.h
+++ b/c/common/transform.h
@@ -71,7 +71,7 @@
 
 BROTLI_COMMON_API int BrotliTransformDictionaryWord(
     uint8_t* dst, const uint8_t* word, int len,
-    const BrotliTransforms* transforms, int transform_idx);
+    const BrotliTransforms* BROTLI_RESTRICT transforms, int transform_idx);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }  /* extern "C" */
diff --git a/go/BUILD b/go/BUILD
new file mode 100644
index 0000000..de37047
--- /dev/null
+++ b/go/BUILD
@@ -0,0 +1,3 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_prefix")
+
+go_prefix("github.com/google/brotli")
diff --git a/go/WORKSPACE b/go/WORKSPACE
new file mode 100644
index 0000000..8a88c7e
--- /dev/null
+++ b/go/WORKSPACE
@@ -0,0 +1,16 @@
+workspace(name = "org_brotli_go")
+
+local_repository(
+    name = "org_brotli",
+    path = "..",
+)
+
+http_archive(
+    name = "io_bazel_rules_go",
+    urls = ["https://github.com/bazelbuild/rules_go/releases/download/0.12.0/rules_go-0.12.0.tar.gz"],
+    sha256 = "c1f52b8789218bb1542ed362c4f7de7052abcf254d865d96fb7ba6d44bc15ee3",
+)
+
+load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
+go_rules_dependencies()
+go_register_toolchains()
diff --git a/go/cbrotli/BUILD b/go/cbrotli/BUILD
index ed0a055..0f23a15 100644
--- a/go/cbrotli/BUILD
+++ b/go/cbrotli/BUILD
@@ -13,8 +13,8 @@
         "writer.go",
     ],
     cdeps = [
-        "//:brotlidec",
-        "//:brotlienc",
+        "@org_brotli//:brotlidec",
+        "@org_brotli//:brotlienc",
     ],
     cgo=True,
 )
diff --git a/java/BUILD b/java/BUILD
new file mode 100644
index 0000000..a00e2d0
--- /dev/null
+++ b/java/BUILD
@@ -0,0 +1,86 @@
+package(
+    default_visibility = ["//visibility:public"],
+)
+
+# >>> JNI headers
+
+genrule(
+    name = "copy_link_jni_header",
+    srcs = ["@openjdk_linux//:jni_h"],
+    outs = ["jni/jni.h"],
+    cmd = "cp -f $< $@",
+)
+
+genrule(
+    name = "copy_link_jni_md_header",
+    srcs = select({
+        "@org_brotli//:darwin": ["@openjdk_macos//:jni_md_h"],
+        "@org_brotli//:darwin_x86_64": ["@openjdk_macos//:jni_md_h"],
+        "@org_brotli//:windows_msys": ["@openjdk_win//:jni_md_h"],
+        "@org_brotli//:windows_msvc": ["@openjdk_win//:jni_md_h"],
+        "@org_brotli//:windows": ["@openjdk_win//:jni_md_h"],
+        "//conditions:default": ["@openjdk_linux//:jni_md_h"],
+    }),
+    outs = ["jni/jni_md.h"],
+    cmd = "cp -f $< $@",
+)
+
+cc_library(
+    name = "jni_inc",
+    hdrs = [
+        ":jni/jni.h",
+        ":jni/jni_md.h",
+    ],
+    includes = ["jni"],
+)
+
+# <<< JNI headers
+
+########################################################
+# WARNING: do not (transitively) depend on this target!
+########################################################
+cc_binary(
+    name = "brotli_jni.dll",
+    srcs = [
+        "@org_brotli//:common_headers",
+        "@org_brotli//:common_sources",
+        "@org_brotli//:dec_headers",
+        "@org_brotli//:dec_sources",
+        "@org_brotli//:enc_headers",
+        "@org_brotli//:enc_sources",
+        "//org/brotli/wrapper/common:jni_src",
+        "//org/brotli/wrapper/dec:jni_src",
+        "//org/brotli/wrapper/enc:jni_src",
+    ],
+    deps = [
+        "@org_brotli//:brotli_inc",
+        ":jni_inc",
+    ],
+    linkshared = 1,
+)
+
+########################################################
+# WARNING: do not (transitively) depend on this target!
+########################################################
+cc_binary(
+    name = "brotli_jni_no_dictionary_data.dll",
+    srcs = [
+        "@org_brotli//:common_headers",
+        "@org_brotli//:common_sources",
+        "@org_brotli//:dec_headers",
+        "@org_brotli//:dec_sources",
+        "@org_brotli//:enc_headers",
+        "@org_brotli//:enc_sources",
+        "//org/brotli/wrapper/common:jni_src",
+        "//org/brotli/wrapper/dec:jni_src",
+        "//org/brotli/wrapper/enc:jni_src",
+    ],
+    defines = [
+        "BROTLI_EXTERNAL_DICTIONARY_DATA=",
+    ],
+    deps = [
+        "@org_brotli//:brotli_inc",
+        ":jni_inc",
+    ],
+    linkshared = 1,
+)
diff --git a/java/WORKSPACE b/java/WORKSPACE
new file mode 100644
index 0000000..ab3f8b1
--- /dev/null
+++ b/java/WORKSPACE
@@ -0,0 +1,69 @@
+workspace(name = "org_brotli_java")
+
+local_repository(
+    name = "org_brotli",
+    path = "..",
+)
+
+maven_jar(
+    name = "junit_junit",
+    artifact = "junit:junit:4.12",
+)
+
+new_http_archive(
+    name = "openjdk_linux",
+    urls = [
+        "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
+        "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
+        "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
+    ],
+    sha256 = "7e6284739c0e5b7142bc7a9adc61ced70dc5bb26b130b582b18e809013bcb251",
+    build_file_content = """
+package(
+    default_visibility = ["//visibility:public"],
+)
+filegroup(
+    name = "jni_h",
+    srcs = ["zulu8.23.0.3-jdk8.0.144-linux_x64/include/jni.h"],
+)
+filegroup(
+    name = "jni_md_h",
+    srcs = ["zulu8.23.0.3-jdk8.0.144-linux_x64/include/linux/jni_md.h"],
+)""",
+)
+
+new_http_archive(
+    name = "openjdk_macos",
+    urls = [
+        "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
+        "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
+        "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
+    ],
+    sha256 = "ff533364c9cbd3b271ab5328efe28e2dd6d7bae5b630098a5683f742ecf0709d",
+    build_file_content = """
+package(
+    default_visibility = ["//visibility:public"],
+)
+filegroup(
+    name = "jni_md_h",
+    srcs = ["zulu8.23.0.3-jdk8.0.144-macosx_x64/include/darwin/jni_md.h"],
+)""",
+)
+
+new_http_archive(
+    name = "openjdk_win",
+    urls = [
+        "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
+        "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
+        "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
+    ],
+    sha256 = "f1d9d3341ef7c8c9baff3597953e99a6a7c64f8608ee62c03fdd7574b7655c02",
+    build_file_content = """
+package(
+    default_visibility = ["//visibility:public"],
+)
+filegroup(
+    name = "jni_md_h",
+    srcs = ["zulu8.23.0.3-jdk8.0.144-win_x64/include/win32/jni_md.h"],
+)""",
+)
diff --git a/java/org/brotli/dec/DictionaryData.java b/java/org/brotli/dec/DictionaryData.java
index 2355b28..a65e812 100644
--- a/java/org/brotli/dec/DictionaryData.java
+++ b/java/org/brotli/dec/DictionaryData.java
@@ -53,6 +53,7 @@
   static {
     ByteBuffer dictionary = ByteBuffer.allocateDirect(122784);
     unpackDictionaryData(dictionary, DATA0, DATA1, SKIP_FLIP);
+    dictionary.flip();
     Dictionary.setData(dictionary.asReadOnlyBuffer());
   }
 }
diff --git a/java/org/brotli/integration/BUILD b/java/org/brotli/integration/BUILD
index fc49e28..5b77325 100644
--- a/java/org/brotli/integration/BUILD
+++ b/java/org/brotli/integration/BUILD
@@ -5,9 +5,9 @@
     name = "brotli_jni_test_base",
     srcs = ["BrotliJniTestBase.java"],
     visibility = [
-        "//java/org/brotli/wrapper/common:__pkg__",
-        "//java/org/brotli/wrapper/dec:__pkg__",
-        "//java/org/brotli/wrapper/enc:__pkg__",
+        "//org/brotli/wrapper/common:__pkg__",
+        "//org/brotli/wrapper/dec:__pkg__",
+        "//org/brotli/wrapper/enc:__pkg__",
     ],
 )
 
@@ -15,8 +15,8 @@
     name = "bundle_helper",
     srcs = ["BundleHelper.java"],
     visibility = [
-        "//java/org/brotli/wrapper/dec:__pkg__",
-        "//java/org/brotli/wrapper/enc:__pkg__",
+        "//org/brotli/wrapper/dec:__pkg__",
+        "//org/brotli/wrapper/enc:__pkg__",
     ],
 )
 
@@ -25,7 +25,7 @@
     srcs = ["BundleChecker.java"],
     deps = [
         ":bundle_helper",
-        "//java/org/brotli/dec",
+        "//org/brotli/dec",
     ],
 )
 
@@ -37,7 +37,7 @@
 
 java_test(
     name = "bundle_checker_data_test",
-    args = ["java/org/brotli/integration/test_data.zip"],
+    args = ["org/brotli/integration/test_data.zip"],
     data = ["test_data.zip"],
     main_class = "org.brotli.integration.BundleChecker",
     use_testrunner = 0,
@@ -48,7 +48,7 @@
     name = "bundle_checker_fuzz_test",
     args = [
         "-s",
-        "java/org/brotli/integration/fuzz_data.zip",
+        "org/brotli/integration/fuzz_data.zip",
     ],
     data = ["fuzz_data.zip"],
     main_class = "org.brotli.integration.BundleChecker",
@@ -60,7 +60,7 @@
     name = "test_data",
     srcs = ["test_data.zip"],
     visibility = [
-        "//java/org/brotli/wrapper/dec:__pkg__",
+        "//org/brotli/wrapper/dec:__pkg__",
     ],
 )
 
@@ -68,6 +68,6 @@
     name = "test_corpus",
     srcs = ["test_corpus.zip"],
     visibility = [
-        "//java/org/brotli/wrapper/enc:__pkg__",
+        "//org/brotli/wrapper/enc:__pkg__",
     ],
 )
diff --git a/java/org/brotli/wrapper/common/BUILD b/java/org/brotli/wrapper/common/BUILD
index 8816a20..48b02f3 100644
--- a/java/org/brotli/wrapper/common/BUILD
+++ b/java/org/brotli/wrapper/common/BUILD
@@ -20,45 +20,41 @@
     ),
 )
 
+java_library(
+    name = "test_lib",
+    testonly = 1,
+    srcs = glob(["*Test*.java"]),
+    deps = [
+        ":common",
+        "//org/brotli/dec",
+        "//org/brotli/integration:brotli_jni_test_base",
+        "//org/brotli/wrapper/dec",
+        "@junit_junit//jar",
+    ],
+)
+
 java_test(
     name = "SetZeroDictionaryTest",
+    test_class = "org.brotli.wrapper.common.SetZeroDictionaryTest",
     size = "small",
-    srcs = ["SetZeroDictionaryTest.java"],
     data = [
         ":brotli_jni_no_dictionary_data",  # Bazel JNI workaround
     ],
     jvm_flags = [
         "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni_no_dictionary_data)",
     ],
-    deps = [
-        ":common",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/wrapper/dec",
-        "@junit_junit//jar",
-    ],
-)
-
-filegroup(
-    name = "rfc_dictionary",
-    srcs = ["//:dictionary"],
+    runtime_deps = [":test_lib"],
 )
 
 java_test(
     name = "SetRfcDictionaryTest",
+    test_class = "org.brotli.wrapper.common.SetRfcDictionaryTest",
     size = "small",
-    srcs = ["SetRfcDictionaryTest.java"],
     data = [
-        ":rfc_dictionary",
         ":brotli_jni_no_dictionary_data",  # Bazel JNI workaround
     ],
     jvm_flags = [
-        "-DRFC_DICTIONARY=$(location :rfc_dictionary)",
         "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni_no_dictionary_data)",
     ],
-    deps = [
-        ":common",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/wrapper/dec",
-        "@junit_junit//jar",
-    ],
+    runtime_deps = [":test_lib"],
 )
diff --git a/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java b/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java
index 0c20f1c..8aecf5f 100644
--- a/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java
+++ b/java/org/brotli/wrapper/common/SetRfcDictionaryTest.java
@@ -11,11 +11,12 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import org.brotli.dec.Dictionary;
 import org.brotli.integration.BrotliJniTestBase;
 import org.brotli.wrapper.dec.BrotliInputStream;
 import java.io.ByteArrayInputStream;
-import java.io.FileInputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import org.junit.Test;
@@ -29,35 +30,18 @@
 public class SetRfcDictionaryTest extends BrotliJniTestBase {
 
   @Test
-  public void testRfcDictionaryChecksums() throws IOException, NoSuchAlgorithmException {
-    FileInputStream dictionary = new FileInputStream(System.getProperty("RFC_DICTIONARY"));
-    byte[] data = new byte[BrotliCommon.RFC_DICTIONARY_SIZE + 1];
-    int offset = 0;
-    try {
-      int readBytes;
-      while ((readBytes = dictionary.read(data, offset, data.length - offset)) != -1) {
-        offset += readBytes;
-        if (offset > BrotliCommon.RFC_DICTIONARY_SIZE) {
-          break;
-        }
-      }
-    } finally {
-      dictionary.close();
-    }
-    if (offset != BrotliCommon.RFC_DICTIONARY_SIZE) {
-      fail("dictionary size mismatch");
-    }
-
+  public void testRfcDictionaryChecksums() throws NoSuchAlgorithmException {
+    System.err.println(Dictionary.getData().slice().remaining());
     MessageDigest md5 = MessageDigest.getInstance("MD5");
-    md5.update(data, 0, offset);
+    md5.update(Dictionary.getData().slice());
     assertTrue(BrotliCommon.checkDictionaryDataMd5(md5.digest()));
 
     MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
-    sha1.update(data, 0, offset);
+    sha1.update(Dictionary.getData().slice());
     assertTrue(BrotliCommon.checkDictionaryDataSha1(sha1.digest()));
 
     MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
-    sha256.update(data, 0, offset);
+    sha256.update(Dictionary.getData().slice());
     assertTrue(BrotliCommon.checkDictionaryDataSha256(sha256.digest()));
   }
 
@@ -66,12 +50,7 @@
     /* "leftdatadataleft" encoded with dictionary words. */
     byte[] data = {27, 15, 0, 0, 0, 0, -128, -29, -76, 13, 0, 0, 7, 91, 38, 49, 64, 2, 0, -32, 78,
         27, 65, -128, 32, 80, 16, 36, 8, 6};
-    FileInputStream dictionary = new FileInputStream(System.getProperty("RFC_DICTIONARY"));
-    try {
-      BrotliCommon.setDictionaryData(dictionary);
-    } finally {
-      dictionary.close();
-    }
+    BrotliCommon.setDictionaryData(Dictionary.getData());
 
     BrotliInputStream decoder = new BrotliInputStream(new ByteArrayInputStream(data));
     byte[] output = new byte[17];
diff --git a/java/org/brotli/wrapper/dec/BUILD b/java/org/brotli/wrapper/dec/BUILD
index c8808fa..fcf0dbf 100644
--- a/java/org/brotli/wrapper/dec/BUILD
+++ b/java/org/brotli/wrapper/dec/BUILD
@@ -15,6 +15,18 @@
     ),
 )
 
+java_library(
+    name = "test_lib",
+    testonly = 1,
+    srcs = glob(["*Test*.java"]),
+    deps = [
+        ":dec",
+        "//org/brotli/integration:brotli_jni_test_base",
+        "//org/brotli/integration:bundle_helper",
+        "@junit_junit//jar",
+    ],
+)
+
 filegroup(
     name = "brotli_jni",
     srcs = ["//:brotli_jni.dll"],
@@ -22,13 +34,13 @@
 
 filegroup(
     name = "test_bundle",
-    srcs = ["//java/org/brotli/integration:test_data"],
+    srcs = ["//org/brotli/integration:test_data"],
 )
 
 java_test(
     name = "BrotliDecoderChannelTest",
+    test_class = "org.brotli.wrapper.dec.BrotliDecoderChannelTest",
     size = "large",
-    srcs = ["BrotliDecoderChannelTest.java"],
     data = [
         ":brotli_jni",  # Bazel JNI workaround
         ":test_bundle",
@@ -37,18 +49,13 @@
         "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
         "-DTEST_BUNDLE=$(location :test_bundle)",
     ],
-    deps = [
-        ":dec",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/integration:bundle_helper",
-        "@junit_junit//jar",
-    ],
+    runtime_deps = [":test_lib"],
 )
 
 java_test(
     name = "BrotliInputStreamTest",
+    test_class = "org.brotli.wrapper.dec.BrotliInputStreamTest",
     size = "large",
-    srcs = ["BrotliInputStreamTest.java"],
     data = [
         ":brotli_jni",  # Bazel JNI workaround
         ":test_bundle",
@@ -57,18 +64,13 @@
         "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
         "-DTEST_BUNDLE=$(location :test_bundle)",
     ],
-    deps = [
-        ":dec",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/integration:bundle_helper",
-        "@junit_junit//jar",
-    ],
+    runtime_deps = [":test_lib"],
 )
 
 java_test(
     name = "DecoderTest",
+    test_class = "org.brotli.wrapper.dec.DecoderTest",
     size = "large",
-    srcs = ["DecoderTest.java"],
     data = [
         ":brotli_jni",  # Bazel JNI workaround
         ":test_bundle",
@@ -77,10 +79,5 @@
         "-DBROTLI_JNI_LIBRARY=$(location :brotli_jni)",
         "-DTEST_BUNDLE=$(location :test_bundle)",
     ],
-    deps = [
-        ":dec",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/integration:bundle_helper",
-        "@junit_junit//jar",
-    ],
+    runtime_deps = [":test_lib"],
 )
diff --git a/java/org/brotli/wrapper/enc/BUILD b/java/org/brotli/wrapper/enc/BUILD
index 6ea048c..42ad23e 100644
--- a/java/org/brotli/wrapper/enc/BUILD
+++ b/java/org/brotli/wrapper/enc/BUILD
@@ -20,15 +20,28 @@
     ),
 )
 
+java_library(
+    name = "test_lib",
+    testonly = 1,
+    srcs = glob(["*Test*.java"]),
+    deps = [
+        ":enc",
+        "//org/brotli/integration:brotli_jni_test_base",
+        "//org/brotli/integration:bundle_helper",
+        "//org/brotli/wrapper/dec",
+        "@junit_junit//jar",
+    ],
+)
+
 filegroup(
     name = "test_bundle",
-    srcs = ["//java/org/brotli/integration:test_corpus"],
+    srcs = ["//org/brotli/integration:test_corpus"],
 )
 
 java_test(
     name = "BrotliEncoderChannelTest",
+    test_class = "org.brotli.wrapper.enc.BrotliEncoderChannelTest",
     size = "large",
-    srcs = ["BrotliEncoderChannelTest.java"],
     data = [
         ":brotli_jni",  # Bazel JNI workaround
         ":test_bundle",
@@ -38,19 +51,13 @@
         "-DTEST_BUNDLE=$(location :test_bundle)",
     ],
     shard_count = 15,
-    deps = [
-        ":enc",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/integration:bundle_helper",
-        "//java/org/brotli/wrapper/dec",
-        "@junit_junit//jar",
-    ],
+    runtime_deps = [":test_lib"],
 )
 
 java_test(
     name = "BrotliOutputStreamTest",
+    test_class = "org.brotli.wrapper.enc.BrotliOutputStreamTest",
     size = "large",
-    srcs = ["BrotliOutputStreamTest.java"],
     data = [
         ":brotli_jni",  # Bazel JNI workaround
         ":test_bundle",
@@ -60,19 +67,13 @@
         "-DTEST_BUNDLE=$(location :test_bundle)",
     ],
     shard_count = 15,
-    deps = [
-        ":enc",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/integration:bundle_helper",
-        "//java/org/brotli/wrapper/dec",
-        "@junit_junit//jar",
-    ],
+    runtime_deps = [":test_lib"],
 )
 
 java_test(
     name = "EncoderTest",
+    test_class = "org.brotli.wrapper.enc.EncoderTest",
     size = "large",
-    srcs = ["EncoderTest.java"],
     data = [
         ":brotli_jni",  # Bazel JNI workaround
         ":test_bundle",
@@ -82,11 +83,5 @@
         "-DTEST_BUNDLE=$(location :test_bundle)",
     ],
     shard_count = 15,
-    deps = [
-        ":enc",
-        "//java/org/brotli/integration:brotli_jni_test_base",
-        "//java/org/brotli/integration:bundle_helper",
-        "//java/org/brotli/wrapper/dec",
-        "@junit_junit//jar",
-    ],
+    runtime_deps = [":test_lib"],
 )
diff --git a/js/WORKSPACE b/js/WORKSPACE
new file mode 100644
index 0000000..b364e5f
--- /dev/null
+++ b/js/WORKSPACE
@@ -0,0 +1,14 @@
+workspace(name = "org_brotli_js")
+
+http_archive(
+    name = "io_bazel_rules_closure",
+    sha256 = "a80acb69c63d5f6437b099c111480a4493bad4592015af2127a2f49fb7512d8d",
+    strip_prefix = "rules_closure-0.7.0",
+    urls = [
+        "https://mirror.bazel.build/github.com/bazelbuild/rules_closure/archive/0.7.0.tar.gz",
+        "https://github.com/bazelbuild/rules_closure/archive/0.7.0.tar.gz",
+    ],
+)
+
+load("@io_bazel_rules_closure//closure:defs.bzl", "closure_repositories")
+closure_repositories()
diff --git a/research/BUILD b/research/BUILD
index 9da08c2..7b7d81b 100755
--- a/research/BUILD
+++ b/research/BUILD
@@ -40,5 +40,5 @@
     name = "brotli_decoder",
     srcs = ["brotli_decoder.c"],
     linkstatic = 1,
-    deps = ["//:brotlidec"],
+    deps = ["@org_brotli//:brotlidec"],
 )
diff --git a/research/WORKSPACE b/research/WORKSPACE
new file mode 100644
index 0000000..bb0f8ca
--- /dev/null
+++ b/research/WORKSPACE
@@ -0,0 +1,12 @@
+workspace(name = "org_brotli_research")
+
+local_repository(
+    name = "org_brotli",
+    path = "..",
+)
+
+new_local_repository(
+    name = "divsufsort",
+    build_file = "BUILD.libdivsufsort",
+    path = "libdivsufsort",
+)
diff --git a/scripts/.travis.sh b/scripts/.travis.sh
index 579856a..6387e22 100755
--- a/scripts/.travis.sh
+++ b/scripts/.travis.sh
@@ -58,7 +58,11 @@
 		./c/fuzz/test_fuzzer.sh
 		;;
 	    "bazel")
-		bazel test -c opt ...:all
+		bazel build -c opt ...:all &&
+		cd go && bazel test -c opt ...:all && cd .. &&
+		cd java && bazel test -c opt ...:all && cd .. &&
+		cd js && bazel test -c opt ...:all && cd .. &&
+		cd research && bazel build -c opt ...:all && cd ..
 		;;
 	esac
 	;;
diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml
index 8f48e57..4e15a5b 100644
--- a/scripts/appveyor.yml
+++ b/scripts/appveyor.yml
@@ -53,6 +53,7 @@
     SET "PATH=C:\mingw-w64\%TOOLCHAIN%\bin;%PATH%" &&

     COPY C:\msys64\usr\bin\make.exe C:\mingw-w64\%TOOLCHAIN%\bin\make.exe

   )

+- SET "ROOT=%APPVEYOR_BUILD_FOLDER%"

 

 build_script:

 - IF "%BUILD_SYSTEM%"=="CMake" ( cmake --build . --config Debug )

@@ -63,17 +64,25 @@
     appveyor PushArtifact brotli-win-%ARCH%-%RELEASE_DATE%.zip && cd ..

   )

 - IF "%BUILD_SYSTEM%"=="bazel" (

-    bazel --batch build -c opt java/org/brotli/wrapper/...:all &&

-    python scripts/fix-win-bazel-build.py &&

-    cd bazel-bin && 7z a -tzip -mx9 brotli-win-bazel-jni-%RELEASE_DATE%.zip brotli_jni.dll &&

-    appveyor PushArtifact brotli-win-bazel-jni-%RELEASE_DATE%.zip && cd ..

+    cd java &&

+      %ROOT%\bazel.exe --batch build -c opt org/brotli/wrapper/...:all &&

+      python %ROOT%\scripts\fix-win-bazel-build.py &&

+      cd bazel-bin &&

+        7z a -tzip -mx9 brotli-win-bazel-jni-%RELEASE_DATE%.zip brotli_jni.dll &&

+        appveyor PushArtifact brotli-win-bazel-jni-%RELEASE_DATE%.zip &&

+      cd .. &&

+    cd ..

   )

 

 test_script:

 - IF "%BUILD_SYSTEM%"=="CMake" ( ctest --output-on-failure --interactive-debug-mode 0 -C Debug )

 - IF "%BUILD_SYSTEM%"=="Python" ( python setup.py test )

 - IF "%BUILD_SYSTEM%"=="make" ( sh -c "make test" )

-- IF "%BUILD_SYSTEM%"=="bazel" ( bazel --batch test -c opt --test_output streamed java/org/brotli/wrapper/...:all )

+- IF "%BUILD_SYSTEM%"=="bazel" (

+    cd java &&

+      %ROOT%\bazel.exe --batch test -c opt --test_output streamed org/brotli/wrapper/...:all &&

+    cd ..

+  )

 

 deploy:

 - provider: BinTray

diff --git a/scripts/fix-win-bazel-build.py b/scripts/fix-win-bazel-build.py
index fcba6f3..7a9b211 100644
--- a/scripts/fix-win-bazel-build.py
+++ b/scripts/fix-win-bazel-build.py
@@ -3,19 +3,22 @@
 import os.path
 from shutil import copyfile
 
+print('Searching for manifests...')
+
 matches = []
-for root, dirnames, filenames in os.walk('bazel-bin\\java\\org\\brotli'):
+for root, dirnames, filenames in os.walk('bazel-bin\\org\\brotli'):
   for filename in fnmatch.filter(filenames, '*.runfiles_manifest'):
     matches.append(os.path.join(root, filename))
 
 for match in matches:
+  print('Scanning manifest ' + match)
   runfiles = match[:-len('_manifest')]
   with open(match) as manifest:
     for entry in manifest:
       entry = entry.strip()
-      if not entry.startswith("org_brotli"):
+      if not entry.startswith("org_brotli_java"):
         continue
-      if entry.startswith('org_brotli/external'):
+      if entry.startswith('org_brotli_java/external'):
         continue
       (alias, space, link) = entry.partition(' ')
       if alias.endswith('.jar') or alias.endswith('.exe'):
@@ -29,3 +32,5 @@
         if not os.path.exists(parent):
           os.makedirs(parent)
         copyfile(link, dst)
+
+print('Finished resolving symlinks')