Merge branch 'develop' into develop-s390x

This commit is contained in:
Bryan Chan 2015-06-16 13:30:54 -04:00
commit 3113ffb074
45 changed files with 4714 additions and 3876 deletions

View File

@ -1,6 +0,0 @@
#Tue Mar 29 16:49:37 JST 2011
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

File diff suppressed because one or more lines are too long

View File

@ -1,9 +0,0 @@
#Tue Mar 29 16:49:37 JST 2011
activeProfiles=
eclipse.preferences.version=1
fullBuildGoals=process-test-resources
includeModules=false
resolveWorkspaceProjects=true
resourceFilterGoals=process-resources resources\:testResources
skipCompilerPlugin=true
version=1

View File

@ -1,6 +1,6 @@
TARGET:=target TARGET:=target
SRC:=src/main/java SRC:=src/main/java
include $(SRC)/org/xerial/snappy/VERSION include src/main/resources/org/xerial/snappy/VERSION
ifndef JAVA_HOME ifndef JAVA_HOME
$(error Set JAVA_HOME environment variable) $(error Set JAVA_HOME environment variable)

View File

@ -1,9 +1,16 @@
## Features under consideration
* `SnappyIndexer` for parallel compression/decompression
* CUI commands (snap/unsnap)
Since vesion 1.1.0.x, Java 6 (1.6) or higher is required. Since vesion 1.1.0.x, Java 6 (1.6) or higher is required.
## snappy-java-1.1.2-RC2 (18 May 2015)
* Fix #107: SnappyOutputStream.close() is not idempotent
## snappy-java-1.1.2-RC1 (13 May 2015)
* SnappyInputStream now supports reading concatenated compressed results of SnappyOutputStream
* There has been no compressed format change since 1.0.5.x. So You can read the compressed results interchangeablly between these versions.
* Fixes a problem when java.io.tmpdir does not exist.
## snappy-java-1.1.1.7 (14 Apr 2015)
* Fixes #100
## snappy-java-1.1.1.6 (26 Oct 2014) ## snappy-java-1.1.1.6 (26 Oct 2014)
* Fixes #88, #89, #90 and #91 * Fixes #88, #89, #90 and #91
* Fixed the broken build of 1.1.1.4 and memory leak bug 1.1.1.5 (so never use these versions) * Fixed the broken build of 1.1.1.4 and memory leak bug 1.1.1.5 (so never use these versions)

View File

@ -39,7 +39,7 @@ Add the following dependency to your pom.xml:
<dependency> <dependency>
<groupId>org.xerial.snappy</groupId> <groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId> <artifactId>snappy-java</artifactId>
<version>1.1.1.6</version> <version>1.1.2-RC3</version>
<type>jar</type> <type>jar</type>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
@ -47,7 +47,7 @@ Add the following dependency to your pom.xml:
### Using with sbt ### Using with sbt
``` ```
libraryDependencies += "org.xerial.snappy" % "snappy-java" % "1.1.1.6" libraryDependencies += "org.xerial.snappy" % "snappy-java" % "1.1.2-RC3"
``` ```
@ -75,7 +75,7 @@ In addition, high-level methods (`Snappy.compress(String)`, `Snappy.compress(flo
### Stream-based API ### Stream-based API
Stream-based compressor/decompressor `SnappyOutputStream`/`SnappyInputStream` are also available for reading/writing large data sets. `SnappyFramedOutputStream`/`SnappyFramedInputStream` can be used for the [framing format](https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt). Stream-based compressor/decompressor `SnappyOutputStream`/`SnappyInputStream` are also available for reading/writing large data sets. `SnappyFramedOutputStream`/`SnappyFramedInputStream` can be used for the [framing format](https://code.google.com/p/snappy/source/browse/trunk/framing_format.txt).
* See also [Javadoc API](https://oss.sonatype.org/service/local/repositories/releases/archive/org/xerial/snappy/snappy-java/1.1.1.6/snappy-java-1.1.1.6-javadoc.jar/!/index.html) * See also [Javadoc API](https://oss.sonatype.org/service/local/repositories/releases/archive/org/xerial/snappy/snappy-java/1.1.2-RC3/snappy-java-1.1.2-RC3-javadoc.jar/!/index.html)
#### Compatibility Notes #### Compatibility Notes
* `SnappyOutputStream` and `SnappyInputStream` use `[magic header:16 bytes]([block size:int32][compressed data:byte array])*` format. You can read the result of `Snappy.compress` with `SnappyInputStream`, but you cannot read the compressed data generated by `SnappyOutputStream` with `Snappy.uncompress`. Here is the compatibility matrix of data foramt: * `SnappyOutputStream` and `SnappyInputStream` use `[magic header:16 bytes]([block size:int32][compressed data:byte array])*` format. You can read the result of `Snappy.compress` with `SnappyInputStream`, but you cannot read the compressed data generated by `SnappyOutputStream` with `Snappy.uncompress`. Here is the compatibility matrix of data foramt:
@ -99,7 +99,7 @@ If you have snappy-java-(VERSION).jar in the current directory, use `-classpath`
## Public discussion group ## Public discussion group
Post bug reports or feature request to the Issue Tracker: <https://github.com/xerial/snappy-java/issues> Post bug reports or feature request to the Issue Tracker: <https://github.com/xerial/snappy-java/issues>
Public discussion forum is here: <http://groups.google.com/group/xerial?hl=en Xerial Public Discussion Group> Public discussion forum is here: [Xerial Public Discussion Group)[http://groups.google.com/group/xerial?hl=en]
## Building from the source code ## Building from the source code
@ -173,7 +173,15 @@ snappy-java uses sbt (simple build tool for Scala) as a build tool. Here is a si
> ~test-only * # run tests that matches a given name pattern > ~test-only * # run tests that matches a given name pattern
> publishM2 # publish jar to $HOME/.m2/repository > publishM2 # publish jar to $HOME/.m2/repository
> package # create jar file > package # create jar file
> findbugs # Produce findbugs report in target/findbugs
> jacoco:cover # Report the code coverage of tests to target/jacoco folder
If you need to see detailed debug messages, launch sbt with `-Dloglevel=debug` option:
```
$ ./sbt -Dloglevel=debug
```
For the details of sbt usage, see my blog post: [Building Java Projects with sbt](http://xerial.org/blog/2014/03/24/sbt/) For the details of sbt usage, see my blog post: [Building Java Projects with sbt](http://xerial.org/blog/2014/03/24/sbt/)
## Miscellaneous Notes ## Miscellaneous Notes

View File

@ -1,6 +1,4 @@
import SonatypeKeys._ import de.johoop.findbugs4sbt.ReportType
sonatypeSettings
name := "snappy-java" name := "snappy-java"
@ -10,7 +8,7 @@ organizationName := "xerial.org"
description := "snappy-java: A fast compression/decompression library" description := "snappy-java: A fast compression/decompression library"
profileName := "org.xerial" sonatypeProfileName := "org.xerial"
pomExtra := { pomExtra := {
<url>https://github.comm/xerial/snappy-java</url> <url>https://github.comm/xerial/snappy-java</url>
@ -47,10 +45,18 @@ pomExtra := {
</scm> </scm>
} }
scalaVersion := "2.11.1" scalaVersion := "2.11.6"
javacOptions in (Compile, compile) ++= Seq("-encoding", "UTF-8", "-Xlint:unchecked", "-Xlint:deprecation", "-source", "1.6", "-target", "1.6") javacOptions in (Compile, compile) ++= Seq("-encoding", "UTF-8", "-Xlint:unchecked", "-Xlint:deprecation", "-source", "1.6", "-target", "1.6")
javacOptions in doc := {
val opts = Seq("-source", "1.6")
if (scala.util.Properties.isJavaAtLeast("1.8"))
opts ++ Seq("-Xdoclint:none")
else
opts
}
testOptions += Tests.Argument(TestFrameworks.JUnit, "-q", "-v") testOptions += Tests.Argument(TestFrameworks.JUnit, "-q", "-v")
concurrentRestrictions in Global := Seq(Tags.limit(Tags.Test, 1)) concurrentRestrictions in Global := Seq(Tags.limit(Tags.Test, 1))
@ -63,6 +69,14 @@ logBuffered in Test := false
incOptions := incOptions.value.withNameHashing(true) incOptions := incOptions.value.withNameHashing(true)
findbugsSettings
findbugsReportType := Some(ReportType.FancyHtml)
findbugsReportPath := Some(crossTarget.value / "findbugs" / "report.html")
jacoco.settings
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"junit" % "junit" % "4.8.2" % "test", "junit" % "junit" % "4.8.2" % "test",
"org.codehaus.plexus" % "plexus-classworlds" % "2.4" % "test", "org.codehaus.plexus" % "plexus-classworlds" % "2.4" % "test",
@ -87,10 +101,14 @@ OsgiKeys.importPackage := Seq("""org.osgi.framework;version="[1.5,2)"""")
OsgiKeys.additionalHeaders := Map( OsgiKeys.additionalHeaders := Map(
"Bundle-NativeCode" -> Seq( "Bundle-NativeCode" -> Seq(
"org/xerial/snappy/native/Windows/x86_64/snappyjava.dll;osname=win32;processor=x86-64", "org/xerial/snappy/native/Windows/x86_64/snappyjava.dll;osname=win32;processor=x86-64",
"org/xerial/snappy/native/Windows/x86_64/snappyjava.dll;osname=win32;processor=x64",
"org/xerial/snappy/native/Windows/x86_64/snappyjava.dll;osname=win32;processor=amd64",
"org/xerial/snappy/native/Windows/x86/snappyjava.dll;osname=win32;processor=x86", "org/xerial/snappy/native/Windows/x86/snappyjava.dll;osname=win32;processor=x86",
"org/xerial/snappy/native/Mac/x86/libsnappyjava.jnilib;osname=macosx;processor=x86", "org/xerial/snappy/native/Mac/x86/libsnappyjava.jnilib;osname=macosx;processor=x86",
"org/xerial/snappy/native/Mac/x86_64/libsnappyjava.jnilib;osname=macosx;processor=x86-64", "org/xerial/snappy/native/Mac/x86_64/libsnappyjava.jnilib;osname=macosx;processor=x86-64",
"org/xerial/snappy/native/Linux/x86_64/libsnappyjava.so;osname=linux;processor=x86-64", "org/xerial/snappy/native/Linux/x86_64/libsnappyjava.so;osname=linux;processor=x86-64",
"org/xerial/snappy/native/Linux/x86_64/libsnappyjava.so;osname=linux;processor=x64",
"org/xerial/snappy/native/Linux/x86_64/libsnappyjava.so;osname=linux;processor=amd64",
"org/xerial/snappy/native/Linux/x86/libsnappyjava.so;osname=linux;processor=x86", "org/xerial/snappy/native/Linux/x86/libsnappyjava.so;osname=linux;processor=x86",
"org/xerial/snappy/native/Linux/aarch64/libsnappyjava.so;osname=linux;processor=aarch64", "org/xerial/snappy/native/Linux/aarch64/libsnappyjava.so;osname=linux;processor=aarch64",
"org/xerial/snappy/native/Linux/arm/libsnappyjava.so;osname=linux;processor=arm", "org/xerial/snappy/native/Linux/arm/libsnappyjava.so;osname=linux;processor=arm",
@ -106,3 +124,28 @@ OsgiKeys.additionalHeaders := Map(
"Bundle-ActivationPolicy" -> "lazy", "Bundle-ActivationPolicy" -> "lazy",
"Bundle-Name" -> "snappy-java: A fast compression/decompression library" "Bundle-Name" -> "snappy-java: A fast compression/decompression library"
) )
import ReleaseTransformations._
import sbtrelease._
releaseTagName := { (version in ThisBuild).value }
releaseProcess := Seq[ReleaseStep](
checkSnapshotDependencies,
inquireVersions,
runClean,
runTest,
setReleaseVersion,
commitReleaseVersion,
tagRelease,
ReleaseStep(action = Command.process("publishSigned", _)),
setNextVersion,
commitNextVersion,
ReleaseStep(action = Command.process("sonatypeReleaseAll", _)),
pushChanges
)
com.etsy.sbt.Checkstyle.checkstyleSettings
com.etsy.sbt.Checkstyle.CheckstyleTasks.checkstyleConfig := file("src/checkstyle/checks.xml")

View File

@ -1,5 +1,5 @@
#ifndef __CONFIG_H #ifndef __CONFIG_H
#define __CONFIG_H #define __CONFIG_H
#endif // __CONFIG_H #endif // __CONFIG_H

View File

@ -1,2 +1,2 @@
sbt.version=0.13.6 sbt.version=0.13.8

View File

@ -1,12 +1,14 @@
addSbtPlugin("com.github.gseitz" % "sbt-release" % "0.7.1") addSbtPlugin("com.github.gseitz" % "sbt-release" % "1.0.0")
addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.2.1") addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "0.5.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-pgp" % "0.8.3") addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")
addSbtPlugin("de.johoop" % "findbugs4sbt" % "1.3.0") addSbtPlugin("de.johoop" % "findbugs4sbt" % "1.4.0")
addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.5") addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.5")
addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.7.0") addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.7.0")
addSbtPlugin("com.etsy" % "sbt-checkstyle-plugin" % "0.4.3")

10
sbt
View File

@ -4,8 +4,8 @@
# Author: Paul Phillips <paulp@typesafe.com> # Author: Paul Phillips <paulp@typesafe.com>
# todo - make this dynamic # todo - make this dynamic
declare -r sbt_release_version="0.13.1" declare -r sbt_release_version="0.13.8"
declare -r sbt_unreleased_version="0.13.2-SNAPSHOT" # -sbt-dev doesn't work at present declare -r sbt_unreleased_version="0.13.8-SNAPSHOT" # -sbt-dev doesn't work at present
declare -r buildProps="project/build.properties" declare -r buildProps="project/build.properties"
declare sbt_jar sbt_dir sbt_create sbt_launch_dir declare sbt_jar sbt_dir sbt_create sbt_launch_dir
@ -119,12 +119,12 @@ init_default_option_file () {
declare -r cms_opts="-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC" declare -r cms_opts="-XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC"
declare -r jit_opts="-XX:ReservedCodeCacheSize=256m -XX:+TieredCompilation" declare -r jit_opts="-XX:ReservedCodeCacheSize=256m -XX:+TieredCompilation"
declare -r default_jvm_opts="-Dfile.encoding=UTF8 -XX:MaxPermSize=384m -Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts" declare -r default_jvm_opts="-ea -Dfile.encoding=UTF8 -Xms512m -Xmx1536m -Xss2m $jit_opts $cms_opts"
declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy" declare -r noshare_opts="-Dsbt.global.base=project/.sbtboot -Dsbt.boot.directory=project/.boot -Dsbt.ivy.home=project/.ivy"
declare -r latest_28="2.8.2" declare -r latest_28="2.8.2"
declare -r latest_29="2.9.3" declare -r latest_29="2.9.3"
declare -r latest_210="2.10.3" declare -r latest_210="2.10.5"
declare -r latest_211="2.11.0-M5" declare -r latest_211="2.11.6"
declare -r script_path="$(get_script_path "$BASH_SOURCE")" declare -r script_path="$(get_script_path "$BASH_SOURCE")"
declare -r script_name="${script_path##*/}" declare -r script_name="${script_path##*/}"

117
src/checkstyle/checks.xml Normal file
View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="FileTabCharacter"/>
<module name="NewlineAtEndOfFile">
<property name="lineSeparator" value="lf"/>
</module>
<module name="RegexpMultiline">
<property name="format" value="\r"/>
<property name="message" value="Line contains carriage return"/>
</module>
<module name="RegexpMultiline">
<property name="format" value=" \n"/>
<property name="message" value="Line has trailing whitespace"/>
</module>
<module name="RegexpMultiline">
<property name="format" value="\{\n\n"/>
<property name="message" value="Blank line after opening brace"/>
</module>
<module name="RegexpMultiline">
<property name="format" value="\n\n\}"/>
<property name="message" value="Blank line before closing brace"/>
</module>
<module name="RegexpMultiline">
<property name="format" value="\n\n\n"/>
<property name="message" value="Multiple consecutive blank lines"/>
</module>
<module name="RegexpMultiline">
<property name="format" value="\n\n\Z"/>
<property name="message" value="Blank line before end of file"/>
</module>
<module name="TreeWalker">
<module name="EmptyBlock">
<property name="option" value="text"/>
<property name="tokens" value="
LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_IF,
LITERAL_FOR, LITERAL_TRY, LITERAL_WHILE, INSTANCE_INIT, STATIC_INIT"/>
</module>
<module name="EmptyStatement"/>
<module name="EmptyForInitializerPad"/>
<module name="EmptyForIteratorPad">
<property name="option" value="space"/>
</module>
<module name="MethodParamPad">
<property name="allowLineBreaks" value="true"/>
<property name="option" value="nospace"/>
</module>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="NeedBraces"/>
<module name="LeftCurly">
<property name="option" value="nl"/>
<property name="tokens" value="CLASS_DEF, CTOR_DEF, INTERFACE_DEF, METHOD_DEF"/>
</module>
<module name="LeftCurly">
<property name="option" value="eol"/>
<property name="tokens" value="
LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY, LITERAL_FOR,
LITERAL_IF, LITERAL_SWITCH, LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE"/>
</module>
<module name="RightCurly">
<property name="option" value="alone"/>
</module>
<module name="GenericWhitespace"/>
<module name="WhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="UpperEll"/>
<module name="DefaultComesLast"/>
<module name="ArrayTypeStyle"/>
<module name="MultipleVariableDeclarations"/>
<module name="ModifierOrder"/>
<module name="OneStatementPerLine"/>
<module name="StringLiteralEquality"/>
<module name="MutableException"/>
<module name="EqualsHashCode"/>
<module name="InnerAssignment"/>
<module name="InterfaceIsType"/>
<module name="HideUtilityClassConstructor"/>
<module name="MemberName"/>
<module name="LocalVariableName"/>
<module name="LocalFinalVariableName"/>
<module name="TypeName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="ClassTypeParameterName">
<property name="format" value="^[A-Z][0-9]?$"/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="^[A-Z][0-9]?$"/>
</module>
<module name="AvoidStarImport"/>
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="ignoreEnhancedForColon" value="false"/>
<property name="tokens" value="
ASSIGN, BAND, BAND_ASSIGN, BOR, BOR_ASSIGN, BSR, BSR_ASSIGN,
BXOR, BXOR_ASSIGN, COLON, DIV, DIV_ASSIGN, EQUAL, GE, GT, LAND, LE,
LITERAL_ASSERT, LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE,
LITERAL_FINALLY, LITERAL_FOR, LITERAL_IF, LITERAL_RETURN,
LITERAL_SYNCHRONIZED, LITERAL_TRY, LITERAL_WHILE,
LOR, LT, MINUS, MINUS_ASSIGN, MOD, MOD_ASSIGN, NOT_EQUAL,
PLUS, PLUS_ASSIGN, QUESTION, SL, SLIST, SL_ASSIGN, SR, SR_ASSIGN,
STAR, STAR_ASSIGN, TYPE_EXTENSION_AND"/>
</module>
</module>
</module>

View File

@ -30,9 +30,8 @@ import java.util.Locale;
/** /**
* Provides OS name and architecture name. * Provides OS name and architecture name.
* *
* @author leo * @author leo
*
*/ */
public class OSInfo public class OSInfo
{ {
@ -91,8 +90,8 @@ public class OSInfo
archMapping.put(IBMZ_64, IBMZ_64); archMapping.put(IBMZ_64, IBMZ_64);
} }
public static void main(String[] args)
public static void main(String[] args) { {
if (args.length >= 1) { if (args.length >= 1) {
if ("--os".equals(args[0])) { if ("--os".equals(args[0])) {
System.out.print(getOSName()); System.out.print(getOSName());
@ -107,27 +106,31 @@ public class OSInfo
System.out.print(getNativeLibFolderPathForCurrentOS()); System.out.print(getNativeLibFolderPathForCurrentOS());
} }
public static String getNativeLibFolderPathForCurrentOS() { public static String getNativeLibFolderPathForCurrentOS()
{
return getOSName() + "/" + getArchName(); return getOSName() + "/" + getArchName();
} }
public static String getOSName() { public static String getOSName()
{
return translateOSNameToFolderName(System.getProperty("os.name")); return translateOSNameToFolderName(System.getProperty("os.name"));
} }
public static String getArchName() { public static String getArchName()
{
// if running Linux on ARM, need to determine ABI of JVM // if running Linux on ARM, need to determine ABI of JVM
String osArch = System.getProperty("os.arch"); String osArch = System.getProperty("os.arch");
if (osArch.startsWith("arm") && System.getProperty("os.name").contains("Linux")) { if (osArch.startsWith("arm") && System.getProperty("os.name").contains("Linux")) {
String javaHome = System.getProperty("java.home"); String javaHome = System.getProperty("java.home");
try { try {
// determine if first JVM found uses ARM hard-float ABI // determine if first JVM found uses ARM hard-float ABI
String[] cmdarray = { "/bin/sh", "-c", "find '" + javaHome + String[] cmdarray = {"/bin/sh", "-c", "find '" + javaHome +
"' -name 'libjvm.so' | head -1 | xargs readelf -A | " + "' -name 'libjvm.so' | head -1 | xargs readelf -A | " +
"grep 'Tag_ABI_VFP_args: VFP registers'" }; "grep 'Tag_ABI_VFP_args: VFP registers'"};
int exitCode = Runtime.getRuntime().exec(cmdarray).waitFor(); int exitCode = Runtime.getRuntime().exec(cmdarray).waitFor();
if (exitCode == 0) if (exitCode == 0) {
return "armhf"; return "armhf";
}
} }
catch (IOException e) { catch (IOException e) {
// ignored: fall back to "arm" arch (soft-float ABI) // ignored: fall back to "arm" arch (soft-float ABI)
@ -135,16 +138,18 @@ public class OSInfo
catch (InterruptedException e) { catch (InterruptedException e) {
// ignored: fall back to "arm" arch (soft-float ABI) // ignored: fall back to "arm" arch (soft-float ABI)
} }
} }
else { else {
String lc = osArch.toLowerCase(Locale.US); String lc = osArch.toLowerCase(Locale.US);
if(archMapping.containsKey(lc)) if (archMapping.containsKey(lc)) {
return archMapping.get(lc); return archMapping.get(lc);
}
} }
return translateArchNameToFolderName(osArch); return translateArchNameToFolderName(osArch);
} }
static String translateOSNameToFolderName(String osName) { static String translateOSNameToFolderName(String osName)
{
if (osName.contains("Windows")) { if (osName.contains("Windows")) {
return "Windows"; return "Windows";
} }
@ -162,7 +167,8 @@ public class OSInfo
} }
} }
static String translateArchNameToFolderName(String archName) { static String translateArchNameToFolderName(String archName)
{
return archName.replaceAll("\\W", ""); return archName.replaceAll("\\W", "");
} }
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +1,68 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// SnappyBundleActivator.java // SnappyBundleActivator.java
// Since: 2011/06/22 10:01:46 // Since: 2011/06/22 10:01:46
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import org.osgi.framework.Bundle; import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext; import org.osgi.framework.BundleContext;
import java.util.jar.Manifest; import java.util.jar.Manifest;
/** /**
* OSGi bundle entry point * OSGi bundle entry point
* *
* @author leo * @author leo
* */
*/ public class SnappyBundleActivator
public class SnappyBundleActivator implements BundleActivator implements BundleActivator
{ {
/** /**
* Name of the Snappy native library * Name of the Snappy native library
*/ */
public static final String LIBRARY_NAME = "snappyjava"; public static final String LIBRARY_NAME = "snappyjava";
/** /**
* Make a call to {@link System#loadLibrary(String)} to load the native library which assumes * Make a call to {@link System#loadLibrary(String)} to load the native library which assumes
* that the library is available on the path based on this {@link Bundle}'s {@link Manifest}. * that the library is available on the path based on this {@link Bundle}'s {@link Manifest}.
*/ */
public void start(BundleContext context) throws Exception public void start(BundleContext context)
throws Exception
{ {
String library = System.mapLibraryName(LIBRARY_NAME); String library = System.mapLibraryName(LIBRARY_NAME);
if (library.toLowerCase().endsWith(".dylib")) if (library.toLowerCase().endsWith(".dylib")) {
{ // some MacOS JDK7+ vendors map to dylib instead of jnilib
// some MacOS JDK7+ vendors map to dylib instead of jnilib library = library.replace(".dylib", ".jnilib");
library = library.replace(".dylib", ".jnilib"); }
} System.loadLibrary(library);
System.loadLibrary(library); SnappyLoader.setApi(new SnappyNative());
SnappyLoader.setApi(new SnappyNative()); }
}
public void stop(BundleContext context)
public void stop(BundleContext context) throws Exception throws Exception
{ {
SnappyLoader.setApi(null); SnappyLoader.setApi(null);
SnappyLoader.cleanUpExtractedNativeLib(); SnappyLoader.cleanUpExtractedNativeLib();
} }
} }

View File

@ -1,117 +1,134 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// SnappyCodec.java // SnappyCodec.java
// Since: 2011/04/03 14:50:20 // Since: 2011/04/03 14:50:20
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Arrays; import java.util.Arrays;
/** /**
* Preamble header for {@link SnappyOutputStream}. * Preamble header for {@link SnappyOutputStream}.
* * <p/>
* <p> * <p>
* The magic header is the following 8 bytes data: * The magic header is the following 8 bytes data:
* * <p/>
* <pre> * <pre>
* -126, 'S', 'N', 'A', 'P', 'P', 'Y', 0 * -126, 'S', 'N', 'A', 'P', 'P', 'Y', 0
* </pre> * </pre>
* * <p/>
* </p> * </p>
* *
* @author leo * @author leo
* */
*/ public class SnappyCodec
public class SnappyCodec {
{ static final byte[] MAGIC_HEADER = new byte[] {-126, 'S', 'N', 'A', 'P', 'P', 'Y', 0};
public static final byte[] MAGIC_HEADER = new byte[] { -126, 'S', 'N', 'A', 'P', 'P', 'Y', 0 }; public static final int MAGIC_LEN = MAGIC_HEADER.length;
public static final int MAGIC_LEN = MAGIC_HEADER.length; public static final int HEADER_SIZE = MAGIC_LEN + 8;
public static final int HEADER_SIZE = MAGIC_LEN + 8; public static final int MAGIC_HEADER_HEAD = SnappyOutputStream.readInt(MAGIC_HEADER, 0);
public static final int DEFAULT_VERSION = 1; static {
public static final int MINIMUM_COMPATIBLE_VERSION = 1; assert (MAGIC_HEADER_HEAD < 0);
}
public final byte[] magic;
public final int version; public static final int DEFAULT_VERSION = 1;
public final int compatibleVersion; public static final int MINIMUM_COMPATIBLE_VERSION = 1;
private final byte[] headerArray; public static final SnappyCodec currentHeader = new SnappyCodec(MAGIC_HEADER, DEFAULT_VERSION, MINIMUM_COMPATIBLE_VERSION);
private SnappyCodec(byte[] magic, int version, int compatibleVersion) { public final byte[] magic;
this.magic = magic; public final int version;
this.version = version; public final int compatibleVersion;
this.compatibleVersion = compatibleVersion; private final byte[] headerArray;
ByteArrayOutputStream header = new ByteArrayOutputStream(HEADER_SIZE); private SnappyCodec(byte[] magic, int version, int compatibleVersion)
DataOutputStream d = new DataOutputStream(header); {
try { this.magic = magic;
d.write(magic, 0, MAGIC_LEN); this.version = version;
d.writeInt(version); this.compatibleVersion = compatibleVersion;
d.writeInt(compatibleVersion);
d.close(); ByteArrayOutputStream header = new ByteArrayOutputStream(HEADER_SIZE);
} DataOutputStream d = new DataOutputStream(header);
catch(IOException e) { try {
throw new RuntimeException(e); d.write(magic, 0, MAGIC_LEN);
} d.writeInt(version);
headerArray = header.toByteArray(); d.writeInt(compatibleVersion);
} d.close();
}
@Override catch (IOException e) {
public String toString() { throw new RuntimeException(e);
return String.format("version:%d, compatible version:%d", version, compatibleVersion); }
} headerArray = header.toByteArray();
}
public static int headerSize() {
return HEADER_SIZE; public static byte[] getMagicHeader()
} {
return MAGIC_HEADER.clone();
public int writeHeader(byte[] dst, int dstOffset) { }
System.arraycopy(headerArray, 0, dst, dstOffset, headerArray.length);
return headerArray.length; @Override
} public String toString()
{
public int writeHeader(OutputStream out) throws IOException { return String.format("version:%d, compatible version:%d", version, compatibleVersion);
out.write(headerArray, 0, headerArray.length); }
return headerArray.length;
} public static int headerSize()
{
public boolean isValidMagicHeader() { return HEADER_SIZE;
return Arrays.equals(MAGIC_HEADER, magic); }
}
public int writeHeader(byte[] dst, int dstOffset)
public static SnappyCodec readHeader(InputStream in) throws IOException { {
DataInputStream d = new DataInputStream(in); System.arraycopy(headerArray, 0, dst, dstOffset, headerArray.length);
byte[] magic = new byte[MAGIC_LEN]; return headerArray.length;
d.readFully(magic, 0, MAGIC_LEN); }
int version = d.readInt();
int compatibleVersion = d.readInt(); public int writeHeader(OutputStream out)
return new SnappyCodec(magic, version, compatibleVersion); throws IOException
} {
out.write(headerArray, 0, headerArray.length);
public static SnappyCodec currentHeader = new SnappyCodec(MAGIC_HEADER, DEFAULT_VERSION, MINIMUM_COMPATIBLE_VERSION); return headerArray.length;
}
}
public boolean isValidMagicHeader()
{
return Arrays.equals(MAGIC_HEADER, magic);
}
public static SnappyCodec readHeader(InputStream in)
throws IOException
{
DataInputStream d = new DataInputStream(in);
byte[] magic = new byte[MAGIC_LEN];
d.readFully(magic, 0, MAGIC_LEN);
int version = d.readInt();
int compatibleVersion = d.readInt();
return new SnappyCodec(magic, version, compatibleVersion);
}
}

View File

@ -1,62 +1,65 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// SnappyError.java // SnappyError.java
// Since: 2011/03/30 15:22:43 // Since: 2011/03/30 15:22:43
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
/** /**
* Used when serious errors (unchecked exception) are observed. * Used when serious errors (unchecked exception) are observed.
* *
* @author leo * @author leo
* */
*/ public class SnappyError
public class SnappyError extends Error extends Error
{ {
/** /**
* *
*/ */
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public final SnappyErrorCode errorCode; public final SnappyErrorCode errorCode;
public SnappyError(SnappyErrorCode code) { public SnappyError(SnappyErrorCode code)
super(); {
this.errorCode = code; super();
} this.errorCode = code;
}
public SnappyError(SnappyErrorCode code, Error e) {
super(e); public SnappyError(SnappyErrorCode code, Error e)
this.errorCode = code; {
} super(e);
this.errorCode = code;
public SnappyError(SnappyErrorCode code, String message) { }
super(message);
this.errorCode = code; public SnappyError(SnappyErrorCode code, String message)
} {
super(message);
@Override this.errorCode = code;
public String getMessage() { }
return String.format("[%s] %s", errorCode.name(), super.getMessage());
} @Override
public String getMessage()
} {
return String.format("[%s] %s", errorCode.name(), super.getMessage());
}
}

View File

@ -1,64 +1,67 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// SnappyErrorCode.java // SnappyErrorCode.java
// Since: 2011/03/30 14:56:50 // Since: 2011/03/30 14:56:50
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
/** /**
* Error codes of snappy-java * Error codes of snappy-java
* *
* @author leo * @author leo
* */
*/ public enum SnappyErrorCode
public enum SnappyErrorCode { {
// DO NOT change these error code IDs because these numbers are used inside SnappyNative.cpp // DO NOT change these error code IDs because these numbers are used inside SnappyNative.cpp
UNKNOWN(0), UNKNOWN(0),
FAILED_TO_LOAD_NATIVE_LIBRARY(1), FAILED_TO_LOAD_NATIVE_LIBRARY(1),
PARSING_ERROR(2), PARSING_ERROR(2),
NOT_A_DIRECT_BUFFER(3), NOT_A_DIRECT_BUFFER(3),
OUT_OF_MEMORY(4), OUT_OF_MEMORY(4),
FAILED_TO_UNCOMPRESS(5), FAILED_TO_UNCOMPRESS(5),
EMPTY_INPUT(6), EMPTY_INPUT(6),
INCOMPATIBLE_VERSION(7), INCOMPATIBLE_VERSION(7),
INVALID_CHUNK_SIZE(8) INVALID_CHUNK_SIZE(8);
;
public final int id;
public final int id;
private SnappyErrorCode(int id)
private SnappyErrorCode(int id) { {
this.id = id; this.id = id;
} }
public static SnappyErrorCode getErrorCode(int id) { public static SnappyErrorCode getErrorCode(int id)
for (SnappyErrorCode code : SnappyErrorCode.values()) { {
if (code.id == id) for (SnappyErrorCode code : SnappyErrorCode.values()) {
return code; if (code.id == id) {
} return code;
return UNKNOWN; }
} }
return UNKNOWN;
public static String getErrorMessage(int id) { }
return getErrorCode(id).name();
} public static String getErrorMessage(int id)
} {
return getErrorCode(id).name();
}
}

View File

@ -1,74 +1,82 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// SnappyException.java // SnappyException.java
// Since: 2011/03/30 14:56:14 // Since: 2011/03/30 14:56:14
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import java.io.IOException; import java.io.IOException;
/** /**
* Exception in snappy-java * Exception in snappy-java
* *
* @deprecated Snappy-java now uses {@link IOException} * @author leo
* @author leo * @deprecated Snappy-java now uses {@link IOException}
* */
*/ @Deprecated
@Deprecated public class SnappyException
public class SnappyException extends Exception extends Exception
{ {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public final SnappyErrorCode errorCode; public final SnappyErrorCode errorCode;
public SnappyException(int code) { public SnappyException(int code)
this(SnappyErrorCode.getErrorCode(code)); {
} this(SnappyErrorCode.getErrorCode(code));
}
public SnappyException(SnappyErrorCode errorCode) {
super(); public SnappyException(SnappyErrorCode errorCode)
this.errorCode = errorCode; {
} super();
this.errorCode = errorCode;
public SnappyException(SnappyErrorCode errorCode, Exception e) { }
super(e);
this.errorCode = errorCode; public SnappyException(SnappyErrorCode errorCode, Exception e)
} {
super(e);
public SnappyException(SnappyErrorCode errorCode, String message) { this.errorCode = errorCode;
super(message); }
this.errorCode = errorCode;
} public SnappyException(SnappyErrorCode errorCode, String message)
{
public SnappyErrorCode getErrorCode() { super(message);
return errorCode; this.errorCode = errorCode;
} }
public static void throwException(int errorCode) throws SnappyException { public SnappyErrorCode getErrorCode()
throw new SnappyException(errorCode); {
} return errorCode;
}
@Override
public String getMessage() { public static void throwException(int errorCode)
return String.format("[%s] %s", errorCode.name(), super.getMessage()); throws SnappyException
} {
} throw new SnappyException(errorCode);
}
@Override
public String getMessage()
{
return String.format("[%s] %s", errorCode.name(), super.getMessage());
}
}

View File

@ -1,186 +1,187 @@
/* /*
* Created: Apr 12, 2013 * Created: Apr 12, 2013
*/ */
package org.xerial.snappy; package org.xerial.snappy;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel; import java.nio.channels.ReadableByteChannel;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
/** /**
* Constants and utilities for implementing x-snappy-framed. * Constants and utilities for implementing x-snappy-framed.
* *
* @author Brett Okken * @author Brett Okken
* @since 1.1.0 * @since 1.1.0
*/ */
final class SnappyFramed { final class SnappyFramed
public static final int COMPRESSED_DATA_FLAG = 0x00; {
public static final int COMPRESSED_DATA_FLAG = 0x00;
public static final int UNCOMPRESSED_DATA_FLAG = 0x01;
public static final int UNCOMPRESSED_DATA_FLAG = 0x01;
public static final int STREAM_IDENTIFIER_FLAG = 0xff;
public static final int STREAM_IDENTIFIER_FLAG = 0xff;
private static final int MASK_DELTA = 0xa282ead8;
private static final int MASK_DELTA = 0xa282ead8;
/**
* Sun specific mechanisms to clean up resources associated with direct byte buffers. /**
*/ * Sun specific mechanisms to clean up resources associated with direct byte buffers.
@SuppressWarnings("unchecked") */
private static final Class<? extends ByteBuffer> SUN_DIRECT_BUFFER = (Class<? extends ByteBuffer>) lookupClassQuietly("sun.nio.ch.DirectBuffer"); @SuppressWarnings("unchecked")
private static final Method SUN_BUFFER_CLEANER; private static final Class<? extends ByteBuffer> SUN_DIRECT_BUFFER = (Class<? extends ByteBuffer>) lookupClassQuietly("sun.nio.ch.DirectBuffer");
private static final Method SUN_CLEANER_CLEAN; private static final Method SUN_BUFFER_CLEANER;
private static final Method SUN_CLEANER_CLEAN;
static
{ static {
Method bufferCleaner = null; Method bufferCleaner = null;
Method cleanerClean = null; Method cleanerClean = null;
try { try {
//operate under the assumption that if the sun direct buffer class exists, //operate under the assumption that if the sun direct buffer class exists,
//all of the sun classes exist //all of the sun classes exist
if (SUN_DIRECT_BUFFER != null) { if (SUN_DIRECT_BUFFER != null) {
bufferCleaner = SUN_DIRECT_BUFFER.getMethod("cleaner", (Class[])null); bufferCleaner = SUN_DIRECT_BUFFER.getMethod("cleaner", (Class[]) null);
Class<?> cleanClazz = lookupClassQuietly("sun.misc.Cleaner"); Class<?> cleanClazz = lookupClassQuietly("sun.misc.Cleaner");
cleanerClean = cleanClazz.getMethod("clean", (Class[])null); cleanerClean = cleanClazz.getMethod("clean", (Class[]) null);
} }
} catch(Throwable t) { }
Logger.getLogger(SnappyFramed.class.getName()).log(Level.FINE, "Exception occurred attempting to lookup Sun specific DirectByteBuffer cleaner classes.", t); catch (Throwable t) {
} Logger.getLogger(SnappyFramed.class.getName()).log(Level.FINE, "Exception occurred attempting to lookup Sun specific DirectByteBuffer cleaner classes.", t);
SUN_BUFFER_CLEANER = bufferCleaner; }
SUN_CLEANER_CLEAN = cleanerClean; SUN_BUFFER_CLEANER = bufferCleaner;
} SUN_CLEANER_CLEAN = cleanerClean;
}
/**
* The header consists of the stream identifier flag, 3 bytes indicating a /**
* length of 6, and "sNaPpY" in ASCII. * The header consists of the stream identifier flag, 3 bytes indicating a
*/ * length of 6, and "sNaPpY" in ASCII.
public static final byte[] HEADER_BYTES = new byte[] { */
(byte) STREAM_IDENTIFIER_FLAG, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61, public static final byte[] HEADER_BYTES = new byte[] {
0x50, 0x70, 0x59 }; (byte) STREAM_IDENTIFIER_FLAG, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61,
0x50, 0x70, 0x59};
public static int maskedCrc32c(byte[] data)
{ public static int maskedCrc32c(byte[] data)
return maskedCrc32c(data, 0, data.length); {
} return maskedCrc32c(data, 0, data.length);
}
public static int maskedCrc32c(byte[] data, int offset, int length)
{ public static int maskedCrc32c(byte[] data, int offset, int length)
final PureJavaCrc32C crc32c = new PureJavaCrc32C(); {
crc32c.update(data, offset, length); final PureJavaCrc32C crc32c = new PureJavaCrc32C();
return mask(crc32c.getIntegerValue()); crc32c.update(data, offset, length);
} return mask(crc32c.getIntegerValue());
}
/**
* Checksums are not stored directly, but masked, as checksumming data and /**
* then its own checksum can be problematic. The masking is the same as used * Checksums are not stored directly, but masked, as checksumming data and
* in Apache Hadoop: Rotate the checksum by 15 bits, then add the constant * then its own checksum can be problematic. The masking is the same as used
* 0xa282ead8 (using wraparound as normal for unsigned integers). This is * in Apache Hadoop: Rotate the checksum by 15 bits, then add the constant
* equivalent to the following C code: * 0xa282ead8 (using wraparound as normal for unsigned integers). This is
* * equivalent to the following C code:
* <pre> * <p/>
* uint32_t mask_checksum(uint32_t x) { * <pre>
* return ((x >> 15) | (x << 17)) + 0xa282ead8; * uint32_t mask_checksum(uint32_t x) {
* } * return ((x >> 15) | (x << 17)) + 0xa282ead8;
* </pre> * }
*/ * </pre>
public static int mask(int crc) */
{ public static int mask(int crc)
// Rotate right by 15 bits and add a constant. {
return ((crc >>> 15) | (crc << 17)) + MASK_DELTA; // Rotate right by 15 bits and add a constant.
} return ((crc >>> 15) | (crc << 17)) + MASK_DELTA;
}
static final int readBytes(ReadableByteChannel source, ByteBuffer dest) throws IOException static final int readBytes(ReadableByteChannel source, ByteBuffer dest)
{ throws IOException
// tells how many bytes to read. {
final int expectedLength = dest.remaining(); // tells how many bytes to read.
final int expectedLength = dest.remaining();
int totalRead = 0;
int totalRead = 0;
// how many bytes were read.
int lastRead = source.read(dest); // how many bytes were read.
int lastRead = source.read(dest);
totalRead = lastRead;
totalRead = lastRead;
// if we did not read as many bytes as we had hoped, try reading again.
if (lastRead < expectedLength) // if we did not read as many bytes as we had hoped, try reading again.
{ if (lastRead < expectedLength) {
// as long the buffer is not full (remaining() == 0) and we have not reached EOF (lastRead == -1) keep reading. // as long the buffer is not full (remaining() == 0) and we have not reached EOF (lastRead == -1) keep reading.
while (dest.remaining() != 0 && lastRead != -1) while (dest.remaining() != 0 && lastRead != -1) {
{ lastRead = source.read(dest);
lastRead = source.read(dest);
// if we got EOF, do not add to total read.
// if we got EOF, do not add to total read. if (lastRead != -1) {
if (lastRead != -1) totalRead += lastRead;
{ }
totalRead += lastRead; }
} }
}
} if (totalRead > 0) {
dest.limit(dest.position());
if (totalRead > 0) }
{ else {
dest.limit(dest.position()); dest.position(dest.limit());
} }
else
{ return totalRead;
dest.position(dest.limit()); }
}
static int skip(final ReadableByteChannel source, final int skip, final ByteBuffer buffer)
return totalRead; throws IOException
} {
if (skip <= 0) {
static int skip(final ReadableByteChannel source, final int skip, final ByteBuffer buffer) throws IOException return 0;
{ }
if (skip <= 0) {
return 0; int toSkip = skip;
} int skipped = 0;
while (toSkip > 0 && skipped != -1) {
int toSkip = skip; buffer.clear();
int skipped = 0; if (toSkip < buffer.capacity()) {
while(toSkip > 0 && skipped != -1) { buffer.limit(toSkip);
buffer.clear(); }
if (toSkip < buffer.capacity()) {
buffer.limit(toSkip); skipped = source.read(buffer);
} if (skipped > 0) {
toSkip -= skipped;
skipped = source.read(buffer); }
if (skipped > 0) { }
toSkip -= skipped;
} buffer.clear();
} return skip - toSkip;
}
buffer.clear();
return skip - toSkip; private static Class<?> lookupClassQuietly(String name)
} {
try {
private static Class<?> lookupClassQuietly(String name) { return SnappyFramed.class.getClassLoader().loadClass(name);
try { }
return SnappyFramed.class.getClassLoader().loadClass(name); catch (Throwable t) {
} catch (Throwable t) { Logger.getLogger(SnappyFramed.class.getName()).log(Level.FINE, "Did not find requested class: " + name, t);
Logger.getLogger(SnappyFramed.class.getName()).log(Level.FINE, "Did not find requested class: " + name, t); }
}
return null;
return null; }
}
/**
/** * Provides jvm implementation specific operation to aggressively release resources associated with <i>buffer</i>.
* Provides jvm implementation specific operation to aggressively release resources associated with <i>buffer</i>. *
* @param buffer The {@code ByteBuffer} to release. Must not be {@code null}. Must be {@link ByteBuffer#isDirect() direct}. * @param buffer The {@code ByteBuffer} to release. Must not be {@code null}. Must be {@link ByteBuffer#isDirect() direct}.
*/ */
static void releaseDirectByteBuffer(ByteBuffer buffer) static void releaseDirectByteBuffer(ByteBuffer buffer)
{ {
assert buffer != null && buffer.isDirect(); assert buffer != null && buffer.isDirect();
if (SUN_DIRECT_BUFFER != null && SUN_DIRECT_BUFFER.isAssignableFrom(buffer.getClass())) { if (SUN_DIRECT_BUFFER != null && SUN_DIRECT_BUFFER.isAssignableFrom(buffer.getClass())) {
try { try {
Object cleaner = SUN_BUFFER_CLEANER.invoke(buffer, (Object[]) null); Object cleaner = SUN_BUFFER_CLEANER.invoke(buffer, (Object[]) null);
SUN_CLEANER_CLEAN.invoke(cleaner, (Object[]) null); SUN_CLEANER_CLEAN.invoke(cleaner, (Object[]) null);
} catch (Throwable t) { }
Logger.getLogger(SnappyFramed.class.getName()).log(Level.FINE, "Exception occurred attempting to clean up Sun specific DirectByteBuffer.", t); catch (Throwable t) {
} Logger.getLogger(SnappyFramed.class.getName()).log(Level.FINE, "Exception occurred attempting to clean up Sun specific DirectByteBuffer.", t);
} }
} }
} }
}

View File

@ -28,12 +28,15 @@ import java.util.Arrays;
* href="http://snappy.googlecode.com/svn/trunk/framing_format.txt" * href="http://snappy.googlecode.com/svn/trunk/framing_format.txt"
* >x-snappy-framed</a> as an {@link InputStream} and * >x-snappy-framed</a> as an {@link InputStream} and
* {@link ReadableByteChannel}. * {@link ReadableByteChannel}.
* *
* @author Brett Okken * @author Brett Okken
* @since 1.1.0 * @since 1.1.0
*/ */
public final class SnappyFramedInputStream extends InputStream implements public final class SnappyFramedInputStream
ReadableByteChannel { extends InputStream
implements
ReadableByteChannel
{
private final ReadableByteChannel rbc; private final ReadableByteChannel rbc;
private final ByteBuffer frameHeader; private final ByteBuffer frameHeader;
@ -77,51 +80,51 @@ public final class SnappyFramedInputStream extends InputStream implements
/** /**
* Creates a Snappy input stream to read data from the specified underlying * Creates a Snappy input stream to read data from the specified underlying
* input stream. * input stream.
* *
* @param in * @param in the underlying input stream. Must not be {@code null}.
* the underlying input stream. Must not be {@code null}.
*/ */
public SnappyFramedInputStream(InputStream in) throws IOException { public SnappyFramedInputStream(InputStream in)
throws IOException
{
this(in, true); this(in, true);
} }
/** /**
* Creates a Snappy input stream to read data from the specified underlying * Creates a Snappy input stream to read data from the specified underlying
* input stream. * input stream.
* *
* @param in * @param in the underlying input stream. Must not be {@code null}.
* the underlying input stream. Must not be {@code null}. * @param verifyChecksums if true, checksums in input stream will be verified
* @param verifyChecksums
* if true, checksums in input stream will be verified
*/ */
public SnappyFramedInputStream(InputStream in, boolean verifyChecksums) public SnappyFramedInputStream(InputStream in, boolean verifyChecksums)
throws IOException { throws IOException
{
this(Channels.newChannel(in), verifyChecksums); this(Channels.newChannel(in), verifyChecksums);
} }
/** /**
* Creates a Snappy input stream to read data from the specified underlying * Creates a Snappy input stream to read data from the specified underlying
* channel. * channel.
* *
* @param in * @param in the underlying readable channel. Must not be {@code null}.
* the underlying readable channel. Must not be {@code null}.
*/ */
public SnappyFramedInputStream(ReadableByteChannel in) public SnappyFramedInputStream(ReadableByteChannel in)
throws IOException { throws IOException
{
this(in, true); this(in, true);
} }
/** /**
* Creates a Snappy input stream to read data from the specified underlying * Creates a Snappy input stream to read data from the specified underlying
* channel. * channel.
* *
* @param in * @param in the underlying readable channel. Must not be {@code null}.
* the underlying readable channel. Must not be {@code null}. * @param verifyChecksums if true, checksums in input stream will be verified
* @param verifyChecksums
* if true, checksums in input stream will be verified
*/ */
public SnappyFramedInputStream(ReadableByteChannel in, public SnappyFramedInputStream(ReadableByteChannel in,
boolean verifyChecksums) throws IOException { boolean verifyChecksums)
throws IOException
{
if (in == null) { if (in == null) {
throw new NullPointerException("in is null"); throw new NullPointerException("in is null");
} }
@ -150,16 +153,17 @@ public final class SnappyFramedInputStream extends InputStream implements
/** /**
* @param size * @param size
*/ */
private void allocateBuffersBasedOnSize(int size) { private void allocateBuffersBasedOnSize(int size)
{
if (input != null) { if (input != null) {
releaseDirectByteBuffer(input); releaseDirectByteBuffer(input);
} }
if (uncompressedDirect != null) { if (uncompressedDirect != null) {
releaseDirectByteBuffer(uncompressedDirect); releaseDirectByteBuffer(uncompressedDirect);
} }
input = ByteBuffer.allocateDirect(size); input = ByteBuffer.allocateDirect(size);
final int maxCompressedLength = Snappy.maxCompressedLength(size); final int maxCompressedLength = Snappy.maxCompressedLength(size);
uncompressedDirect = ByteBuffer.allocateDirect(maxCompressedLength); uncompressedDirect = ByteBuffer.allocateDirect(maxCompressedLength);
@ -167,7 +171,9 @@ public final class SnappyFramedInputStream extends InputStream implements
} }
@Override @Override
public int read() throws IOException { public int read()
throws IOException
{
if (closed) { if (closed) {
return -1; return -1;
} }
@ -178,7 +184,9 @@ public final class SnappyFramedInputStream extends InputStream implements
} }
@Override @Override
public int read(byte[] output, int offset, int length) throws IOException { public int read(byte[] output, int offset, int length)
throws IOException
{
if (output == null) { if (output == null) {
throw new IllegalArgumentException("output is null"); throw new IllegalArgumentException("output is null");
@ -207,7 +215,9 @@ public final class SnappyFramedInputStream extends InputStream implements
} }
@Override @Override
public int available() throws IOException { public int available()
throws IOException
{
if (closed) { if (closed) {
return 0; return 0;
} }
@ -218,7 +228,8 @@ public final class SnappyFramedInputStream extends InputStream implements
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public boolean isOpen() { public boolean isOpen()
{
return !closed; return !closed;
} }
@ -226,7 +237,9 @@ public final class SnappyFramedInputStream extends InputStream implements
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public int read(ByteBuffer dst) throws IOException { public int read(ByteBuffer dst)
throws IOException
{
if (dst == null) { if (dst == null) {
throw new IllegalArgumentException("dst is null"); throw new IllegalArgumentException("dst is null");
@ -259,14 +272,15 @@ public final class SnappyFramedInputStream extends InputStream implements
* Any calls after the source has been exhausted will result in a return * Any calls after the source has been exhausted will result in a return
* value of {@code 0}. * value of {@code 0}.
* </p> * </p>
* *
* @param os * @param os The destination to write decompressed content to.
* The destination to write decompressed content to.
* @return The number of bytes transferred. * @return The number of bytes transferred.
* @throws IOException * @throws IOException
* @since 1.1.1 * @since 1.1.1
*/ */
public long transferTo(OutputStream os) throws IOException { public long transferTo(OutputStream os)
throws IOException
{
if (os == null) { if (os == null) {
throw new IllegalArgumentException("os is null"); throw new IllegalArgumentException("os is null");
} }
@ -291,21 +305,22 @@ public final class SnappyFramedInputStream extends InputStream implements
* Transfers the entire content of this {@link ReadableByteChannel} to * Transfers the entire content of this {@link ReadableByteChannel} to
* <i>wbc</i>. This potentially limits the amount of buffering required to * <i>wbc</i>. This potentially limits the amount of buffering required to
* decompress content. * decompress content.
* * <p/>
* <p> * <p>
* Unlike {@link #read(ByteBuffer)}, this method does not need to be called * Unlike {@link #read(ByteBuffer)}, this method does not need to be called
* multiple times. A single call will transfer all available content. Any * multiple times. A single call will transfer all available content. Any
* calls after the source has been exhausted will result in a return value * calls after the source has been exhausted will result in a return value
* of {@code 0}. * of {@code 0}.
* </p> * </p>
* *
* @param wbc * @param wbc The destination to write decompressed content to.
* The destination to write decompressed content to.
* @return The number of bytes transferred. * @return The number of bytes transferred.
* @throws IOException * @throws IOException
* @since 1.1.1 * @since 1.1.1
*/ */
public long transferTo(WritableByteChannel wbc) throws IOException { public long transferTo(WritableByteChannel wbc)
throws IOException
{
if (wbc == null) { if (wbc == null) {
throw new IllegalArgumentException("wbc is null"); throw new IllegalArgumentException("wbc is null");
} }
@ -335,10 +350,13 @@ public final class SnappyFramedInputStream extends InputStream implements
} }
@Override @Override
public void close() throws IOException { public void close()
throws IOException
{
try { try {
rbc.close(); rbc.close();
} finally { }
finally {
if (!closed) { if (!closed) {
closed = true; closed = true;
} }
@ -346,18 +364,20 @@ public final class SnappyFramedInputStream extends InputStream implements
if (input != null) { if (input != null) {
releaseDirectByteBuffer(input); releaseDirectByteBuffer(input);
} }
if (uncompressedDirect != null) { if (uncompressedDirect != null) {
releaseDirectByteBuffer(uncompressedDirect); releaseDirectByteBuffer(uncompressedDirect);
} }
} }
} }
static enum FrameAction { static enum FrameAction
{
RAW, SKIP, UNCOMPRESS; RAW, SKIP, UNCOMPRESS;
} }
public static final class FrameMetaData { public static final class FrameMetaData
{
final int length; final int length;
final FrameAction frameAction; final FrameAction frameAction;
@ -365,14 +385,16 @@ public final class SnappyFramedInputStream extends InputStream implements
* @param frameAction * @param frameAction
* @param length * @param length
*/ */
public FrameMetaData(FrameAction frameAction, int length) { public FrameMetaData(FrameAction frameAction, int length)
{
super(); super();
this.frameAction = frameAction; this.frameAction = frameAction;
this.length = length; this.length = length;
} }
} }
public static final class FrameData { public static final class FrameData
{
final int checkSum; final int checkSum;
final int offset; final int offset;
@ -380,14 +402,17 @@ public final class SnappyFramedInputStream extends InputStream implements
* @param checkSum * @param checkSum
* @param offset * @param offset
*/ */
public FrameData(int checkSum, int offset) { public FrameData(int checkSum, int offset)
{
super(); super();
this.checkSum = checkSum; this.checkSum = checkSum;
this.offset = offset; this.offset = offset;
} }
} }
private boolean ensureBuffer() throws IOException { private boolean ensureBuffer()
throws IOException
{
if (available() > 0) { if (available() > 0) {
return true; return true;
} }
@ -435,14 +460,15 @@ public final class SnappyFramedInputStream extends InputStream implements
.allocateDirect(uncompressedLength); .allocateDirect(uncompressedLength);
buffer = new byte[Math.max(input.capacity(), uncompressedLength)]; buffer = new byte[Math.max(input.capacity(), uncompressedLength)];
} }
uncompressedDirect.clear(); uncompressedDirect.clear();
this.valid = Snappy.uncompress(input, uncompressedDirect); this.valid = Snappy.uncompress(input, uncompressedDirect);
uncompressedDirect.get(buffer, 0, valid); uncompressedDirect.get(buffer, 0, valid);
this.position = 0; this.position = 0;
} else { }
else {
// we need to start reading at the offset // we need to start reading at the offset
input.position(frameData.offset); input.position(frameData.offset);
this.position = 0; this.position = 0;
@ -461,7 +487,9 @@ public final class SnappyFramedInputStream extends InputStream implements
return true; return true;
} }
private boolean readBlockHeader() throws IOException { private boolean readBlockHeader()
throws IOException
{
frameHeader.clear(); frameHeader.clear();
int read = readBytes(rbc, frameHeader); int read = readBytes(rbc, frameHeader);
@ -478,13 +506,13 @@ public final class SnappyFramedInputStream extends InputStream implements
} }
/** /**
*
* @param frameHeader * @param frameHeader
* @return * @return
* @throws IOException * @throws IOException
*/ */
private FrameMetaData getFrameMetaData(ByteBuffer frameHeader) private FrameMetaData getFrameMetaData(ByteBuffer frameHeader)
throws IOException { throws IOException
{
assert frameHeader.hasArray(); assert frameHeader.hasArray();
@ -537,16 +565,18 @@ public final class SnappyFramedInputStream extends InputStream implements
} }
/** /**
*
* @param content * @param content
* @return * @return
* @throws IOException * @throws IOException
*/ */
private FrameData getFrameData(ByteBuffer content) throws IOException { private FrameData getFrameData(ByteBuffer content)
throws IOException
{
return new FrameData(getCrc32c(content), 4); return new FrameData(getCrc32c(content), 4);
} }
private int getCrc32c(ByteBuffer content) { private int getCrc32c(ByteBuffer content)
{
final int position = content.position(); final int position = content.position();

View File

@ -24,12 +24,15 @@ import java.nio.channels.WritableByteChannel;
* href="http://snappy.googlecode.com/svn/trunk/framing_format.txt" * href="http://snappy.googlecode.com/svn/trunk/framing_format.txt"
* >x-snappy-framed</a> as an {@link OutputStream} and * >x-snappy-framed</a> as an {@link OutputStream} and
* {@link WritableByteChannel}. * {@link WritableByteChannel}.
* *
* @author Brett Okken * @author Brett Okken
* @since 1.1.0 * @since 1.1.0
*/ */
public final class SnappyFramedOutputStream extends OutputStream implements public final class SnappyFramedOutputStream
WritableByteChannel { extends OutputStream
implements
WritableByteChannel
{
/** /**
* The x-snappy-framed specification allows for a chunk size up to * The x-snappy-framed specification allows for a chunk size up to
@ -37,7 +40,7 @@ public final class SnappyFramedOutputStream extends OutputStream implements
* <p> * <p>
* <code> * <code>
* We place an additional restriction that the uncompressed data in a chunk * We place an additional restriction that the uncompressed data in a chunk
* must be no longer than 65536 bytes. This allows consumers to easily use * must be no longer than 65536 bytes. This allows consumers to easily use
* small fixed-size buffers. * small fixed-size buffers.
* </code> * </code>
* </p> * </p>
@ -69,67 +72,68 @@ public final class SnappyFramedOutputStream extends OutputStream implements
/** /**
* Creates a new {@link SnappyFramedOutputStream} using the {@link #DEFAULT_BLOCK_SIZE} * Creates a new {@link SnappyFramedOutputStream} using the {@link #DEFAULT_BLOCK_SIZE}
* and {@link #DEFAULT_MIN_COMPRESSION_RATIO}. * and {@link #DEFAULT_MIN_COMPRESSION_RATIO}.
* @param out *
* The underlying {@link OutputStream} to write to. Must not be * @param out The underlying {@link OutputStream} to write to. Must not be
* {@code null}. * {@code null}.
* @throws IOException * @throws IOException
*/ */
public SnappyFramedOutputStream(OutputStream out) throws IOException { public SnappyFramedOutputStream(OutputStream out)
throws IOException
{
this(out, DEFAULT_BLOCK_SIZE, DEFAULT_MIN_COMPRESSION_RATIO); this(out, DEFAULT_BLOCK_SIZE, DEFAULT_MIN_COMPRESSION_RATIO);
} }
/** /**
* Creates a new {@link SnappyFramedOutputStream} instance. * Creates a new {@link SnappyFramedOutputStream} instance.
* *
* @param out * @param out The underlying {@link OutputStream} to write to. Must not be
* The underlying {@link OutputStream} to write to. Must not be * {@code null}.
* {@code null}. * @param blockSize The block size (of raw data) to compress before writing frames
* @param blockSize * to <i>out</i>. Must be in (0, 65536].
* The block size (of raw data) to compress before writing frames * @param minCompressionRatio Defines the minimum compression ratio (
* to <i>out</i>. Must be in (0, 65536]. * {@code compressedLength / rawLength}) that must be achieved to
* @param minCompressionRatio * write the compressed data. This must be in (0, 1.0].
* Defines the minimum compression ratio (
* {@code compressedLength / rawLength}) that must be achieved to
* write the compressed data. This must be in (0, 1.0].
* @throws IOException * @throws IOException
*/ */
public SnappyFramedOutputStream(OutputStream out, int blockSize, public SnappyFramedOutputStream(OutputStream out, int blockSize,
double minCompressionRatio) throws IOException { double minCompressionRatio)
throws IOException
{
this(Channels.newChannel(out), blockSize, minCompressionRatio); this(Channels.newChannel(out), blockSize, minCompressionRatio);
} }
/** /**
* Creates a new {@link SnappyFramedOutputStream} using the * Creates a new {@link SnappyFramedOutputStream} using the
* {@link #DEFAULT_BLOCK_SIZE} and {@link #DEFAULT_MIN_COMPRESSION_RATIO}. * {@link #DEFAULT_BLOCK_SIZE} and {@link #DEFAULT_MIN_COMPRESSION_RATIO}.
* *
* @param out * @param out The underlying {@link WritableByteChannel} to write to. Must
* The underlying {@link WritableByteChannel} to write to. Must * not be {@code null}.
* not be {@code null}.
* @since 1.1.1
* @throws IOException * @throws IOException
* @since 1.1.1
*/ */
public SnappyFramedOutputStream(WritableByteChannel out) throws IOException { public SnappyFramedOutputStream(WritableByteChannel out)
throws IOException
{
this(out, DEFAULT_BLOCK_SIZE, DEFAULT_MIN_COMPRESSION_RATIO); this(out, DEFAULT_BLOCK_SIZE, DEFAULT_MIN_COMPRESSION_RATIO);
} }
/** /**
* Creates a new {@link SnappyFramedOutputStream} instance. * Creates a new {@link SnappyFramedOutputStream} instance.
* *
* @param out * @param out The underlying {@link WritableByteChannel} to write to. Must
* The underlying {@link WritableByteChannel} to write to. Must * not be {@code null}.
* not be {@code null}. * @param blockSize The block size (of raw data) to compress before writing frames
* @param blockSize * to <i>out</i>. Must be in (0, 65536].
* The block size (of raw data) to compress before writing frames * @param minCompressionRatio Defines the minimum compression ratio (
* to <i>out</i>. Must be in (0, 65536]. * {@code compressedLength / rawLength}) that must be achieved to
* @param minCompressionRatio * write the compressed data. This must be in (0, 1.0].
* Defines the minimum compression ratio (
* {@code compressedLength / rawLength}) that must be achieved to
* write the compressed data. This must be in (0, 1.0].
* @since 1.1.1
* @throws IOException * @throws IOException
* @since 1.1.1
*/ */
public SnappyFramedOutputStream(WritableByteChannel out, int blockSize, public SnappyFramedOutputStream(WritableByteChannel out, int blockSize,
double minCompressionRatio) throws IOException { double minCompressionRatio)
throws IOException
{
if (out == null) { if (out == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
@ -157,12 +161,13 @@ public final class SnappyFramedOutputStream extends OutputStream implements
/** /**
* Writes the implementation specific header or "marker bytes" to * Writes the implementation specific header or "marker bytes" to
* <i>out</i>. * <i>out</i>.
* *
* @param out * @param out The underlying {@link OutputStream}.
* The underlying {@link OutputStream}.
* @throws IOException * @throws IOException
*/ */
private void writeHeader(WritableByteChannel out) throws IOException { private void writeHeader(WritableByteChannel out)
throws IOException
{
out.write(ByteBuffer.wrap(HEADER_BYTES)); out.write(ByteBuffer.wrap(HEADER_BYTES));
} }
@ -170,12 +175,15 @@ public final class SnappyFramedOutputStream extends OutputStream implements
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public boolean isOpen() { public boolean isOpen()
{
return !closed; return !closed;
} }
@Override @Override
public void write(int b) throws IOException { public void write(int b)
throws IOException
{
if (closed) { if (closed) {
throw new IOException("Stream is closed"); throw new IOException("Stream is closed");
} }
@ -186,14 +194,17 @@ public final class SnappyFramedOutputStream extends OutputStream implements
} }
@Override @Override
public void write(byte[] input, int offset, int length) throws IOException { public void write(byte[] input, int offset, int length)
throws IOException
{
if (closed) { if (closed) {
throw new IOException("Stream is closed"); throw new IOException("Stream is closed");
} }
if (input == null) { if (input == null) {
throw new NullPointerException(); throw new NullPointerException();
} else if ((offset < 0) || (offset > input.length) || (length < 0) }
else if ((offset < 0) || (offset > input.length) || (length < 0)
|| ((offset + length) > input.length) || ((offset + length) > input.length)
|| ((offset + length) < 0)) { || ((offset + length) < 0)) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
@ -215,7 +226,9 @@ public final class SnappyFramedOutputStream extends OutputStream implements
* {@inheritDoc} * {@inheritDoc}
*/ */
@Override @Override
public int write(ByteBuffer src) throws IOException { public int write(ByteBuffer src)
throws IOException
{
if (closed) { if (closed) {
throw new ClosedChannelException(); throw new ClosedChannelException();
} }
@ -255,14 +268,15 @@ public final class SnappyFramedOutputStream extends OutputStream implements
* Transfers all the content from <i>is</i> to this {@link OutputStream}. * Transfers all the content from <i>is</i> to this {@link OutputStream}.
* This potentially limits the amount of buffering required to compress * This potentially limits the amount of buffering required to compress
* content. * content.
* *
* @param is * @param is The source of data to compress.
* The source of data to compress.
* @return The number of bytes read from <i>is</i>. * @return The number of bytes read from <i>is</i>.
* @throws IOException * @throws IOException
* @since 1.1.1 * @since 1.1.1
*/ */
public long transferFrom(InputStream is) throws IOException { public long transferFrom(InputStream is)
throws IOException
{
if (closed) { if (closed) {
throw new ClosedChannelException(); throw new ClosedChannelException();
} }
@ -299,14 +313,15 @@ public final class SnappyFramedOutputStream extends OutputStream implements
* Transfers all the content from <i>rbc</i> to this * Transfers all the content from <i>rbc</i> to this
* {@link WritableByteChannel}. This potentially limits the amount of * {@link WritableByteChannel}. This potentially limits the amount of
* buffering required to compress content. * buffering required to compress content.
* *
* @param rbc * @param rbc The source of data to compress.
* The source of data to compress.
* @return The number of bytes read from <i>rbc</i>. * @return The number of bytes read from <i>rbc</i>.
* @throws IOException * @throws IOException
* @since 1.1.1 * @since 1.1.1
*/ */
public long transferFrom(ReadableByteChannel rbc) throws IOException { public long transferFrom(ReadableByteChannel rbc)
throws IOException
{
if (closed) { if (closed) {
throw new ClosedChannelException(); throw new ClosedChannelException();
} }
@ -333,7 +348,9 @@ public final class SnappyFramedOutputStream extends OutputStream implements
} }
@Override @Override
public final void flush() throws IOException { public final void flush()
throws IOException
{
if (closed) { if (closed) {
throw new IOException("Stream is closed"); throw new IOException("Stream is closed");
} }
@ -341,16 +358,19 @@ public final class SnappyFramedOutputStream extends OutputStream implements
} }
@Override @Override
public final void close() throws IOException { public final void close()
throws IOException
{
if (closed) { if (closed) {
return; return;
} }
try { try {
flush(); flush();
out.close(); out.close();
} finally { }
finally {
closed = true; closed = true;
releaseDirectByteBuffer(directInputBuffer); releaseDirectByteBuffer(directInputBuffer);
releaseDirectByteBuffer(outputBuffer); releaseDirectByteBuffer(outputBuffer);
} }
@ -359,10 +379,12 @@ public final class SnappyFramedOutputStream extends OutputStream implements
/** /**
* Compresses and writes out any buffered data. This does nothing if there * Compresses and writes out any buffered data. This does nothing if there
* is no currently buffered data. * is no currently buffered data.
* *
* @throws IOException * @throws IOException
*/ */
private void flushBuffer() throws IOException { private void flushBuffer()
throws IOException
{
if (buffer.position() > 0) { if (buffer.position() > 0) {
buffer.flip(); buffer.flip();
writeCompressed(buffer); writeCompressed(buffer);
@ -375,12 +397,13 @@ public final class SnappyFramedOutputStream extends OutputStream implements
* the data, determines if the compression ratio is acceptable and calls * the data, determines if the compression ratio is acceptable and calls
* {@link #writeBlock(java.nio.channels.WritableByteChannel, java.nio.ByteBuffer, boolean, int)} to * {@link #writeBlock(java.nio.channels.WritableByteChannel, java.nio.ByteBuffer, boolean, int)} to
* actually write the frame. * actually write the frame.
* *
* @param buffer * @param buffer
* @throws IOException * @throws IOException
*/ */
private void writeCompressed(ByteBuffer buffer) throws IOException { private void writeCompressed(ByteBuffer buffer)
throws IOException
{
final byte[] input = buffer.array(); final byte[] input = buffer.array();
final int length = buffer.remaining(); final int length = buffer.remaining();
@ -401,7 +424,8 @@ public final class SnappyFramedOutputStream extends OutputStream implements
// minCompressonRatio // minCompressonRatio
if (((double) compressedLength / (double) length) <= minCompressionRatio) { if (((double) compressedLength / (double) length) <= minCompressionRatio) {
writeBlock(out, outputBuffer, true, crc32c); writeBlock(out, outputBuffer, true, crc32c);
} else { }
else {
// otherwise use the uncompressed data. // otherwise use the uncompressed data.
buffer.flip(); buffer.flip();
writeBlock(out, buffer, false, crc32c); writeBlock(out, buffer, false, crc32c);
@ -410,21 +434,19 @@ public final class SnappyFramedOutputStream extends OutputStream implements
/** /**
* Write a frame (block) to <i>out</i>. * Write a frame (block) to <i>out</i>.
* *
* @param out * @param out The {@link OutputStream} to write to.
* The {@link OutputStream} to write to. * @param data The data to write.
* @param data * @param compressed Indicates if <i>data</i> is the compressed or raw content.
* The data to write. * This is based on whether the compression ratio desired is
* @param compressed * reached.
* Indicates if <i>data</i> is the compressed or raw content. * @param crc32c The calculated checksum.
* This is based on whether the compression ratio desired is
* reached.
* @param crc32c
* The calculated checksum.
* @throws IOException * @throws IOException
*/ */
private void writeBlock(final WritableByteChannel out, ByteBuffer data, private void writeBlock(final WritableByteChannel out, ByteBuffer data,
boolean compressed, int crc32c) throws IOException { boolean compressed, int crc32c)
throws IOException
{
headerBuffer.clear(); headerBuffer.clear();
headerBuffer.put((byte) (compressed ? COMPRESSED_DATA_FLAG headerBuffer.put((byte) (compressed ? COMPRESSED_DATA_FLAG

View File

@ -5,19 +5,22 @@ import java.io.IOException;
/** /**
* Enhanced IOException with SnappyErrorCode * Enhanced IOException with SnappyErrorCode
*/ */
public class SnappyIOException extends IOException { public class SnappyIOException
extends IOException
{
private final SnappyErrorCode errorCode; private final SnappyErrorCode errorCode;
public SnappyIOException(SnappyErrorCode errorCode, String message) { public SnappyIOException(SnappyErrorCode errorCode, String message)
{
super(message); super(message);
this.errorCode = errorCode; this.errorCode = errorCode;
} }
@Override @Override
public String getMessage() { public String getMessage()
{
return String.format("[%s] %s", errorCode.name(), super.getMessage()); return String.format("[%s] %s", errorCode.name(), super.getMessage());
} }
public SnappyErrorCode getErrorCode() { return errorCode; } public SnappyErrorCode getErrorCode() { return errorCode; }
} }

View File

@ -30,30 +30,31 @@ import java.io.InputStream;
/** /**
* A stream filter for reading data compressed by {@link SnappyOutputStream}. * A stream filter for reading data compressed by {@link SnappyOutputStream}.
* *
*
* @author leo * @author leo
*
*/ */
public class SnappyInputStream extends InputStream public class SnappyInputStream
extends InputStream
{ {
private boolean finishedReading = false; private boolean finishedReading = false;
protected final InputStream in; protected final InputStream in;
private byte[] compressed; private byte[] compressed;
private byte[] uncompressed; private byte[] uncompressed;
private int uncompressedCursor = 0; private int uncompressedCursor = 0;
private int uncompressedLimit = 0; private int uncompressedLimit = 0;
private byte[] chunkSizeBuf = new byte[4]; private byte[] header = new byte[SnappyCodec.headerSize()];
/** /**
* Create a filter for reading compressed data as a uncompressed stream * Create a filter for reading compressed data as a uncompressed stream
* *
* @param input * @param input
* @throws IOException * @throws IOException
*/ */
public SnappyInputStream(InputStream input) throws IOException { public SnappyInputStream(InputStream input)
throws IOException
{
this.in = input; this.in = input;
readHeader(); readHeader();
} }
@ -65,34 +66,44 @@ public class SnappyInputStream extends InputStream
* @see java.io.InputStream#close() * @see java.io.InputStream#close()
*/ */
@Override @Override
public void close() throws IOException { public void close()
throws IOException
{
compressed = null; compressed = null;
uncompressed = null; uncompressed = null;
if (in != null) if (in != null) {
in.close(); in.close();
}
} }
protected void readHeader() throws IOException { protected void readHeader()
byte[] header = new byte[SnappyCodec.headerSize()]; throws IOException
{
int readBytes = 0; int readBytes = 0;
while (readBytes < header.length) { while (readBytes < header.length) {
int ret = in.read(header, readBytes, header.length - readBytes); int ret = in.read(header, readBytes, header.length - readBytes);
if (ret == -1) if (ret == -1) {
break; break;
}
readBytes += ret; readBytes += ret;
} }
// Quick test of the header // Quick test of the header
if(readBytes == 0) { if (readBytes == 0) {
// Snappy produces at least 1-byte result. So the empty input is not a valid input // Snappy produces at least 1-byte result. So the empty input is not a valid input
throw new SnappyIOException(SnappyErrorCode.EMPTY_INPUT, "Cannot decompress empty stream"); throw new SnappyIOException(SnappyErrorCode.EMPTY_INPUT, "Cannot decompress empty stream");
} }
if (readBytes < header.length || header[0] != SnappyCodec.MAGIC_HEADER[0]) { if (readBytes < header.length || header[0] != SnappyCodec.MAGIC_HEADER[0]) {
// do the default uncompression // do the default uncompression
// (probably) compressed by Snappy.compress(byte[])
readFully(header, readBytes); readFully(header, readBytes);
return; return;
} }
}
private static boolean isValidHeader(byte[] header)
throws IOException
{
SnappyCodec codec = SnappyCodec.readHeader(new ByteArrayInputStream(header)); SnappyCodec codec = SnappyCodec.readHeader(new ByteArrayInputStream(header));
if (codec.isValidMagicHeader()) { if (codec.isValidMagicHeader()) {
// The input data is compressed by SnappyOutputStream // The input data is compressed by SnappyOutputStream
@ -101,16 +112,17 @@ public class SnappyInputStream extends InputStream
"Compressed with an incompatible codec version %d. At least version %d is required", "Compressed with an incompatible codec version %d. At least version %d is required",
codec.version, SnappyCodec.MINIMUM_COMPATIBLE_VERSION)); codec.version, SnappyCodec.MINIMUM_COMPATIBLE_VERSION));
} }
return true;
} }
else { else {
// (probably) compressed by Snappy.compress(byte[]) return false;
readFully(header, readBytes);
return;
} }
} }
protected void readFully(byte[] fragment, int fragmentLength) throws IOException { protected void readFully(byte[] fragment, int fragmentLength)
if(fragmentLength == 0) { throws IOException
{
if (fragmentLength == 0) {
finishedReading = true; finishedReading = true;
return; return;
} }
@ -118,7 +130,7 @@ public class SnappyInputStream extends InputStream
compressed = new byte[Math.max(8 * 1024, fragmentLength)]; // 8K compressed = new byte[Math.max(8 * 1024, fragmentLength)]; // 8K
System.arraycopy(fragment, 0, compressed, 0, fragmentLength); System.arraycopy(fragment, 0, compressed, 0, fragmentLength);
int cursor = fragmentLength; int cursor = fragmentLength;
for (int readBytes = 0; (readBytes = in.read(compressed, cursor, compressed.length - cursor)) != -1;) { for (int readBytes = 0; (readBytes = in.read(compressed, cursor, compressed.length - cursor)) != -1; ) {
cursor += readBytes; cursor += readBytes;
if (cursor >= compressed.length) { if (cursor >= compressed.length) {
byte[] newBuf = new byte[(compressed.length * 2)]; byte[] newBuf = new byte[(compressed.length * 2)];
@ -135,7 +147,6 @@ public class SnappyInputStream extends InputStream
Snappy.uncompress(compressed, 0, cursor, uncompressed, 0); Snappy.uncompress(compressed, 0, cursor, uncompressed, 0);
this.uncompressedCursor = 0; this.uncompressedCursor = 0;
this.uncompressedLimit = uncompressedLength; this.uncompressedLimit = uncompressedLength;
} }
/** /**
@ -146,26 +157,31 @@ public class SnappyInputStream extends InputStream
* @see java.io.InputStream#read(byte[], int, int) * @see java.io.InputStream#read(byte[], int, int)
*/ */
@Override @Override
public int read(byte[] b, int off, int len) throws IOException { public int read(byte[] b, int off, int len)
throws IOException
{
return rawRead(b, off, len); return rawRead(b, off, len);
} }
/** /**
* Read uncompressed data into the specified array * Read uncompressed data into the specified array
* *
* @param array * @param array
* @param byteOffset * @param byteOffset
* @param byteLength * @param byteLength
* @return written bytes * @return written bytes
* @throws IOException * @throws IOException
*/ */
public int rawRead(Object array, int byteOffset, int byteLength) throws IOException { public int rawRead(Object array, int byteOffset, int byteLength)
throws IOException
{
int writtenBytes = 0; int writtenBytes = 0;
for (; writtenBytes < byteLength;) { for (; writtenBytes < byteLength; ) {
if (uncompressedCursor >= uncompressedLimit) { if (uncompressedCursor >= uncompressedLimit) {
if (hasNextChunk()) if (hasNextChunk()) {
continue; continue;
}
else { else {
return writtenBytes == 0 ? -1 : writtenBytes; return writtenBytes == 0 ? -1 : writtenBytes;
} }
@ -181,166 +197,209 @@ public class SnappyInputStream extends InputStream
/** /**
* Read long array from the stream * Read long array from the stream
* *
* @param d * @param d input
* input * @param off offset
* @param off * @param len the number of long elements to read
* offset
* @param len
* the number of long elements to read
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(long[] d, int off, int len) throws IOException { public int read(long[] d, int off, int len)
throws IOException
{
return rawRead(d, off * 8, len * 8); return rawRead(d, off * 8, len * 8);
} }
/** /**
* Read long array from the stream * Read long array from the stream
* *
* @param d * @param d
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(long[] d) throws IOException { public int read(long[] d)
throws IOException
{
return read(d, 0, d.length); return read(d, 0, d.length);
} }
/** /**
* Read double array from the stream * Read double array from the stream
* *
* @param d * @param d input
* input * @param off offset
* @param off * @param len the number of double elements to read
* offset
* @param len
* the number of double elements to read
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(double[] d, int off, int len) throws IOException { public int read(double[] d, int off, int len)
throws IOException
{
return rawRead(d, off * 8, len * 8); return rawRead(d, off * 8, len * 8);
} }
/** /**
* Read double array from the stream * Read double array from the stream
* *
* @param d * @param d
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(double[] d) throws IOException { public int read(double[] d)
throws IOException
{
return read(d, 0, d.length); return read(d, 0, d.length);
} }
/** /**
* Read int array from the stream * Read int array from the stream
* *
* @param d * @param d
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(int[] d) throws IOException { public int read(int[] d)
throws IOException
{
return read(d, 0, d.length); return read(d, 0, d.length);
} }
/** /**
* Read int array from the stream * Read int array from the stream
* *
* @param d * @param d input
* input * @param off offset
* @param off * @param len the number of int elements to read
* offset
* @param len
* the number of int elements to read
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(int[] d, int off, int len) throws IOException { public int read(int[] d, int off, int len)
throws IOException
{
return rawRead(d, off * 4, len * 4); return rawRead(d, off * 4, len * 4);
} }
/** /**
* Read float array from the stream * Read float array from the stream
* *
* @param d * @param d input
* input * @param off offset
* @param off * @param len the number of float elements to read
* offset
* @param len
* the number of float elements to read
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(float[] d, int off, int len) throws IOException { public int read(float[] d, int off, int len)
throws IOException
{
return rawRead(d, off * 4, len * 4); return rawRead(d, off * 4, len * 4);
} }
/** /**
* Read float array from the stream * Read float array from the stream
* *
* @param d * @param d
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(float[] d) throws IOException { public int read(float[] d)
throws IOException
{
return read(d, 0, d.length); return read(d, 0, d.length);
} }
/** /**
* Read short array from the stream * Read short array from the stream
* *
* @param d * @param d input
* input * @param off offset
* @param off * @param len the number of short elements to read
* offset
* @param len
* the number of short elements to read
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(short[] d, int off, int len) throws IOException { public int read(short[] d, int off, int len)
throws IOException
{
return rawRead(d, off * 2, len * 2); return rawRead(d, off * 2, len * 2);
} }
/** /**
* Read short array from the stream * Read short array from the stream
* *
* @param d * @param d
* @return the total number of bytes read into the buffer, or -1 if there is * @return the total number of bytes read into the buffer, or -1 if there is
* no more data because the end of the stream has been reached. * no more data because the end of the stream has been reached.
* @throws IOException * @throws IOException
*/ */
public int read(short[] d) throws IOException { public int read(short[] d)
throws IOException
{
return read(d, 0, d.length); return read(d, 0, d.length);
} }
protected boolean hasNextChunk() throws IOException { /**
if (finishedReading) * Read next len bytes
*
* @param dest
* @param offset
* @param len
* @return read bytes
*/
private int readNext(byte[] dest, int offset, int len)
throws IOException
{
int readBytes = 0;
while (readBytes < len) {
int ret = in.read(dest, readBytes + offset, len - readBytes);
if (ret == -1) {
finishedReading = true;
return readBytes;
}
readBytes += ret;
}
return readBytes;
}
protected boolean hasNextChunk()
throws IOException
{
if (finishedReading) {
return false; return false;
}
uncompressedCursor = 0; uncompressedCursor = 0;
uncompressedLimit = 0; uncompressedLimit = 0;
int readBytes = 0; int readBytes = readNext(header, 0, 4);
while (readBytes < 4) { if (readBytes < 4) {
int ret = in.read(chunkSizeBuf, readBytes, 4 - readBytes); return false;
if (ret == -1) { }
finishedReading = true;
int chunkSize = SnappyOutputStream.readInt(header, 0);
if (chunkSize == SnappyCodec.MAGIC_HEADER_HEAD) {
// Concatenated data
int remainingHeaderSize = SnappyCodec.headerSize() - 4;
readBytes = readNext(header, 4, remainingHeaderSize);
if(readBytes < remainingHeaderSize) {
throw new SnappyIOException(SnappyErrorCode.FAILED_TO_UNCOMPRESS, String.format("Insufficient header size in a concatenated block"));
}
if (isValidHeader(header)) {
return hasNextChunk();
}
else {
return false; return false;
} }
readBytes += ret;
} }
int chunkSize = SnappyOutputStream.readInt(chunkSizeBuf, 0);
// extend the compressed data buffer size // extend the compressed data buffer size
if (compressed == null || chunkSize > compressed.length) { if (compressed == null || chunkSize > compressed.length) {
compressed = new byte[chunkSize]; compressed = new byte[chunkSize];
@ -348,8 +407,9 @@ public class SnappyInputStream extends InputStream
readBytes = 0; readBytes = 0;
while (readBytes < chunkSize) { while (readBytes < chunkSize) {
int ret = in.read(compressed, readBytes, chunkSize - readBytes); int ret = in.read(compressed, readBytes, chunkSize - readBytes);
if (ret == -1) if (ret == -1) {
break; break;
}
readBytes += ret; readBytes += ret;
} }
if (readBytes < chunkSize) { if (readBytes < chunkSize) {
@ -379,15 +439,19 @@ public class SnappyInputStream extends InputStream
* @see java.io.InputStream#read() * @see java.io.InputStream#read()
*/ */
@Override @Override
public int read() throws IOException { public int read()
throws IOException
{
if (uncompressedCursor < uncompressedLimit) { if (uncompressedCursor < uncompressedLimit) {
return uncompressed[uncompressedCursor++] & 0xFF; return uncompressed[uncompressedCursor++] & 0xFF;
} }
else { else {
if (hasNextChunk()) if (hasNextChunk()) {
return read(); return read();
else }
else {
return -1; return -1;
}
} }
} }
@ -395,7 +459,9 @@ public class SnappyInputStream extends InputStream
* @see java.io.InputStream#available() * @see java.io.InputStream#available()
*/ */
@Override @Override
public int available() throws IOException { public int available()
throws IOException
{
if (uncompressedCursor < uncompressedLimit) { if (uncompressedCursor < uncompressedLimit) {
return uncompressedLimit - uncompressedCursor; return uncompressedLimit - uncompressedCursor;
} }

View File

@ -36,10 +36,10 @@ import java.util.UUID;
* user platform (<i>os.name</i> and <i>os.arch</i>). The natively compiled * user platform (<i>os.name</i> and <i>os.arch</i>). The natively compiled
* libraries bundled to snappy-java contain the codes of the original snappy and * libraries bundled to snappy-java contain the codes of the original snappy and
* JNI programs to access Snappy. * JNI programs to access Snappy.
* * <p/>
* In default, no configuration is required to use snappy-java, but you can load * In default, no configuration is required to use snappy-java, but you can load
* your own native library created by 'make native' command. * your own native library created by 'make native' command.
* * <p/>
* This SnappyLoader searches for native libraries (snappyjava.dll, * This SnappyLoader searches for native libraries (snappyjava.dll,
* libsnappy.so, etc.) in the following order: * libsnappy.so, etc.) in the following order:
* <ol> * <ol>
@ -53,70 +53,76 @@ import java.util.UUID;
* <i>org.xerial.snappy.tempdir</i> is set, use this folder instead of * <i>org.xerial.snappy.tempdir</i> is set, use this folder instead of
* <i>java.io.tempdir</i>. * <i>java.io.tempdir</i>.
* </ol> * </ol>
* * <p/>
* <p> * <p>
* If you do not want to use folder <i>java.io.tempdir</i>, set the System * If you do not want to use folder <i>java.io.tempdir</i>, set the System
* property <i>org.xerial.snappy.tempdir</i>. For example, to use * property <i>org.xerial.snappy.tempdir</i>. For example, to use
* <i>/tmp/leo</i> as a temporary folder to copy native libraries, use -D option * <i>/tmp/leo</i> as a temporary folder to copy native libraries, use -D option
* of JVM: * of JVM:
* * <p/>
* <pre> * <pre>
* <code> * <code>
* java -Dorg.xerial.snappy.tempdir="/tmp/leo" ... * java -Dorg.xerial.snappy.tempdir="/tmp/leo" ...
* </code> * </code>
* </pre> * </pre>
* * <p/>
* </p> * </p>
* *
* @author leo * @author leo
*
*/ */
public class SnappyLoader public class SnappyLoader
{ {
public static final String SNAPPY_SYSTEM_PROPERTIES_FILE = "org-xerial-snappy.properties"; public static final String SNAPPY_SYSTEM_PROPERTIES_FILE = "org-xerial-snappy.properties";
public static final String KEY_SNAPPY_LIB_PATH = "org.xerial.snappy.lib.path"; public static final String KEY_SNAPPY_LIB_PATH = "org.xerial.snappy.lib.path";
public static final String KEY_SNAPPY_LIB_NAME = "org.xerial.snappy.lib.name"; public static final String KEY_SNAPPY_LIB_NAME = "org.xerial.snappy.lib.name";
public static final String KEY_SNAPPY_TEMPDIR = "org.xerial.snappy.tempdir"; public static final String KEY_SNAPPY_TEMPDIR = "org.xerial.snappy.tempdir";
public static final String KEY_SNAPPY_USE_SYSTEMLIB = "org.xerial.snappy.use.systemlib"; public static final String KEY_SNAPPY_USE_SYSTEMLIB = "org.xerial.snappy.use.systemlib";
public static final String KEY_SNAPPY_DISABLE_BUNDLED_LIBS = "org.xerial.snappy.disable.bundled.libs"; // Depreciated, but preserved for backward compatibility public static final String KEY_SNAPPY_DISABLE_BUNDLED_LIBS = "org.xerial.snappy.disable.bundled.libs"; // Depreciated, but preserved for backward compatibility
private static volatile boolean isLoaded = false; private static volatile boolean isLoaded = false;
private static volatile SnappyNative api = null; private static volatile SnappyNative api = null;
private static File nativeLibFile = null; private static File nativeLibFile = null;
static void cleanUpExtractedNativeLib() { static void cleanUpExtractedNativeLib()
if(nativeLibFile != null && nativeLibFile.exists()) {
nativeLibFile.delete(); if (nativeLibFile != null && nativeLibFile.exists()) {
boolean deleted = nativeLibFile.delete();
if (!deleted) {
// Deleting native lib has failed, but it's not serious so simply ignore it here
}
}
} }
/** /**
* Set the api instance. * Set the api instance.
* *
* @param nativeCode * @param nativeCode
*/ */
static synchronized void setApi(SnappyNative nativeCode) static synchronized void setApi(SnappyNative nativeCode)
{ {
api = nativeCode; api = nativeCode;
} }
/** /**
* load system properties when configuration file of the name * load system properties when configuration file of the name
* {@link #SNAPPY_SYSTEM_PROPERTIES_FILE} is found * {@link #SNAPPY_SYSTEM_PROPERTIES_FILE} is found
*/ */
private static void loadSnappySystemProperties() { private static void loadSnappySystemProperties()
{
try { try {
InputStream is = Thread.currentThread().getContextClassLoader() InputStream is = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(SNAPPY_SYSTEM_PROPERTIES_FILE); .getResourceAsStream(SNAPPY_SYSTEM_PROPERTIES_FILE);
if (is == null) if (is == null) {
return; // no configuration file is found return; // no configuration file is found
}
// Load property file // Load property file
Properties props = new Properties(); Properties props = new Properties();
props.load(is); props.load(is);
is.close(); is.close();
Enumeration< ? > names = props.propertyNames(); Enumeration<?> names = props.propertyNames();
while (names.hasMoreElements()) { while (names.hasMoreElements()) {
String name = (String) names.nextElement(); String name = (String) names.nextElement();
if (name.startsWith("org.xerial.snappy.")) { if (name.startsWith("org.xerial.snappy.")) {
@ -138,8 +144,9 @@ public class SnappyLoader
static synchronized SnappyNative load() static synchronized SnappyNative load()
{ {
if (api != null) if (api != null) {
return api; return api;
}
try { try {
loadNativeLibrary(); loadNativeLibrary();
@ -158,7 +165,8 @@ public class SnappyLoader
/** /**
* Load a native library of snappy-java * Load a native library of snappy-java
*/ */
private static void loadNativeLibrary() { private static void loadNativeLibrary()
{
nativeLibFile = findNativeLibrary(); nativeLibFile = findNativeLibrary();
if (nativeLibFile != null) { if (nativeLibFile != null) {
@ -171,34 +179,38 @@ public class SnappyLoader
} }
} }
private static boolean contentsEquals(InputStream in1, InputStream in2)
private static boolean contentsEquals(InputStream in1, InputStream in2) throws IOException { throws IOException
if(!(in1 instanceof BufferedInputStream)) { {
in1 = new BufferedInputStream(in1); if (!(in1 instanceof BufferedInputStream)) {
in1 = new BufferedInputStream(in1);
} }
if(!(in2 instanceof BufferedInputStream)) { if (!(in2 instanceof BufferedInputStream)) {
in2 = new BufferedInputStream(in2); in2 = new BufferedInputStream(in2);
} }
int ch = in1.read(); int ch = in1.read();
while(ch != -1) { while (ch != -1) {
int ch2 = in2.read(); int ch2 = in2.read();
if(ch != ch2) if (ch != ch2) {
return false; return false;
}
ch = in1.read(); ch = in1.read();
} }
int ch2 = in2.read(); int ch2 = in2.read();
return ch2 == -1; return ch2 == -1;
} }
/** /**
* Extract the specified library file to the target folder * Extract the specified library file to the target folder
* *
* @param libFolderForCurrentOS * @param libFolderForCurrentOS
* @param libraryFileName * @param libraryFileName
* @param targetFolder * @param targetFolder
* @return * @return
*/ */
private static File extractLibraryFile(String libFolderForCurrentOS, String libraryFileName, String targetFolder) { private static File extractLibraryFile(String libFolderForCurrentOS, String libraryFileName, String targetFolder)
{
String nativeLibraryFilePath = libFolderForCurrentOS + "/" + libraryFileName; String nativeLibraryFilePath = libFolderForCurrentOS + "/" + libraryFileName;
// Attach UUID to the native library file to ensure multiple class loaders can read the libsnappy-java multiple times. // Attach UUID to the native library file to ensure multiple class loaders can read the libsnappy-java multiple times.
@ -208,44 +220,61 @@ public class SnappyLoader
try { try {
// Extract a native library file into the target directory // Extract a native library file into the target directory
InputStream reader = SnappyLoader.class.getResourceAsStream(nativeLibraryFilePath); InputStream reader = null;
FileOutputStream writer = new FileOutputStream(extractedLibFile); FileOutputStream writer = null;
try { try {
byte[] buffer = new byte[8192]; reader = SnappyLoader.class.getResourceAsStream(nativeLibraryFilePath);
int bytesRead = 0; try {
while ((bytesRead = reader.read(buffer)) != -1) { writer = new FileOutputStream(extractedLibFile);
writer.write(buffer, 0, bytesRead);
byte[] buffer = new byte[8192];
int bytesRead = 0;
while ((bytesRead = reader.read(buffer)) != -1) {
writer.write(buffer, 0, bytesRead);
}
}
finally {
if (writer != null) {
writer.close();
}
} }
} }
finally { finally {
if (reader != null) {
reader.close();
}
// Delete the extracted lib file on JVM exit. // Delete the extracted lib file on JVM exit.
extractedLibFile.deleteOnExit(); extractedLibFile.deleteOnExit();
if(writer != null)
writer.close();
if(reader != null)
reader.close();
} }
// Set executable (x) flag to enable Java to load the native library // Set executable (x) flag to enable Java to load the native library
extractedLibFile.setReadable(true); boolean success = extractedLibFile.setReadable(true) &&
extractedLibFile.setWritable(true, true); extractedLibFile.setWritable(true, true) &&
extractedLibFile.setExecutable(true); extractedLibFile.setExecutable(true);
if (!success) {
// Setting file flag may fail, but in this case another error will be thrown in later phase
}
// Check whether the contents are properly copied from the resource folder // Check whether the contents are properly copied from the resource folder
{ {
InputStream nativeIn = SnappyLoader.class.getResourceAsStream(nativeLibraryFilePath); InputStream nativeIn = null;
InputStream extractedLibIn = new FileInputStream(extractedLibFile); InputStream extractedLibIn = null;
try { try {
if(!contentsEquals(nativeIn, extractedLibIn)) nativeIn = SnappyLoader.class.getResourceAsStream(nativeLibraryFilePath);
extractedLibIn = new FileInputStream(extractedLibFile);
if (!contentsEquals(nativeIn, extractedLibIn)) {
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, String.format("Failed to write a native library file at %s", extractedLibFile)); throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, String.format("Failed to write a native library file at %s", extractedLibFile));
}
} }
finally { finally {
if(nativeIn != null) if (nativeIn != null) {
nativeIn.close(); nativeIn.close();
if(extractedLibIn != null) }
if (extractedLibIn != null) {
extractedLibIn.close(); extractedLibIn.close();
}
} }
} }
@ -257,76 +286,84 @@ public class SnappyLoader
} }
} }
static File findNativeLibrary() { static File findNativeLibrary()
{
boolean useSystemLib = Boolean.parseBoolean(System.getProperty(KEY_SNAPPY_USE_SYSTEMLIB, "false")); boolean useSystemLib = Boolean.parseBoolean(System.getProperty(KEY_SNAPPY_USE_SYSTEMLIB, "false"));
boolean disabledBundledLibs = Boolean boolean disabledBundledLibs = Boolean
.parseBoolean(System.getProperty(KEY_SNAPPY_DISABLE_BUNDLED_LIBS, "false")); .parseBoolean(System.getProperty(KEY_SNAPPY_DISABLE_BUNDLED_LIBS, "false"));
if (useSystemLib || disabledBundledLibs) if (useSystemLib || disabledBundledLibs) {
return null; // Use a pre-installed libsnappyjava return null; // Use a pre-installed libsnappyjava
}
// Try to load the library in org.xerial.snappy.lib.path */ // Try to load the library in org.xerial.snappy.lib.path */
String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH); String snappyNativeLibraryPath = System.getProperty(KEY_SNAPPY_LIB_PATH);
String snappyNativeLibraryName = System.getProperty(KEY_SNAPPY_LIB_NAME); String snappyNativeLibraryName = System.getProperty(KEY_SNAPPY_LIB_NAME);
// Resolve the library file name with a suffix (e.g., dll, .so, etc.) // Resolve the library file name with a suffix (e.g., dll, .so, etc.)
if (snappyNativeLibraryName == null) if (snappyNativeLibraryName == null) {
snappyNativeLibraryName = System.mapLibraryName("snappyjava"); snappyNativeLibraryName = System.mapLibraryName("snappyjava");
}
if (snappyNativeLibraryPath != null) { if (snappyNativeLibraryPath != null) {
File nativeLib = new File(snappyNativeLibraryPath, snappyNativeLibraryName); File nativeLib = new File(snappyNativeLibraryPath, snappyNativeLibraryName);
if (nativeLib.exists()) if (nativeLib.exists()) {
return nativeLib; return nativeLib;
}
} }
// Load an OS-dependent native library inside a jar file // Load an OS-dependent native library inside a jar file
snappyNativeLibraryPath = "/org/xerial/snappy/native/" + OSInfo.getNativeLibFolderPathForCurrentOS(); snappyNativeLibraryPath = "/org/xerial/snappy/native/" + OSInfo.getNativeLibFolderPathForCurrentOS();
boolean hasNativeLib = hasResource(snappyNativeLibraryPath + "/" + snappyNativeLibraryName); boolean hasNativeLib = hasResource(snappyNativeLibraryPath + "/" + snappyNativeLibraryName);
if(!hasNativeLib) { if (!hasNativeLib) {
if(OSInfo.getOSName().equals("Mac")) { if (OSInfo.getOSName().equals("Mac")) {
// Fix for openjdk7 for Mac // Fix for openjdk7 for Mac
String altName = "libsnappyjava.jnilib"; String altName = "libsnappyjava.jnilib";
if(hasResource(snappyNativeLibraryPath + "/" + altName)) { if (hasResource(snappyNativeLibraryPath + "/" + altName)) {
snappyNativeLibraryName = altName; snappyNativeLibraryName = altName;
hasNativeLib = true; hasNativeLib = true;
} }
} }
} }
if(!hasNativeLib) { if (!hasNativeLib) {
String errorMessage = String.format("no native library is found for os.name=%s and os.arch=%s", OSInfo.getOSName(), OSInfo.getArchName()); String errorMessage = String.format("no native library is found for os.name=%s and os.arch=%s", OSInfo.getOSName(), OSInfo.getArchName());
throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, errorMessage); throw new SnappyError(SnappyErrorCode.FAILED_TO_LOAD_NATIVE_LIBRARY, errorMessage);
} }
// Temporary folder for the native lib. Use the value of org.xerial.snappy.tempdir or java.io.tmpdir // Temporary folder for the native lib. Use the value of org.xerial.snappy.tempdir or java.io.tmpdir
String tempFolder = new File(System.getProperty(KEY_SNAPPY_TEMPDIR, File tempFolder = new File(System.getProperty(KEY_SNAPPY_TEMPDIR, System.getProperty("java.io.tmpdir")));
System.getProperty("java.io.tmpdir"))).getAbsolutePath(); if (!tempFolder.exists()) {
boolean created = tempFolder.mkdirs();
if (!created) {
// if created == false, it will fail eventually in the later part
}
}
// Extract and load a native library inside the jar file // Extract and load a native library inside the jar file
return extractLibraryFile(snappyNativeLibraryPath, snappyNativeLibraryName, tempFolder); return extractLibraryFile(snappyNativeLibraryPath, snappyNativeLibraryName, tempFolder.getAbsolutePath());
} }
private static boolean hasResource(String path)
private static boolean hasResource(String path) { {
return SnappyLoader.class.getResource(path) != null; return SnappyLoader.class.getResource(path) != null;
} }
/** /**
* Get the snappy-java version by reading pom.properties embedded in jar. * Get the snappy-java version by reading pom.properties embedded in jar.
* This version data is used as a suffix of a dll file extracted from the * This version data is used as a suffix of a dll file extracted from the
* jar. * jar.
* *
* @return the version string * @return the version string
*/ */
public static String getVersion() { public static String getVersion()
{
URL versionFile = SnappyLoader.class URL versionFile = SnappyLoader.class
.getResource("/META-INF/maven/org.xerial.snappy/snappy-java/pom.properties"); .getResource("/META-INF/maven/org.xerial.snappy/snappy-java/pom.properties");
if (versionFile == null) if (versionFile == null) {
versionFile = SnappyLoader.class.getResource("/org/xerial/snappy/VERSION"); versionFile = SnappyLoader.class.getResource("/org/xerial/snappy/VERSION");
}
String version = "unknown"; String version = "unknown";
try { try {
@ -334,8 +371,9 @@ public class SnappyLoader
Properties versionData = new Properties(); Properties versionData = new Properties();
versionData.load(versionFile.openStream()); versionData.load(versionFile.openStream());
version = versionData.getProperty("version", version); version = versionData.getProperty("version", version);
if (version.equals("unknown")) if (version.equals("unknown")) {
version = versionData.getProperty("VERSION", version); version = versionData.getProperty("VERSION", version);
}
version = version.trim().replaceAll("[^0-9M\\.]", ""); version = version.trim().replaceAll("[^0-9M\\.]", "");
} }
} }
@ -344,5 +382,4 @@ public class SnappyLoader
} }
return version; return version;
} }
} }

View File

@ -1,309 +1,309 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <snappy.h> #include <snappy.h>
#include "SnappyNative.h" #include "SnappyNative.h"
void throw_exception(JNIEnv *env, jobject self, int errorCode) void throw_exception(JNIEnv *env, jobject self, int errorCode)
{ {
jclass c = env->FindClass("org/xerial/snappy/SnappyNative"); jclass c = env->FindClass("org/xerial/snappy/SnappyNative");
if(c==0) if(c==0)
return; return;
jmethodID mth_throwex = env->GetMethodID(c, "throw_error", "(I)V"); jmethodID mth_throwex = env->GetMethodID(c, "throw_error", "(I)V");
if(mth_throwex == 0) if(mth_throwex == 0)
return; return;
env->CallVoidMethod(self, mth_throwex, (jint) errorCode); env->CallVoidMethod(self, mth_throwex, (jint) errorCode);
} }
JNIEXPORT jstring JNICALL Java_org_xerial_snappy_SnappyNative_nativeLibraryVersion JNIEXPORT jstring JNICALL Java_org_xerial_snappy_SnappyNative_nativeLibraryVersion
(JNIEnv * env, jobject self) (JNIEnv * env, jobject self)
{ {
return env->NewStringUTF("1.1.0"); return env->NewStringUTF("1.1.0");
} }
JNIEXPORT jlong JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__JJJ JNIEXPORT jlong JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__JJJ
(JNIEnv* env, jobject self, jlong srcAddr, jlong length, jlong destAddr) { (JNIEnv* env, jobject self, jlong srcAddr, jlong length, jlong destAddr) {
size_t compressedLength; size_t compressedLength;
snappy::RawCompress((char*) srcAddr, (size_t) length, (char*) destAddr, &compressedLength); snappy::RawCompress((char*) srcAddr, (size_t) length, (char*) destAddr, &compressedLength);
return (jlong) compressedLength; return (jlong) compressedLength;
} }
JNIEXPORT jlong JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__JJJ JNIEXPORT jlong JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__JJJ
(JNIEnv* env, jobject self, jlong srcAddr, jlong length, jlong destAddr) { (JNIEnv* env, jobject self, jlong srcAddr, jlong length, jlong destAddr) {
size_t uncompressedLength; size_t uncompressedLength;
snappy::GetUncompressedLength((char*) srcAddr, (size_t) length, &uncompressedLength); snappy::GetUncompressedLength((char*) srcAddr, (size_t) length, &uncompressedLength);
bool ret = snappy::RawUncompress((char*) srcAddr, (size_t) length, (char*) destAddr); bool ret = snappy::RawUncompress((char*) srcAddr, (size_t) length, (char*) destAddr);
if(!ret) { if(!ret) {
throw_exception(env, self, 5); throw_exception(env, self, 5);
return 0; return 0;
} }
return (jlong) uncompressedLength; return (jlong) uncompressedLength;
} }
/* /*
* Class: org_xerial_snappy_Snappy * Class: org_xerial_snappy_Snappy
* Method: compress * Method: compress
* Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)J * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)J
*/ */
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I
(JNIEnv* env, jobject self, jobject uncompressed, jint upos, jint ulen, jobject compressed, jint cpos) (JNIEnv* env, jobject self, jobject uncompressed, jint upos, jint ulen, jobject compressed, jint cpos)
{ {
char* uncompressedBuffer = (char*) env->GetDirectBufferAddress(uncompressed); char* uncompressedBuffer = (char*) env->GetDirectBufferAddress(uncompressed);
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
if(uncompressedBuffer == 0 || compressedBuffer == 0) { if(uncompressedBuffer == 0 || compressedBuffer == 0) {
throw_exception(env, self, 3); throw_exception(env, self, 3);
return (jint) 0; return (jint) 0;
} }
size_t compressedLength; size_t compressedLength;
snappy::RawCompress(uncompressedBuffer + upos, (size_t) ulen, compressedBuffer + cpos, &compressedLength); snappy::RawCompress(uncompressedBuffer + upos, (size_t) ulen, compressedBuffer + cpos, &compressedLength);
return (jint) compressedLength; return (jint) compressedLength;
} }
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_lang_Object_2IILjava_lang_Object_2I JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_lang_Object_2IILjava_lang_Object_2I
(JNIEnv * env, jobject self, jobject input, jint inputOffset, jint inputLen, jobject output, jint outputOffset) (JNIEnv * env, jobject self, jobject input, jint inputOffset, jint inputLen, jobject output, jint outputOffset)
{ {
char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0);
char* out = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0); char* out = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0);
if(in == 0 || out == 0) { if(in == 0 || out == 0) {
// out of memory // out of memory
if(in != 0) { if(in != 0) {
env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); env->ReleasePrimitiveArrayCritical((jarray) input, in, 0);
} }
if(out != 0) { if(out != 0) {
env->ReleasePrimitiveArrayCritical((jarray) output, out, 0); env->ReleasePrimitiveArrayCritical((jarray) output, out, 0);
} }
throw_exception(env, self, 4); throw_exception(env, self, 4);
return 0; return 0;
} }
size_t compressedLength; size_t compressedLength;
snappy::RawCompress(in + inputOffset, (size_t) inputLen, out + outputOffset, &compressedLength); snappy::RawCompress(in + inputOffset, (size_t) inputLen, out + outputOffset, &compressedLength);
env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); env->ReleasePrimitiveArrayCritical((jarray) input, in, 0);
env->ReleasePrimitiveArrayCritical((jarray) output, out, 0); env->ReleasePrimitiveArrayCritical((jarray) output, out, 0);
return (jint) compressedLength; return (jint) compressedLength;
} }
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_lang_Object_2IILjava_lang_Object_2I JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_lang_Object_2IILjava_lang_Object_2I
(JNIEnv * env, jobject self, jobject input, jint inputOffset, jint inputLength, jobject output, jint outputOffset) (JNIEnv * env, jobject self, jobject input, jint inputOffset, jint inputLength, jobject output, jint outputOffset)
{ {
char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0);
char* out = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0); char* out = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0);
if(in == 0 || out == 0) { if(in == 0 || out == 0) {
// out of memory // out of memory
if(in != 0) { if(in != 0) {
env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); env->ReleasePrimitiveArrayCritical((jarray) input, in, 0);
} }
if(out != 0) { if(out != 0) {
env->ReleasePrimitiveArrayCritical((jarray) output, out, 0); env->ReleasePrimitiveArrayCritical((jarray) output, out, 0);
} }
throw_exception(env, self, 4); throw_exception(env, self, 4);
return 0; return 0;
} }
size_t uncompressedLength; size_t uncompressedLength;
snappy::GetUncompressedLength(in + inputOffset, (size_t) inputLength, &uncompressedLength); snappy::GetUncompressedLength(in + inputOffset, (size_t) inputLength, &uncompressedLength);
bool ret = snappy::RawUncompress(in + inputOffset, (size_t) inputLength, out + outputOffset); bool ret = snappy::RawUncompress(in + inputOffset, (size_t) inputLength, out + outputOffset);
env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); env->ReleasePrimitiveArrayCritical((jarray) input, in, 0);
env->ReleasePrimitiveArrayCritical((jarray) output, out, 0); env->ReleasePrimitiveArrayCritical((jarray) output, out, 0);
if(!ret) { if(!ret) {
throw_exception(env, self, 5); throw_exception(env, self, 5);
return 0; return 0;
} }
return (jint) uncompressedLength; return (jint) uncompressedLength;
} }
/* /*
* Class: org_xerial_snappy_Snappy * Class: org_xerial_snappy_Snappy
* Method: uncompress * Method: uncompress
* Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Z * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Z
*/ */
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I
(JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen, jobject decompressed, jint dpos) (JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen, jobject decompressed, jint dpos)
{ {
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
char* decompressedBuffer = (char*) env->GetDirectBufferAddress(decompressed); char* decompressedBuffer = (char*) env->GetDirectBufferAddress(decompressed);
if(compressedBuffer == 0 || decompressedBuffer == 0) { if(compressedBuffer == 0 || decompressedBuffer == 0) {
throw_exception(env, self, 3); throw_exception(env, self, 3);
return (jint) 0; return (jint) 0;
} }
size_t decompressedLength; size_t decompressedLength;
snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &decompressedLength); snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &decompressedLength);
bool ret = snappy::RawUncompress(compressedBuffer + cpos, (size_t) clen, decompressedBuffer + dpos); bool ret = snappy::RawUncompress(compressedBuffer + cpos, (size_t) clen, decompressedBuffer + dpos);
if(!ret) { if(!ret) {
throw_exception(env, self, 5); throw_exception(env, self, 5);
return 0; return 0;
} }
return (jint) decompressedLength; return (jint) decompressedLength;
} }
/* /*
* Class: org_xerial_snappy_Snappy * Class: org_xerial_snappy_Snappy
* Method: maxCompressedLength * Method: maxCompressedLength
* Signature: (J)J * Signature: (J)J
*/ */
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_maxCompressedLength JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_maxCompressedLength
(JNIEnv *, jobject, jint size) (JNIEnv *, jobject, jint size)
{ {
size_t l = snappy::MaxCompressedLength((size_t) size); size_t l = snappy::MaxCompressedLength((size_t) size);
return (jint) l; return (jint) l;
} }
/* /*
* Class: org_xerial_snappy_Snappy * Class: org_xerial_snappy_Snappy
* Method: getUncompressedLength * Method: getUncompressedLength
* Signature: (Ljava/nio/ByteBuffer;)J * Signature: (Ljava/nio/ByteBuffer;)J
*/ */
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_nio_ByteBuffer_2II JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_nio_ByteBuffer_2II
(JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen) (JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen)
{ {
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
if(compressedBuffer == 0) { if(compressedBuffer == 0) {
throw_exception(env, self, 3); throw_exception(env, self, 3);
return (jint) 0; return (jint) 0;
} }
size_t result; size_t result;
bool ret = snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &result); bool ret = snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &result);
if(!ret) { if(!ret) {
throw_exception(env, self, 2); throw_exception(env, self, 2);
return 0; return 0;
} }
return (jint) result; return (jint) result;
} }
JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_lang_Object_2II JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_lang_Object_2II
(JNIEnv * env, jobject self, jobject input, jint offset, jint length) (JNIEnv * env, jobject self, jobject input, jint offset, jint length)
{ {
char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0);
if(in == 0) { if(in == 0) {
// out of memory // out of memory
throw_exception(env, self, 4); throw_exception(env, self, 4);
return 0; return 0;
} }
size_t result; size_t result;
bool ret = snappy::GetUncompressedLength(in + offset, (size_t) length, &result); bool ret = snappy::GetUncompressedLength(in + offset, (size_t) length, &result);
env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); env->ReleasePrimitiveArrayCritical((jarray) input, in, 0);
if(!ret) { if(!ret) {
throw_exception(env, self, 2); throw_exception(env, self, 2);
return 0; return 0;
} }
return (jint) result; return (jint) result;
} }
JNIEXPORT jlong JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__JJ JNIEXPORT jlong JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__JJ
(JNIEnv *env, jobject self, jlong inputAddr, jlong len) { (JNIEnv *env, jobject self, jlong inputAddr, jlong len) {
size_t result; size_t result;
bool ret = snappy::GetUncompressedLength((char*) inputAddr, (size_t) len, &result); bool ret = snappy::GetUncompressedLength((char*) inputAddr, (size_t) len, &result);
if(!ret) { if(!ret) {
throw_exception(env, self, 2); throw_exception(env, self, 2);
return 0; return 0;
} }
return (jint) result; return (jint) result;
} }
JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_nio_ByteBuffer_2II JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_nio_ByteBuffer_2II
(JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen) (JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen)
{ {
char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed);
if(compressedBuffer == 0) { if(compressedBuffer == 0) {
throw_exception(env, self, 3); throw_exception(env, self, 3);
return (jint) 0; return (jint) 0;
} }
bool ret = snappy::IsValidCompressedBuffer(compressedBuffer + cpos, (size_t) clen); bool ret = snappy::IsValidCompressedBuffer(compressedBuffer + cpos, (size_t) clen);
return ret; return ret;
} }
JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_lang_Object_2II JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_lang_Object_2II
(JNIEnv * env, jobject self, jobject input, jint offset, jint length) (JNIEnv * env, jobject self, jobject input, jint offset, jint length)
{ {
char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0);
if(in == 0) { if(in == 0) {
// out of memory // out of memory
throw_exception(env, self, 4); throw_exception(env, self, 4);
return 0; return 0;
} }
bool ret = snappy::IsValidCompressedBuffer(in + offset, (size_t) length); bool ret = snappy::IsValidCompressedBuffer(in + offset, (size_t) length);
env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); env->ReleasePrimitiveArrayCritical((jarray) input, in, 0);
return ret; return ret;
} }
JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__JJJ JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__JJJ
(JNIEnv * env, jobject self, jlong inputAddr, jlong offset, jlong length) (JNIEnv * env, jobject self, jlong inputAddr, jlong offset, jlong length)
{ {
if(inputAddr == 0) { if(inputAddr == 0) {
// out of memory // out of memory
throw_exception(env, self, 4); throw_exception(env, self, 4);
return 0; return 0;
} }
bool ret = snappy::IsValidCompressedBuffer((char*) (inputAddr + offset), (size_t) length); bool ret = snappy::IsValidCompressedBuffer((char*) (inputAddr + offset), (size_t) length);
return ret; return ret;
} }
JNIEXPORT void JNICALL Java_org_xerial_snappy_SnappyNative_arrayCopy JNIEXPORT void JNICALL Java_org_xerial_snappy_SnappyNative_arrayCopy
(JNIEnv * env, jobject self, jobject input, jint offset, jint length, jobject output, jint output_offset) (JNIEnv * env, jobject self, jobject input, jint offset, jint length, jobject output, jint output_offset)
{ {
char* src = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); char* src = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0);
char* dest = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0); char* dest = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0);
if(src == 0 || dest == 0) { if(src == 0 || dest == 0) {
// out of memory // out of memory
if(src != 0) { if(src != 0) {
env->ReleasePrimitiveArrayCritical((jarray) input, src, 0); env->ReleasePrimitiveArrayCritical((jarray) input, src, 0);
} }
if(dest != 0) { if(dest != 0) {
env->ReleasePrimitiveArrayCritical((jarray) output, dest, 0); env->ReleasePrimitiveArrayCritical((jarray) output, dest, 0);
} }
throw_exception(env, self, 4); throw_exception(env, self, 4);
return; return;
} }
memcpy(dest+output_offset, src+offset, (size_t) length); memcpy(dest+output_offset, src+offset, (size_t) length);
env->ReleasePrimitiveArrayCritical((jarray) input, src, 0); env->ReleasePrimitiveArrayCritical((jarray) input, src, 0);
env->ReleasePrimitiveArrayCritical((jarray) output, dest, 0); env->ReleasePrimitiveArrayCritical((jarray) output, dest, 0);
} }

View File

@ -1,87 +1,100 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// snappy-java Project // snappy-java Project
// //
// SnappyNative.java // SnappyNative.java
// Since: 2011/03/30 // Since: 2011/03/30
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
* JNI interface of the {@link Snappy} implementation. The native method in this class is * JNI interface of the {@link Snappy} implementation. The native method in this class is
* defined in SnappyNative.h (genereted by javah) and SnappyNative.cpp * defined in SnappyNative.h (genereted by javah) and SnappyNative.cpp
* * <p/>
* <p> * <p>
* <b> DO NOT USE THIS CLASS since the direct use of this class might break the * <b> DO NOT USE THIS CLASS since the direct use of this class might break the
* native library code loading in {@link SnappyLoader}. </b> * native library code loading in {@link SnappyLoader}. </b>
* </p> * </p>
* *
* @author leo * @author leo
* */
*/ public class SnappyNative
public class SnappyNative {
{
public native String nativeLibraryVersion();
public native String nativeLibraryVersion();
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------ // Generic compression/decompression routines.
// Generic compression/decompression routines. // ------------------------------------------------------------------------
// ------------------------------------------------------------------------ public native long rawCompress(long inputAddr, long inputSize, long destAddr)
public native long rawCompress(long inputAddr, long inputSize, long destAddr) throws IOException; throws IOException;
public native long rawUncompress(long inputAddr, long inputSize, long destAddr) throws IOException;
public native long rawUncompress(long inputAddr, long inputSize, long destAddr)
public native int rawCompress(ByteBuffer input, int inputOffset, int inputLength, ByteBuffer compressed, throws IOException;
int outputOffset) throws IOException;
public native int rawCompress(ByteBuffer input, int inputOffset, int inputLength, ByteBuffer compressed,
public native int rawCompress(Object input, int inputOffset, int inputByteLength, Object output, int outputOffset) throws IOException; int outputOffset)
throws IOException;
public native int rawUncompress(ByteBuffer compressed, int inputOffset, int inputLength, ByteBuffer uncompressed,
int outputOffset) throws IOException; public native int rawCompress(Object input, int inputOffset, int inputByteLength, Object output, int outputOffset)
throws IOException;
public native int rawUncompress(Object input, int inputOffset, int inputLength, Object output, int outputOffset)
throws IOException; public native int rawUncompress(ByteBuffer compressed, int inputOffset, int inputLength, ByteBuffer uncompressed,
int outputOffset)
// Returns the maximal size of the compressed representation of throws IOException;
// input data that is "source_bytes" bytes in length;
public native int maxCompressedLength(int source_bytes); public native int rawUncompress(Object input, int inputOffset, int inputLength, Object output, int outputOffset)
throws IOException;
// This operation takes O(1) time.
public native int uncompressedLength(ByteBuffer compressed, int offset, int len) throws IOException; // Returns the maximal size of the compressed representation of
// input data that is "source_bytes" bytes in length;
public native int uncompressedLength(Object input, int offset, int len) throws IOException; public native int maxCompressedLength(int source_bytes);
public native long uncompressedLength(long inputAddr, long len) throws IOException; // This operation takes O(1) time.
public native int uncompressedLength(ByteBuffer compressed, int offset, int len)
public native boolean isValidCompressedBuffer(ByteBuffer compressed, int offset, int len) throws IOException; throws IOException;
public native boolean isValidCompressedBuffer(Object input, int offset, int len) throws IOException; public native int uncompressedLength(Object input, int offset, int len)
throws IOException;
public native boolean isValidCompressedBuffer(long inputAddr, long offset, long len) throws IOException;
public native long uncompressedLength(long inputAddr, long len)
public native void arrayCopy(Object src, int offset, int byteLength, Object dest, int dOffset) throws IOException; throws IOException;
public void throw_error(int errorCode) throws IOException { public native boolean isValidCompressedBuffer(ByteBuffer compressed, int offset, int len)
throw new IOException(String.format("%s(%d)", SnappyErrorCode.getErrorMessage(errorCode), errorCode)); throws IOException;
}
public native boolean isValidCompressedBuffer(Object input, int offset, int len)
} throws IOException;
public native boolean isValidCompressedBuffer(long inputAddr, long offset, long len)
throws IOException;
public native void arrayCopy(Object src, int offset, int byteLength, Object dest, int dOffset)
throws IOException;
public void throw_error(int errorCode)
throws IOException
{
throw new IOException(String.format("%s(%d)", SnappyErrorCode.getErrorMessage(errorCode), errorCode));
}
}

View File

@ -55,7 +55,9 @@ import java.io.OutputStream;
* *
* @author leo * @author leo
*/ */
public class SnappyOutputStream extends OutputStream { public class SnappyOutputStream
extends OutputStream
{
static final int MIN_BLOCK_SIZE = 1 * 1024; static final int MIN_BLOCK_SIZE = 1 * 1024;
static final int DEFAULT_BLOCK_SIZE = 32 * 1024; // Use 32kb for the default block size static final int DEFAULT_BLOCK_SIZE = 32 * 1024; // Use 32kb for the default block size
@ -65,12 +67,15 @@ public class SnappyOutputStream extends OutputStream {
private final BufferAllocator inputBufferAllocator; private final BufferAllocator inputBufferAllocator;
private final BufferAllocator outputBufferAllocator; private final BufferAllocator outputBufferAllocator;
protected final byte[] inputBuffer; // The input and output buffer fields are set to null when closing this stream:
protected final byte[] outputBuffer; protected byte[] inputBuffer;
protected byte[] outputBuffer;
private int inputCursor = 0; private int inputCursor = 0;
private int outputCursor = 0; private int outputCursor = 0;
private boolean closed;
public SnappyOutputStream(OutputStream out) { public SnappyOutputStream(OutputStream out)
{
this(out, DEFAULT_BLOCK_SIZE); this(out, DEFAULT_BLOCK_SIZE);
} }
@ -79,11 +84,13 @@ public class SnappyOutputStream extends OutputStream {
* @param blockSize byte size of the internal buffer size * @param blockSize byte size of the internal buffer size
* @throws IOException * @throws IOException
*/ */
public SnappyOutputStream(OutputStream out, int blockSize) { public SnappyOutputStream(OutputStream out, int blockSize)
this(out, blockSize, CachedBufferAllocator.factory); {
this(out, blockSize, CachedBufferAllocator.getBufferAllocatorFactory());
} }
public SnappyOutputStream(OutputStream out, int blockSize, BufferAllocatorFactory bufferAllocatorFactory) { public SnappyOutputStream(OutputStream out, int blockSize, BufferAllocatorFactory bufferAllocatorFactory)
{
this.out = out; this.out = out;
this.blockSize = Math.max(MIN_BLOCK_SIZE, blockSize); this.blockSize = Math.max(MIN_BLOCK_SIZE, blockSize);
int inputSize = blockSize; int inputSize = blockSize;
@ -98,72 +105,83 @@ public class SnappyOutputStream extends OutputStream {
outputCursor = SnappyCodec.currentHeader.writeHeader(outputBuffer, 0); outputCursor = SnappyCodec.currentHeader.writeHeader(outputBuffer, 0);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see java.io.OutputStream#write(byte[], int, int) * @see java.io.OutputStream#write(byte[], int, int)
*/ */
@Override @Override
public void write(byte[] b, int off, int len) throws IOException { public void write(byte[] b, int off, int len)
throws IOException
{
rawWrite(b, off, len); rawWrite(b, off, len);
} }
/** /**
* Compress the input long array data * Compress the input long array data
* *
* @param d input array * @param d input array
* @param off offset in the array * @param off offset in the array
* @param len the number of elements in the array to copy * @param len the number of elements in the array to copy
* @throws IOException * @throws IOException
*/ */
public void write(long[] d, int off, int len) throws IOException { public void write(long[] d, int off, int len)
throws IOException
{
rawWrite(d, off * 8, len * 8); rawWrite(d, off * 8, len * 8);
} }
/** /**
* Compress the input double array data * Compress the input double array data
* *
* @param f input array * @param f input array
* @param off offset in the array * @param off offset in the array
* @param len the number of elements in the array to copy * @param len the number of elements in the array to copy
* @throws IOException * @throws IOException
*/ */
public void write(double[] f, int off, int len) throws IOException { public void write(double[] f, int off, int len)
throws IOException
{
rawWrite(f, off * 8, len * 8); rawWrite(f, off * 8, len * 8);
} }
/** /**
* Compress the input float array data * Compress the input float array data
* *
* @param f input array * @param f input array
* @param off offset in the array * @param off offset in the array
* @param len the number of elements in the array to copy * @param len the number of elements in the array to copy
* @throws IOException * @throws IOException
*/ */
public void write(float[] f, int off, int len) throws IOException { public void write(float[] f, int off, int len)
throws IOException
{
rawWrite(f, off * 4, len * 4); rawWrite(f, off * 4, len * 4);
} }
/** /**
* Compress the input int array data * Compress the input int array data
* *
* @param f input array * @param f input array
* @param off offset in the array * @param off offset in the array
* @param len the number of elements in the array to copy * @param len the number of elements in the array to copy
* @throws IOException * @throws IOException
*/ */
public void write(int[] f, int off, int len) throws IOException { public void write(int[] f, int off, int len)
throws IOException
{
rawWrite(f, off * 4, len * 4); rawWrite(f, off * 4, len * 4);
} }
/** /**
* Compress the input short array data * Compress the input short array data
* *
* @param f input array * @param f input array
* @param off offset in the array * @param off offset in the array
* @param len the number of elements in the array to copy * @param len the number of elements in the array to copy
* @throws IOException * @throws IOException
*/ */
public void write(short[] f, int off, int len) throws IOException { public void write(short[] f, int off, int len)
throws IOException
{
rawWrite(f, off * 2, len * 2); rawWrite(f, off * 2, len * 2);
} }
@ -173,7 +191,9 @@ public class SnappyOutputStream extends OutputStream {
* @param d * @param d
* @throws IOException * @throws IOException
*/ */
public void write(long[] d) throws IOException { public void write(long[] d)
throws IOException
{
write(d, 0, d.length); write(d, 0, d.length);
} }
@ -183,7 +203,9 @@ public class SnappyOutputStream extends OutputStream {
* @param f * @param f
* @throws IOException * @throws IOException
*/ */
public void write(double[] f) throws IOException { public void write(double[] f)
throws IOException
{
write(f, 0, f.length); write(f, 0, f.length);
} }
@ -193,7 +215,9 @@ public class SnappyOutputStream extends OutputStream {
* @param f * @param f
* @throws IOException * @throws IOException
*/ */
public void write(float[] f) throws IOException { public void write(float[] f)
throws IOException
{
write(f, 0, f.length); write(f, 0, f.length);
} }
@ -203,7 +227,9 @@ public class SnappyOutputStream extends OutputStream {
* @param f * @param f
* @throws IOException * @throws IOException
*/ */
public void write(int[] f) throws IOException { public void write(int[] f)
throws IOException
{
write(f, 0, f.length); write(f, 0, f.length);
} }
@ -213,11 +239,14 @@ public class SnappyOutputStream extends OutputStream {
* @param f * @param f
* @throws IOException * @throws IOException
*/ */
public void write(short[] f) throws IOException { public void write(short[] f)
throws IOException
{
write(f, 0, f.length); write(f, 0, f.length);
} }
private boolean hasSufficientOutputBufferFor(int inputSize) { private boolean hasSufficientOutputBufferFor(int inputSize)
{
int maxCompressedSize = Snappy.maxCompressedLength(inputSize); int maxCompressedSize = Snappy.maxCompressedLength(inputSize);
return maxCompressedSize < outputBuffer.length - outputCursor - 4; return maxCompressedSize < outputBuffer.length - outputCursor - 4;
} }
@ -225,31 +254,31 @@ public class SnappyOutputStream extends OutputStream {
/** /**
* Compress the raw byte array data. * Compress the raw byte array data.
* *
* @param array array data of any type (e.g., byte[], float[], long[], ...) * @param array array data of any type (e.g., byte[], float[], long[], ...)
* @param byteOffset * @param byteOffset
* @param byteLength * @param byteLength
* @throws IOException * @throws IOException
*/ */
public void rawWrite(Object array, int byteOffset, int byteLength) throws IOException { public void rawWrite(Object array, int byteOffset, int byteLength)
throws IOException
if(inputCursor + byteLength < MIN_BLOCK_SIZE) { {
// copy the input data to uncompressed buffer if (closed) {
Snappy.arrayCopy(array, byteOffset, byteLength, inputBuffer, inputCursor); throw new IOException("Stream is closed");
inputCursor += byteLength;
return;
} }
int cursor = 0;
compressInput(); while (cursor < byteLength) {
int readLen = Math.min(byteLength - cursor, blockSize - inputCursor);
for(int readBytes = 0; readBytes < byteLength; ) { // copy the input data to uncompressed buffer
int inputLen = Math.min(blockSize, byteLength - readBytes); if (readLen > 0) {
if(!hasSufficientOutputBufferFor(inputLen)) { Snappy.arrayCopy(array, byteOffset + cursor, readLen, inputBuffer, inputCursor);
dumpOutput(); inputCursor += readLen;
} }
int compressedSize = Snappy.rawCompress(array, byteOffset + readBytes, inputLen, outputBuffer, outputCursor + 4); if (inputCursor < blockSize) {
writeInt(outputBuffer, outputCursor, compressedSize); return;
outputCursor += 4 + compressedSize; }
readBytes += inputLen;
compressInput();
cursor += readLen;
} }
} }
@ -263,8 +292,13 @@ public class SnappyOutputStream extends OutputStream {
* @see java.io.OutputStream#write(int) * @see java.io.OutputStream#write(int)
*/ */
@Override @Override
public void write(int b) throws IOException { public void write(int b)
if(inputCursor >= inputBuffer.length) { throws IOException
{
if (closed) {
throw new IOException("Stream is closed");
}
if (inputCursor >= inputBuffer.length) {
compressInput(); compressInput();
} }
inputBuffer[inputCursor++] = (byte) b; inputBuffer[inputCursor++] = (byte) b;
@ -274,20 +308,27 @@ public class SnappyOutputStream extends OutputStream {
* @see java.io.OutputStream#flush() * @see java.io.OutputStream#flush()
*/ */
@Override @Override
public void flush() throws IOException { public void flush()
throws IOException
{
if (closed) {
throw new IOException("Stream is closed");
}
compressInput(); compressInput();
dumpOutput(); dumpOutput();
out.flush(); out.flush();
} }
static void writeInt(byte[] dst, int offset, int v) { static void writeInt(byte[] dst, int offset, int v)
{
dst[offset] = (byte) ((v >> 24) & 0xFF); dst[offset] = (byte) ((v >> 24) & 0xFF);
dst[offset + 1] = (byte) ((v >> 16) & 0xFF); dst[offset + 1] = (byte) ((v >> 16) & 0xFF);
dst[offset + 2] = (byte) ((v >> 8) & 0xFF); dst[offset + 2] = (byte) ((v >> 8) & 0xFF);
dst[offset + 3] = (byte) ((v >> 0) & 0xFF); dst[offset + 3] = (byte) ((v >> 0) & 0xFF);
} }
static int readInt(byte[] buffer, int pos) { static int readInt(byte[] buffer, int pos)
{
int b1 = (buffer[pos] & 0xFF) << 24; int b1 = (buffer[pos] & 0xFF) << 24;
int b2 = (buffer[pos + 1] & 0xFF) << 16; int b2 = (buffer[pos + 1] & 0xFF) << 16;
int b3 = (buffer[pos + 2] & 0xFF) << 8; int b3 = (buffer[pos + 2] & 0xFF) << 8;
@ -295,20 +336,24 @@ public class SnappyOutputStream extends OutputStream {
return b1 | b2 | b3 | b4; return b1 | b2 | b3 | b4;
} }
protected void dumpOutput() throws IOException { protected void dumpOutput()
if(outputCursor > 0) { throws IOException
{
if (outputCursor > 0) {
out.write(outputBuffer, 0, outputCursor); out.write(outputBuffer, 0, outputCursor);
outputCursor = 0; outputCursor = 0;
} }
} }
protected void compressInput() throws IOException { protected void compressInput()
if(inputCursor <= 0) { throws IOException
{
if (inputCursor <= 0) {
return; // no need to dump return; // no need to dump
} }
// Compress and dump the buffer content // Compress and dump the buffer content
if(!hasSufficientOutputBufferFor(inputCursor)) { if (!hasSufficientOutputBufferFor(inputCursor)) {
dumpOutput(); dumpOutput();
} }
int compressedSize = Snappy.compress(inputBuffer, 0, inputCursor, outputBuffer, outputCursor + 4); int compressedSize = Snappy.compress(inputBuffer, 0, inputCursor, outputBuffer, outputCursor + 4);
@ -325,14 +370,22 @@ public class SnappyOutputStream extends OutputStream {
* @see java.io.OutputStream#close() * @see java.io.OutputStream#close()
*/ */
@Override @Override
public void close() throws IOException { public void close()
throws IOException
{
if (closed) {
return;
}
try { try {
flush(); flush();
out.close(); out.close();
} finally { }
finally {
closed = true;
inputBufferAllocator.release(inputBuffer); inputBufferAllocator.release(inputBuffer);
outputBufferAllocator.release(outputBuffer); outputBufferAllocator.release(outputBuffer);
inputBuffer = null;
outputBuffer = null;
} }
} }
} }

View File

@ -1,2 +0,0 @@
VERSION=1.1.1

View File

@ -3,9 +3,10 @@ package org.xerial.snappy.buffer;
/** /**
* BufferAllocator interface. The implementation of this interface must be thread-safe * BufferAllocator interface. The implementation of this interface must be thread-safe
*/ */
public interface BufferAllocator { public interface BufferAllocator
{
public byte[] allocate(int size); public byte[] allocate(int size);
public void release(byte[] buffer);
public void release(byte[] buffer);
} }

View File

@ -3,7 +3,8 @@ package org.xerial.snappy.buffer;
/** /**
* *
*/ */
public interface BufferAllocatorFactory { public interface BufferAllocatorFactory
{
BufferAllocator getBufferAllocator(int minSize); BufferAllocator getBufferAllocator(int minSize);
} }

View File

@ -6,29 +6,45 @@ import java.util.*;
/** /**
* Cached buffer * Cached buffer
*/ */
public class CachedBufferAllocator implements BufferAllocator { public class CachedBufferAllocator
implements BufferAllocator
public static BufferAllocatorFactory factory = new BufferAllocatorFactory() { {
private static BufferAllocatorFactory factory = new BufferAllocatorFactory()
{
@Override @Override
public BufferAllocator getBufferAllocator(int bufferSize) { public BufferAllocator getBufferAllocator(int bufferSize)
{
return CachedBufferAllocator.getAllocator(bufferSize); return CachedBufferAllocator.getAllocator(bufferSize);
} }
}; };
public static void setBufferAllocatorFactory(BufferAllocatorFactory factory)
{
assert (factory != null);
CachedBufferAllocator.factory = factory;
}
public static BufferAllocatorFactory getBufferAllocatorFactory()
{
return factory;
}
/** /**
* Use SoftReference so that having this queueTable does not prevent the GC of CachedBufferAllocator instances * Use SoftReference so that having this queueTable does not prevent the GC of CachedBufferAllocator instances
*/ */
public static Map<Integer, SoftReference<CachedBufferAllocator>> queueTable = new HashMap<Integer, SoftReference<CachedBufferAllocator>>(); private static final Map<Integer, SoftReference<CachedBufferAllocator>> queueTable = new HashMap<Integer, SoftReference<CachedBufferAllocator>>();
private final int bufferSize; private final int bufferSize;
private final Deque<byte[]> bufferQueue; private final Deque<byte[]> bufferQueue;
public CachedBufferAllocator(int bufferSize) { public CachedBufferAllocator(int bufferSize)
{
this.bufferSize = bufferSize; this.bufferSize = bufferSize;
this.bufferQueue = new ArrayDeque<byte[]>(); this.bufferQueue = new ArrayDeque<byte[]>();
} }
public static synchronized CachedBufferAllocator getAllocator(int bufferSize) { public static synchronized CachedBufferAllocator getAllocator(int bufferSize)
{
CachedBufferAllocator result = null; CachedBufferAllocator result = null;
if (queueTable.containsKey(bufferSize)) { if (queueTable.containsKey(bufferSize)) {
@ -42,9 +58,10 @@ public class CachedBufferAllocator implements BufferAllocator {
} }
@Override @Override
public byte[] allocate(int size) { public byte[] allocate(int size)
synchronized(this) { {
if(bufferQueue.isEmpty()) { synchronized (this) {
if (bufferQueue.isEmpty()) {
return new byte[size]; return new byte[size];
} }
else { else {
@ -52,9 +69,11 @@ public class CachedBufferAllocator implements BufferAllocator {
} }
} }
} }
@Override @Override
public void release(byte[] buffer) { public void release(byte[] buffer)
synchronized(this) { {
synchronized (this) {
bufferQueue.addLast(buffer); bufferQueue.addLast(buffer);
} }
} }

View File

@ -3,24 +3,30 @@ package org.xerial.snappy.buffer;
/** /**
* Simple buffer allocator, which does not reuse the allocated buffer * Simple buffer allocator, which does not reuse the allocated buffer
*/ */
public class DefaultBufferAllocator implements BufferAllocator { public class DefaultBufferAllocator
implements BufferAllocator
{
public static BufferAllocatorFactory factory = new BufferAllocatorFactory() { public static BufferAllocatorFactory factory = new BufferAllocatorFactory()
{
public BufferAllocator singleton = new DefaultBufferAllocator(); public BufferAllocator singleton = new DefaultBufferAllocator();
@Override @Override
public BufferAllocator getBufferAllocator(int bufferSize) { public BufferAllocator getBufferAllocator(int bufferSize)
{
return singleton; return singleton;
} }
}; };
@Override @Override
public byte[] allocate(int size) { public byte[] allocate(int size)
{
return new byte[size]; return new byte[size];
} }
@Override @Override
public void release(byte[] buffer) { public void release(byte[] buffer)
{
// do nothing // do nothing
} }
} }

View File

@ -1,44 +1,44 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
/** /**
* Snappy API for compressing/decompressing data. * Snappy API for compressing/decompressing data.
* * <p/>
* Usage * Usage
* First, import {@link org.xerial.snappy.Snappy} in your Java code: * First, import {@link org.xerial.snappy.Snappy} in your Java code:
* <code> * <code>
* <pre> * <pre>
* import org.xerial.snappy.Snappy; * import org.xerial.snappy.Snappy;
* </pre> * </pre>
* </code> * </code>
* Then use {@link org.xerial.snappy.Snappy#compress(byte[])} and {@link org.xerial.snappy.Snappy#uncompress(byte[])}: * Then use {@link org.xerial.snappy.Snappy#compress(byte[])} and {@link org.xerial.snappy.Snappy#uncompress(byte[])}:
* <code> * <code>
* <pre> * <pre>
* String input = "Hello snappy-java! Snappy-java is a JNI-based wrapper of Snappy, a fast compresser/decompresser."; * String input = "Hello snappy-java! Snappy-java is a JNI-based wrapper of Snappy, a fast compresser/decompresser.";
* byte[] compressed = Snappy.compress(input.getBytes("UTF-8")); * byte[] compressed = Snappy.compress(input.getBytes("UTF-8"));
* byte[] uncompressed = Snappy.uncompress(compressed); * byte[] uncompressed = Snappy.uncompress(compressed);
* String result = new String(uncompressed, "UTF-8"); * String result = new String(uncompressed, "UTF-8");
* System.out.println(result); * System.out.println(result);
* </pre> * </pre>
* </code> * </code>
* * <p/>
* <p>In addition, high-level methods (Snappy.compress(String), Snappy.compress(float[] ..) etc. ) and low-level ones (e.g. Snappy.rawCompress(.. ), Snappy.rawUncompress(..), etc.), which minimize memory copies, can be used. </p> * <p>In addition, high-level methods (Snappy.compress(String), Snappy.compress(float[] ..) etc. ) and low-level ones (e.g. Snappy.rawCompress(.. ), Snappy.rawUncompress(..), etc.), which minimize memory copies, can be used. </p>
* * <p/>
* <h3>Stream-based API</h3> * <h3>Stream-based API</h3>
* Stream-based compressor/decompressor SnappyOutputStream, SnappyInputStream are also available for reading/writing large data sets. * Stream-based compressor/decompressor SnappyOutputStream, SnappyInputStream are also available for reading/writing large data sets.
*/ */
package org.xerial.snappy; package org.xerial.snappy;

View File

@ -0,0 +1 @@
VERSION=1.1.2

View File

@ -1,228 +1,238 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// CalgaryTest.java // CalgaryTest.java
// Since: 2011/04/04 12:10:36 // Since: 2011/04/04 12:10:36
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
import org.xerial.util.FileResource; import org.xerial.util.FileResource;
import org.xerial.util.log.Logger; import org.xerial.util.log.Logger;
/** /**
* Benchmark using Calgary data set * Benchmark using Calgary data set
* *
* @author leo * @author leo
* */
*/ public class CalgaryTest
public class CalgaryTest {
{ private static Logger _logger = Logger.getLogger(CalgaryTest.class);
private static Logger _logger = Logger.getLogger(CalgaryTest.class);
@Rule
@Rule public final TemporaryFolder tempFolder = new TemporaryFolder();
public final TemporaryFolder tempFolder = new TemporaryFolder();
static byte[] readFile(String file)
static byte[] readFile(String file) throws IOException { throws IOException
InputStream in = FileResource.find(CalgaryTest.class, file).openStream(); {
if (in == null) InputStream in = FileResource.find(CalgaryTest.class, file).openStream();
throw new IOException("file " + file + " is not found"); if (in == null) {
try { throw new IOException("file " + file + " is not found");
return SnappyInputStreamTest.readFully(in); }
} try {
finally { return SnappyInputStreamTest.readFully(in);
if (in != null) }
in.close(); finally {
} if (in != null) {
} in.close();
}
public static final String[] files = { "bib", "book1", "book2", "geo", "news", "obj1", "obj2", "paper1", "paper2", }
"paper3", "paper4", "paper5", "paper6", "pic", "progc", "progl", "progp", "trans" }; }
@Test public static final String[] files = {"bib", "book1", "book2", "geo", "news", "obj1", "obj2", "paper1", "paper2",
public void block() throws Exception { "paper3", "paper4", "paper5", "paper6", "pic", "progc", "progl", "progp", "trans"};
for (String f : files) {
byte[] orig = readFile("testdata/calgary/" + f); @Test
public void block()
byte[] compressed = Snappy.compress(orig); throws Exception
byte[] uncompressed = Snappy.uncompress(compressed); {
for (String f : files) {
assertArrayEquals(orig, uncompressed); byte[] orig = readFile("testdata/calgary/" + f);
}
} byte[] compressed = Snappy.compress(orig);
byte[] uncompressed = Snappy.uncompress(compressed);
@Test
public void stream() throws Exception { assertArrayEquals(orig, uncompressed);
for (String f : files) { }
byte[] orig = readFile("testdata/calgary/" + f); }
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream(); @Test
SnappyOutputStream out = new SnappyOutputStream(compressedBuf); public void stream()
out.write(orig); throws Exception
out.close(); {
for (String f : files) {
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressedBuf.toByteArray())); byte[] orig = readFile("testdata/calgary/" + f);
byte[] uncompressed = new byte[orig.length];
int readBytes = in.read(uncompressed); ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream();
assertEquals(orig.length, readBytes); SnappyOutputStream out = new SnappyOutputStream(compressedBuf);
assertArrayEquals(orig, uncompressed); out.write(orig);
} out.close();
}
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressedBuf.toByteArray()));
@Test byte[] uncompressed = new byte[orig.length];
public void streamFramed() throws Exception { int readBytes = in.read(uncompressed);
for (String f : files) { assertEquals(orig.length, readBytes);
byte[] orig = readFile("testdata/calgary/" + f); assertArrayEquals(orig, uncompressed);
}
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream(); }
SnappyFramedOutputStream out = new SnappyFramedOutputStream(compressedBuf);
out.write(orig); @Test
out.close(); public void streamFramed()
throws Exception
SnappyFramedInputStream in = new SnappyFramedInputStream(new ByteArrayInputStream(compressedBuf.toByteArray())); {
for (String f : files) {
byte[] uncompressed = new byte[orig.length]; byte[] orig = readFile("testdata/calgary/" + f);
int readBytes = readBytes(in, uncompressed, 0, orig.length);
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream();
assertEquals(orig.length, readBytes); SnappyFramedOutputStream out = new SnappyFramedOutputStream(compressedBuf);
assertArrayEquals(orig, uncompressed); out.write(orig);
} out.close();
}
SnappyFramedInputStream in = new SnappyFramedInputStream(new ByteArrayInputStream(compressedBuf.toByteArray()));
@Test
public void streamFramedToFile() throws Exception { byte[] uncompressed = new byte[orig.length];
for (String f : files) { int readBytes = readBytes(in, uncompressed, 0, orig.length);
byte[] orig = readFile("testdata/calgary/" + f);
assertEquals(orig.length, readBytes);
final File tempFile = tempFolder.newFile(f); assertArrayEquals(orig, uncompressed);
final FileOutputStream compressedFOS = new FileOutputStream(tempFile); }
try }
{
SnappyFramedOutputStream out = new SnappyFramedOutputStream(compressedFOS); @Test
out.write(orig); public void streamFramedToFile()
out.close(); throws Exception
} {
finally for (String f : files) {
{ byte[] orig = readFile("testdata/calgary/" + f);
compressedFOS.close();
} final File tempFile = tempFolder.newFile(f);
final FileOutputStream compressedFOS = new FileOutputStream(tempFile);
byte[] uncompressed = new byte[orig.length]; try {
SnappyFramedOutputStream out = new SnappyFramedOutputStream(compressedFOS);
final FileInputStream compressedFIS = new FileInputStream(tempFile); out.write(orig);
try out.close();
{ }
SnappyFramedInputStream in = new SnappyFramedInputStream(compressedFIS.getChannel()); finally {
int readBytes = readBytes(in, uncompressed, 0, orig.length); compressedFOS.close();
}
assertEquals(orig.length, readBytes);
} byte[] uncompressed = new byte[orig.length];
finally
{ final FileInputStream compressedFIS = new FileInputStream(tempFile);
compressedFIS.close(); try {
} SnappyFramedInputStream in = new SnappyFramedInputStream(compressedFIS.getChannel());
int readBytes = readBytes(in, uncompressed, 0, orig.length);
assertArrayEquals(orig, uncompressed);
} assertEquals(orig.length, readBytes);
} }
finally {
@Test compressedFIS.close();
public void streamFramedNoCRCVerify() throws Exception { }
for (String f : files) {
byte[] orig = readFile("testdata/calgary/" + f); assertArrayEquals(orig, uncompressed);
}
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream(); }
SnappyFramedOutputStream out = new SnappyFramedOutputStream(compressedBuf);
out.write(orig); @Test
out.close(); public void streamFramedNoCRCVerify()
throws Exception
SnappyFramedInputStream in = new SnappyFramedInputStream(new ByteArrayInputStream(compressedBuf.toByteArray()), false); {
for (String f : files) {
byte[] uncompressed = new byte[orig.length]; byte[] orig = readFile("testdata/calgary/" + f);
int readBytes = readBytes(in, uncompressed, 0, orig.length);
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream();
assertEquals(orig.length, readBytes); SnappyFramedOutputStream out = new SnappyFramedOutputStream(compressedBuf);
assertArrayEquals(orig, uncompressed); out.write(orig);
} out.close();
}
SnappyFramedInputStream in = new SnappyFramedInputStream(new ByteArrayInputStream(compressedBuf.toByteArray()), false);
@Test
public void byteWiseRead() throws Exception { byte[] uncompressed = new byte[orig.length];
for (String f : files) { int readBytes = readBytes(in, uncompressed, 0, orig.length);
byte[] orig = readFile("testdata/calgary/" + f);
assertEquals(orig.length, readBytes);
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream(); assertArrayEquals(orig, uncompressed);
SnappyOutputStream out = new SnappyOutputStream(compressedBuf); }
out.write(orig); }
out.close();
@Test
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressedBuf.toByteArray())); public void byteWiseRead()
byte[] uncompressed = new byte[orig.length]; throws Exception
int cursor = 0; {
for (;;) { for (String f : files) {
int b = in.read(); byte[] orig = readFile("testdata/calgary/" + f);
if (b == -1)
break; ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream();
uncompressed[cursor++] = (byte) b; SnappyOutputStream out = new SnappyOutputStream(compressedBuf);
} out.write(orig);
assertEquals(orig.length, cursor); out.close();
assertArrayEquals(orig, uncompressed);
} SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressedBuf.toByteArray()));
} byte[] uncompressed = new byte[orig.length];
int cursor = 0;
static final int readBytes(InputStream source, byte[] dest, int offset, int length) throws IOException for (; ; ) {
{ int b = in.read();
// how many bytes were read. if (b == -1) {
int lastRead = source.read(dest, offset, length); break;
}
int totalRead = lastRead; uncompressed[cursor++] = (byte) b;
}
// if we did not read as many bytes as we had hoped, try reading again. assertEquals(orig.length, cursor);
if (lastRead < length) assertArrayEquals(orig, uncompressed);
{ }
// as long the buffer is not full (remaining() == 0) and we have not reached EOF (lastRead == -1) keep reading. }
while (totalRead < length && lastRead != -1)
{ static final int readBytes(InputStream source, byte[] dest, int offset, int length)
lastRead = source.read(dest, offset + totalRead, length - totalRead); throws IOException
{
// if we got EOF, do not add to total read. // how many bytes were read.
if (lastRead != -1) int lastRead = source.read(dest, offset, length);
{
totalRead += lastRead; int totalRead = lastRead;
}
} // if we did not read as many bytes as we had hoped, try reading again.
} if (lastRead < length) {
return totalRead; // as long the buffer is not full (remaining() == 0) and we have not reached EOF (lastRead == -1) keep reading.
} while (totalRead < length && lastRead != -1) {
} lastRead = source.read(dest, offset + totalRead, length - totalRead);
// if we got EOF, do not add to total read.
if (lastRead != -1) {
totalRead += lastRead;
}
}
}
return totalRead;
}
}

View File

@ -34,7 +34,8 @@ import org.junit.Test;
public class OSInfoTest public class OSInfoTest
{ {
@Test @Test
public void osName() { public void osName()
{
assertEquals("Windows", OSInfo.translateOSNameToFolderName("Windows XP")); assertEquals("Windows", OSInfo.translateOSNameToFolderName("Windows XP"));
assertEquals("Windows", OSInfo.translateOSNameToFolderName("Windows 2000")); assertEquals("Windows", OSInfo.translateOSNameToFolderName("Windows 2000"));
assertEquals("Windows", OSInfo.translateOSNameToFolderName("Windows Vista")); assertEquals("Windows", OSInfo.translateOSNameToFolderName("Windows Vista"));
@ -53,7 +54,8 @@ public class OSInfoTest
} }
@Test @Test
public void archName() { public void archName()
{
assertEquals("i386", OSInfo.translateArchNameToFolderName("i386")); assertEquals("i386", OSInfo.translateArchNameToFolderName("i386"));
assertEquals("x86", OSInfo.translateArchNameToFolderName("x86")); assertEquals("x86", OSInfo.translateArchNameToFolderName("x86"));
assertEquals("ppc", OSInfo.translateArchNameToFolderName("ppc")); assertEquals("ppc", OSInfo.translateArchNameToFolderName("ppc"));
@ -61,7 +63,8 @@ public class OSInfoTest
} }
@Test @Test
public void folderPath() { public void folderPath()
{
String[] component = OSInfo.getNativeLibFolderPathForCurrentOS().split("/"); String[] component = OSInfo.getNativeLibFolderPathForCurrentOS().split("/");
assertEquals(2, component.length); assertEquals(2, component.length);
assertEquals(OSInfo.getOSName(), component[0]); assertEquals(OSInfo.getOSName(), component[0]);
@ -69,7 +72,9 @@ public class OSInfoTest
} }
@Test @Test
public void testMainForOSName() throws Exception { public void testMainForOSName()
throws Exception
{
// preserve the current System.out // preserve the current System.out
PrintStream out = System.out; PrintStream out = System.out;
@ -78,18 +83,19 @@ public class OSInfoTest
ByteArrayOutputStream buf = new ByteArrayOutputStream(); ByteArrayOutputStream buf = new ByteArrayOutputStream();
PrintStream tmpOut = new PrintStream(buf); PrintStream tmpOut = new PrintStream(buf);
System.setOut(tmpOut); System.setOut(tmpOut);
OSInfo.main(new String[] { "--os" }); OSInfo.main(new String[] {"--os"});
assertEquals(OSInfo.getOSName(), buf.toString()); assertEquals(OSInfo.getOSName(), buf.toString());
} }
finally { finally {
// reset STDOUT // reset STDOUT
System.setOut(out); System.setOut(out);
} }
} }
@Test @Test
public void testMainForArchName() throws Exception { public void testMainForArchName()
throws Exception
{
// preserver the current System.out // preserver the current System.out
PrintStream out = System.out; PrintStream out = System.out;
@ -98,7 +104,7 @@ public class OSInfoTest
ByteArrayOutputStream buf = new ByteArrayOutputStream(); ByteArrayOutputStream buf = new ByteArrayOutputStream();
PrintStream tmpOut = new PrintStream(buf); PrintStream tmpOut = new PrintStream(buf);
System.setOut(tmpOut); System.setOut(tmpOut);
OSInfo.main(new String[] { "--arch" }); OSInfo.main(new String[] {"--arch"});
assertEquals(OSInfo.getArchName(), buf.toString()); assertEquals(OSInfo.getArchName(), buf.toString());
} }
finally { finally {
@ -106,5 +112,4 @@ public class OSInfoTest
System.setOut(out); System.setOut(out);
} }
} }
} }

View File

@ -1,68 +1,73 @@
/* /*
* Created: Apr 15, 2013 * Created: Apr 15, 2013
*/ */
package org.xerial.snappy; package org.xerial.snappy;
import java.util.Random; import java.util.Random;
/** /**
* Generates random data with specific expected snappy performance characteristics. * Generates random data with specific expected snappy performance characteristics.
* * <p/>
* <p> * <p>
* This has been copied from <a href="https://github.com/dain/snappy"> dain's snappy</a> implementation.. * This has been copied from <a href="https://github.com/dain/snappy"> dain's snappy</a> implementation..
* </p> * </p>
*/ */
public class RandomGenerator { public class RandomGenerator
{
public final byte[] data;
public int position; public final byte[] data;
public int position;
public RandomGenerator(double compressionRatio) {
// We use a limited amount of data over and over again and ensure public RandomGenerator(double compressionRatio)
// that it is larger than the compression window (32KB), and also {
// large enough to serve all typical value sizes we want to write. // We use a limited amount of data over and over again and ensure
Random rnd = new Random(301); // that it is larger than the compression window (32KB), and also
data = new byte[1048576 + 100]; // large enough to serve all typical value sizes we want to write.
for (int i = 0; i < 1048576; i += 100) { Random rnd = new Random(301);
// Add a short fragment that is as compressible as specified ratio data = new byte[1048576 + 100];
System.arraycopy(compressibleData(rnd, compressionRatio, 100), 0, for (int i = 0; i < 1048576; i += 100) {
data, i, 100); // Add a short fragment that is as compressible as specified ratio
} System.arraycopy(compressibleData(rnd, compressionRatio, 100), 0,
} data, i, 100);
}
public int getNextPosition(int length) { }
if (position + length > data.length) {
position = 0; public int getNextPosition(int length)
assert (length < data.length); {
} if (position + length > data.length) {
int result = position; position = 0;
position += length; assert (length < data.length);
return result; }
} int result = position;
position += length;
private static byte[] compressibleData(Random random, return result;
double compressionRatio, int length) { }
int raw = (int) (length * compressionRatio);
if (raw < 1) { private static byte[] compressibleData(Random random,
raw = 1; double compressionRatio, int length)
} {
byte[] rawData = generateRandomData(random, raw); int raw = (int) (length * compressionRatio);
if (raw < 1) {
// Duplicate the random data until we have filled "length" bytes raw = 1;
byte[] dest = new byte[length]; }
for (int i = 0; i < length;) { byte[] rawData = generateRandomData(random, raw);
int chunkLength = Math.min(rawData.length, length - i);
System.arraycopy(rawData, 0, dest, i, chunkLength); // Duplicate the random data until we have filled "length" bytes
i += chunkLength; byte[] dest = new byte[length];
} for (int i = 0; i < length; ) {
return dest; int chunkLength = Math.min(rawData.length, length - i);
} System.arraycopy(rawData, 0, dest, i, chunkLength);
i += chunkLength;
private static byte[] generateRandomData(Random random, int length) { }
byte[] rawData = new byte[length]; return dest;
for (int i = 0; i < rawData.length; i++) { }
rawData[i] = (byte) random.nextInt(256);
} private static byte[] generateRandomData(Random random, int length)
return rawData; {
} byte[] rawData = new byte[length];
for (int i = 0; i < rawData.length; i++) {
rawData[i] = (byte) random.nextInt(256);
}
return rawData;
}
} }

View File

@ -26,35 +26,42 @@ import org.junit.Test;
/** /**
* Tests the functionality of {@link org.xerial.snappy.SnappyFramedInputStream} * Tests the functionality of {@link org.xerial.snappy.SnappyFramedInputStream}
* and {@link org.xerial.snappy.SnappyFramedOutputStream}. * and {@link org.xerial.snappy.SnappyFramedOutputStream}.
* *
* @author Brett Okken * @author Brett Okken
*/ */
public class SnappyFramedStreamTest { public class SnappyFramedStreamTest
{
/** /**
* @throws IOException * @throws IOException
*/ */
protected OutputStream createOutputStream(OutputStream target) protected OutputStream createOutputStream(OutputStream target)
throws IOException { throws IOException
{
return new SnappyFramedOutputStream(target); return new SnappyFramedOutputStream(target);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
* @throws IOException * @throws IOException
*/ */
protected InputStream createInputStream(InputStream source, protected InputStream createInputStream(InputStream source,
boolean verifyCheckSums) throws IOException { boolean verifyCheckSums)
throws IOException
{
return new SnappyFramedInputStream(source, verifyCheckSums); return new SnappyFramedInputStream(source, verifyCheckSums);
} }
protected byte[] getMarkerFrame() { protected byte[] getMarkerFrame()
{
return HEADER_BYTES; return HEADER_BYTES;
} }
@Test @Test
public void testSimple() throws Exception { public void testSimple()
throws Exception
{
byte[] original = "aaaaaaaaaaaabbbbbbbaaaaaa".getBytes("utf-8"); byte[] original = "aaaaaaaaaaaabbbbbbbaaaaaa".getBytes("utf-8");
byte[] compressed = compress(original); byte[] compressed = compress(original);
@ -83,7 +90,9 @@ public class SnappyFramedStreamTest {
} }
@Test @Test
public void testUncompressable() throws Exception { public void testUncompressable()
throws Exception
{
byte[] random = getRandom(1, 5000); byte[] random = getRandom(1, 5000);
int crc32c = maskedCrc32c(random); int crc32c = maskedCrc32c(random);
@ -103,71 +112,90 @@ public class SnappyFramedStreamTest {
} }
@Test @Test
public void testEmptyCompression() throws Exception { public void testEmptyCompression()
throws Exception
{
byte[] empty = new byte[0]; byte[] empty = new byte[0];
assertArrayEquals(compress(empty), HEADER_BYTES); assertArrayEquals(compress(empty), HEADER_BYTES);
assertArrayEquals(uncompress(HEADER_BYTES), empty); assertArrayEquals(uncompress(HEADER_BYTES), empty);
} }
@Test(expected = EOFException.class) @Test(expected = EOFException.class)
public void testShortBlockHeader() throws Exception { public void testShortBlockHeader()
uncompressBlock(new byte[] { 0 }); throws Exception
{
uncompressBlock(new byte[] {0});
} }
@Test(expected = EOFException.class) @Test(expected = EOFException.class)
public void testShortBlockData() throws Exception { public void testShortBlockData()
throws Exception
{
// flag = 0, size = 8, crc32c = 0, block data= [x, x] // flag = 0, size = 8, crc32c = 0, block data= [x, x]
uncompressBlock(new byte[] { 1, 8, 0, 0, 0, 0, 0, 0, 'x', 'x' }); uncompressBlock(new byte[] {1, 8, 0, 0, 0, 0, 0, 0, 'x', 'x'});
} }
@Test @Test
public void testUnskippableChunkFlags() throws Exception { public void testUnskippableChunkFlags()
throws Exception
{
for (int i = 2; i <= 0x7f; i++) { for (int i = 2; i <= 0x7f; i++) {
try { try {
uncompressBlock(new byte[] { (byte) i, 5, 0, 0, 0, 0, 0, 0, 0 }); uncompressBlock(new byte[] {(byte) i, 5, 0, 0, 0, 0, 0, 0, 0});
fail("no exception thrown with flag: " + Integer.toHexString(i)); fail("no exception thrown with flag: " + Integer.toHexString(i));
} catch (IOException e) { }
catch (IOException e) {
} }
} }
} }
@Test @Test
public void testSkippableChunkFlags() throws Exception { public void testSkippableChunkFlags()
throws Exception
{
for (int i = 0x80; i <= 0xfe; i++) { for (int i = 0x80; i <= 0xfe; i++) {
try { try {
uncompressBlock(new byte[] { (byte) i, 5, 0, 0, 0, 0, 0, 0, 0 }); uncompressBlock(new byte[] {(byte) i, 5, 0, 0, 0, 0, 0, 0, 0});
} catch (IOException e) { }
catch (IOException e) {
fail("exception thrown with flag: " + Integer.toHexString(i)); fail("exception thrown with flag: " + Integer.toHexString(i));
} }
} }
} }
@Test(expected = IOException.class) @Test(expected = IOException.class)
public void testInvalidBlockSizeZero() throws Exception { public void testInvalidBlockSizeZero()
throws Exception
{
// flag = '0', block size = 4, crc32c = 0 // flag = '0', block size = 4, crc32c = 0
uncompressBlock(new byte[] { 1, 4, 0, 0, 0, 0, 0, 0 }); uncompressBlock(new byte[] {1, 4, 0, 0, 0, 0, 0, 0});
} }
@Test(expected = IOException.class) @Test(expected = IOException.class)
public void testInvalidChecksum() throws Exception { public void testInvalidChecksum()
throws Exception
{
// flag = 0, size = 5, crc32c = 0, block data = [a] // flag = 0, size = 5, crc32c = 0, block data = [a]
uncompressBlock(new byte[] { 1, 5, 0, 0, 0, 0, 0, 0, 'a' }); uncompressBlock(new byte[] {1, 5, 0, 0, 0, 0, 0, 0, 'a'});
} }
@Test @Test
public void testInvalidChecksumIgnoredWhenVerificationDisabled() public void testInvalidChecksumIgnoredWhenVerificationDisabled()
throws Exception { throws Exception
{
// flag = 0, size = 4, crc32c = 0, block data = [a] // flag = 0, size = 4, crc32c = 0, block data = [a]
byte[] block = { 1, 5, 0, 0, 0, 0, 0, 0, 'a' }; byte[] block = {1, 5, 0, 0, 0, 0, 0, 0, 'a'};
ByteArrayInputStream inputData = new ByteArrayInputStream( ByteArrayInputStream inputData = new ByteArrayInputStream(
blockToStream(block)); blockToStream(block));
assertArrayEquals(toByteArray(createInputStream(inputData, false)), assertArrayEquals(toByteArray(createInputStream(inputData, false)),
new byte[] { 'a' }); new byte[] {'a'});
} }
@Test @Test
public void testTransferFrom_InputStream() throws IOException { public void testTransferFrom_InputStream()
throws IOException
{
final byte[] random = getRandom(0.5, 100000); final byte[] random = getRandom(0.5, 100000);
final ByteArrayOutputStream baos = new ByteArrayOutputStream( final ByteArrayOutputStream baos = new ByteArrayOutputStream(
@ -184,7 +212,9 @@ public class SnappyFramedStreamTest {
} }
@Test @Test
public void testTransferFrom_ReadableByteChannel() throws IOException { public void testTransferFrom_ReadableByteChannel()
throws IOException
{
final byte[] random = getRandom(0.5, 100000); final byte[] random = getRandom(0.5, 100000);
final ByteArrayOutputStream baos = new ByteArrayOutputStream( final ByteArrayOutputStream baos = new ByteArrayOutputStream(
@ -201,7 +231,9 @@ public class SnappyFramedStreamTest {
} }
@Test @Test
public void testTransferTo_OutputStream() throws IOException { public void testTransferTo_OutputStream()
throws IOException
{
final byte[] random = getRandom(0.5, 100000); final byte[] random = getRandom(0.5, 100000);
final byte[] compressed = compress(random); final byte[] compressed = compress(random);
@ -216,7 +248,9 @@ public class SnappyFramedStreamTest {
} }
@Test @Test
public void testTransferTo_WritableByteChannel() throws IOException { public void testTransferTo_WritableByteChannel()
throws IOException
{
final byte[] random = getRandom(0.5, 100000); final byte[] random = getRandom(0.5, 100000);
final byte[] compressed = compress(random); final byte[] compressed = compress(random);
@ -233,14 +267,16 @@ public class SnappyFramedStreamTest {
} }
@Test @Test
public void testLargerFrames_raw_() throws IOException { public void testLargerFrames_raw_()
throws IOException
{
final byte[] random = getRandom(0.5, 100000); final byte[] random = getRandom(0.5, 100000);
final byte[] stream = new byte[HEADER_BYTES.length + 8 + random.length]; final byte[] stream = new byte[HEADER_BYTES.length + 8 + random.length];
System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length); System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length);
stream[10] = UNCOMPRESSED_DATA_FLAG; stream[10] = UNCOMPRESSED_DATA_FLAG;
int length = random.length + 4; int length = random.length + 4;
stream[11] = (byte) length; stream[11] = (byte) length;
stream[12] = (byte) (length >>> 8); stream[12] = (byte) (length >>> 8);
@ -260,16 +296,18 @@ public class SnappyFramedStreamTest {
} }
@Test @Test
public void testLargerFrames_compressed_() throws IOException { public void testLargerFrames_compressed_()
throws IOException
{
final byte[] random = getRandom(0.5, 500000); final byte[] random = getRandom(0.5, 500000);
final byte[] compressed = Snappy.compress(random); final byte[] compressed = Snappy.compress(random);
final byte[] stream = new byte[HEADER_BYTES.length + 8 + compressed.length]; final byte[] stream = new byte[HEADER_BYTES.length + 8 + compressed.length];
System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length); System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length);
stream[10] = COMPRESSED_DATA_FLAG; stream[10] = COMPRESSED_DATA_FLAG;
int length = compressed.length + 4; int length = compressed.length + 4;
stream[11] = (byte) length; stream[11] = (byte) length;
stream[12] = (byte) (length >>> 8); stream[12] = (byte) (length >>> 8);
@ -290,7 +328,8 @@ public class SnappyFramedStreamTest {
@Test @Test
public void testLargerFrames_compressed_smaller_raw_larger() public void testLargerFrames_compressed_smaller_raw_larger()
throws IOException { throws IOException
{
final byte[] random = getRandom(0.5, 100000); final byte[] random = getRandom(0.5, 100000);
final byte[] compressed = Snappy.compress(random); final byte[] compressed = Snappy.compress(random);
@ -300,7 +339,7 @@ public class SnappyFramedStreamTest {
System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length); System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length);
stream[10] = COMPRESSED_DATA_FLAG; stream[10] = COMPRESSED_DATA_FLAG;
int length = compressed.length + 4; int length = compressed.length + 4;
stream[11] = (byte) length; stream[11] = (byte) length;
stream[12] = (byte) (length >>> 8); stream[12] = (byte) (length >>> 8);
@ -319,19 +358,23 @@ public class SnappyFramedStreamTest {
assertArrayEquals(random, uncompressed); assertArrayEquals(random, uncompressed);
} }
private byte[] uncompressBlock(byte[] block) throws IOException { private byte[] uncompressBlock(byte[] block)
throws IOException
{
return uncompress(blockToStream(block)); return uncompress(blockToStream(block));
} }
private static byte[] blockToStream(byte[] block) { private static byte[] blockToStream(byte[] block)
{
byte[] stream = new byte[HEADER_BYTES.length + block.length]; byte[] stream = new byte[HEADER_BYTES.length + block.length];
System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length); System.arraycopy(HEADER_BYTES, 0, stream, 0, HEADER_BYTES.length);
System.arraycopy(block, 0, stream, HEADER_BYTES.length, block.length); System.arraycopy(block, 0, stream, HEADER_BYTES.length, block.length);
return stream; return stream;
} }
protected byte[] compress(byte[] original)
protected byte[] compress(byte[] original) throws IOException { throws IOException
{
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStream snappyOut = createOutputStream(out); OutputStream snappyOut = createOutputStream(out);
snappyOut.write(original); snappyOut.write(original);
@ -339,29 +382,35 @@ public class SnappyFramedStreamTest {
return out.toByteArray(); return out.toByteArray();
} }
protected byte[] uncompress(byte[] compressed) throws IOException { protected byte[] uncompress(byte[] compressed)
return toByteArray(createInputStream(new ByteArrayInputStream( throws IOException
{
return toByteArray(createInputStream(new ByteArrayInputStream(
compressed), true)); compressed), true));
} }
private static byte[] toByteArray(InputStream createInputStream) throws IOException { private static byte[] toByteArray(InputStream createInputStream)
throws IOException
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream(64 * 1024); final ByteArrayOutputStream baos = new ByteArrayOutputStream(64 * 1024);
final byte[] buffer = new byte[8 * 1024]; final byte[] buffer = new byte[8 * 1024];
int read; int read;
while((read = createInputStream.read(buffer)) > 0) { while ((read = createInputStream.read(buffer)) > 0) {
baos.write(buffer, 0, read); baos.write(buffer, 0, read);
} }
return baos.toByteArray(); return baos.toByteArray();
} }
static int toInt(byte value) { static int toInt(byte value)
{
return value & 0xFF; return value & 0xFF;
} }
private byte[] getRandom(double compressionRatio, int length) { private byte[] getRandom(double compressionRatio, int length)
{
RandomGenerator gen = new RandomGenerator( RandomGenerator gen = new RandomGenerator(
compressionRatio); compressionRatio);
gen.getNextPosition(length); gen.getNextPosition(length);
@ -369,5 +418,4 @@ public class SnappyFramedStreamTest {
assertEquals(random.length, length); assertEquals(random.length, length);
return random; return random;
} }
} }

View File

@ -1,145 +1,207 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// SnappyInputStreamTest.java // SnappyInputStreamTest.java
// Since: 2011/03/31 22:31:51 // Since: 2011/03/31 22:31:51
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
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 java.io.InputStream;
import org.junit.Test; import org.junit.Test;
import org.xerial.util.FileResource; import org.xerial.util.FileResource;
import org.xerial.util.log.Logger; import org.xerial.util.log.Logger;
public class SnappyInputStreamTest public class SnappyInputStreamTest
{ {
private static Logger _logger = Logger.getLogger(SnappyInputStreamTest.class); private static Logger _logger = Logger.getLogger(SnappyInputStreamTest.class);
public static byte[] readResourceFile(String fileName) throws IOException { public static byte[] readResourceFile(String fileName)
BufferedInputStream input = new BufferedInputStream(FileResource.find(SnappyOutputStreamTest.class, fileName) throws IOException
.openStream()); {
assertNotNull(input); BufferedInputStream input = new BufferedInputStream(FileResource.find(SnappyOutputStreamTest.class, fileName)
return readFully(input); .openStream());
} assertNotNull(input);
return readFully(input);
public static byte[] readFully(InputStream input) throws IOException { }
try {
ByteArrayOutputStream out = new ByteArrayOutputStream(); public static byte[] readFully(InputStream input)
byte[] buf = new byte[4096]; throws IOException
for (int readBytes = 0; (readBytes = input.read(buf)) != -1;) { {
out.write(buf, 0, readBytes); try {
} ByteArrayOutputStream out = new ByteArrayOutputStream();
out.flush(); byte[] buf = new byte[4096];
return out.toByteArray(); for (int readBytes = 0; (readBytes = input.read(buf)) != -1; ) {
} out.write(buf, 0, readBytes);
finally { }
input.close(); out.flush();
} return out.toByteArray();
} }
finally {
public static byte[] byteWiseReadFully(InputStream input) throws IOException { input.close();
ByteArrayOutputStream out = new ByteArrayOutputStream(); }
byte[] buf = new byte[4096]; }
for (int readData = 0; (readData = input.read()) != -1;) {
out.write(readData); public static byte[] byteWiseReadFully(InputStream input)
} throws IOException
out.flush(); {
return out.toByteArray(); ByteArrayOutputStream out = new ByteArrayOutputStream();
} byte[] buf = new byte[4096];
for (int readData = 0; (readData = input.read()) != -1; ) {
@Test out.write(readData);
public void read() throws Exception { }
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream(); out.flush();
SnappyOutputStream snappyOut = new SnappyOutputStream(compressedBuf); return out.toByteArray();
byte[] orig = readResourceFile("alice29.txt"); }
snappyOut.write(orig);
snappyOut.close(); @Test
byte[] compressed = compressedBuf.toByteArray(); public void read()
_logger.debug("compressed size: " + compressed.length); throws Exception
{
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed)); ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream();
byte[] uncompressed = readFully(in); SnappyOutputStream snappyOut = new SnappyOutputStream(compressedBuf);
byte[] orig = readResourceFile("alice29.txt");
assertEquals(orig.length, uncompressed.length); snappyOut.write(orig);
assertArrayEquals(orig, uncompressed); snappyOut.close();
byte[] compressed = compressedBuf.toByteArray();
} _logger.debug("compressed size: " + compressed.length);
@Test SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed));
public void readBlockCompressedData() throws Exception { byte[] uncompressed = readFully(in);
byte[] orig = readResourceFile("alice29.txt");
byte[] compressed = Snappy.compress(orig); assertEquals(orig.length, uncompressed.length);
assertArrayEquals(orig, uncompressed);
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed)); }
byte[] uncompressed = readFully(in);
@Test
assertEquals(orig.length, uncompressed.length); public void readBlockCompressedData()
assertArrayEquals(orig, uncompressed); throws Exception
} {
byte[] orig = readResourceFile("alice29.txt");
@Test byte[] compressed = Snappy.compress(orig);
public void biteWiseRead() throws Exception {
byte[] orig = readResourceFile("testdata/calgary/paper6"); SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed));
byte[] compressed = Snappy.compress(orig); byte[] uncompressed = readFully(in);
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed)); assertEquals(orig.length, uncompressed.length);
byte[] uncompressed = byteWiseReadFully(in); assertArrayEquals(orig, uncompressed);
}
assertEquals(orig.length, uncompressed.length);
assertArrayEquals(orig, uncompressed); @Test
public void biteWiseRead()
} throws Exception
{
@Test byte[] orig = readResourceFile("testdata/calgary/paper6");
public void available() throws Exception { byte[] compressed = Snappy.compress(orig);
byte[] orig = readResourceFile("testdata/calgary/paper6");
byte[] compressed = Snappy.compress(orig); SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed));
byte[] uncompressed = byteWiseReadFully(in);
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed));
byte[] buf = new byte[4]; assertEquals(orig.length, uncompressed.length);
for (int readBytes = 0; (readBytes = in.read(buf)) != -1;) { assertArrayEquals(orig, uncompressed);
assertTrue(in.available() >= 0); }
}
assertTrue(in.available() == 0); @Test
in.close(); public void available()
} throws Exception
{
@Test byte[] orig = readResourceFile("testdata/calgary/paper6");
public void emptyStream() throws Exception { byte[] compressed = Snappy.compress(orig);
try {
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(new byte[0])); SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed));
byte[] uncompressed = readFully(in); byte[] buf = new byte[4];
assertEquals(0, uncompressed.length); for (int readBytes = 0; (readBytes = in.read(buf)) != -1; ) {
fail("should not reach here"); assertTrue(in.available() >= 0);
} }
catch(SnappyIOException e) { assertTrue(in.available() == 0);
assertEquals(SnappyErrorCode.EMPTY_INPUT, e.getErrorCode()); in.close();
} }
}
@Test
} public void emptyStream()
throws Exception
{
try {
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(new byte[0]));
byte[] uncompressed = readFully(in);
assertEquals(0, uncompressed.length);
fail("should not reach here");
}
catch (SnappyIOException e) {
assertEquals(SnappyErrorCode.EMPTY_INPUT, e.getErrorCode());
}
}
public static byte[] compressResource(String resourcePath)
throws Exception
{
ByteArrayOutputStream compressedBuf = new ByteArrayOutputStream();
SnappyOutputStream snappyOut = new SnappyOutputStream(compressedBuf);
byte[] orig = readResourceFile(resourcePath);
snappyOut.write(orig);
snappyOut.close();
return compressedBuf.toByteArray();
}
@Test
public void chunkRead()
throws Exception
{
byte[] chunk1 = compressResource("alice29.txt");
byte[] chunk2 = compressResource("testdata/calgary/paper6");
byte[] concatenated = new byte[chunk1.length + chunk2.length];
System.arraycopy(chunk1, 0, concatenated, 0, chunk1.length);
System.arraycopy(chunk2, 0, concatenated, chunk1.length, chunk2.length);
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(concatenated));
byte[] uncompressed = readFully(in);
byte[] orig1 = readResourceFile("alice29.txt");
byte[] orig2 = readResourceFile("testdata/calgary/paper6");
assertEquals(orig1.length + orig2.length, uncompressed.length);
byte[] uncompressed1 = new byte[orig1.length];
byte[] uncompressed2 = new byte[orig2.length];
System.arraycopy(uncompressed, 0, uncompressed1, 0, orig1.length);
System.arraycopy(uncompressed, orig1.length, uncompressed2, 0, orig2.length);
assertArrayEquals(orig1, uncompressed1);
assertArrayEquals(orig2, uncompressed2);
}
@Test
public void readSnappyCompressResult()
throws Exception
{
byte[] orig = readResourceFile("alice29.txt");
byte[] compressed = Snappy.compress(orig);
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(compressed));
byte[] uncompressed = readFully(in);
assertArrayEquals(orig, uncompressed);
}
}

View File

@ -1,125 +1,137 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// XerialJ // XerialJ
// //
// SnappyLoaderTest.java // SnappyLoaderTest.java
// Since: 2011/06/22 23:59:47 // Since: 2011/06/22 23:59:47
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import org.codehaus.plexus.classworlds.ClassWorld; import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.junit.Test; import org.junit.Test;
import org.xerial.util.FileResource; import org.xerial.util.FileResource;
import org.xerial.util.log.Logger; import org.xerial.util.log.Logger;
import java.io.*; import java.io.*;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
public class SnappyLoaderTest public class SnappyLoaderTest
{ {
private static Logger _logger = Logger.getLogger(SnappyLoaderTest.class); private static Logger _logger = Logger.getLogger(SnappyLoaderTest.class);
public static BufferedInputStream openByteStream(Class< ? > referenceClass, String resourceFileName) public static BufferedInputStream openByteStream(Class<?> referenceClass, String resourceFileName)
throws IOException { throws IOException
URL url = FileResource.find(referenceClass, resourceFileName); {
if (url != null) { URL url = FileResource.find(referenceClass, resourceFileName);
return new BufferedInputStream(url.openStream()); if (url != null) {
} return new BufferedInputStream(url.openStream());
else }
return null; else {
} return null;
}
public static <T> String loadIntoString(Class<T> referenceClass, String path) throws IOException { }
BufferedInputStream in = openByteStream(referenceClass, path);
if (in == null) public static <T> String loadIntoString(Class<T> referenceClass, String path)
throw new FileNotFoundException( throws IOException
String.format("reference class:%s, path:%s", referenceClass.getName(), path)); {
BufferedInputStream in = openByteStream(referenceClass, path);
ByteArrayOutputStream buf = new ByteArrayOutputStream(); if (in == null) {
try { throw new FileNotFoundException(
byte[] tmp = new byte[4028]; String.format("reference class:%s, path:%s", referenceClass.getName(), path));
for (int readBytes = 0; (readBytes = in.read(tmp)) != -1;) { }
buf.write(tmp, 0, readBytes);
} ByteArrayOutputStream buf = new ByteArrayOutputStream();
buf.flush(); try {
return buf.toString(); byte[] tmp = new byte[4028];
} for (int readBytes = 0; (readBytes = in.read(tmp)) != -1; ) {
finally { buf.write(tmp, 0, readBytes);
in.close(); }
} buf.flush();
} return buf.toString();
}
@Test finally {
public void loadSnappyByDiffentClassloadersInTheSameJVM() throws Exception { in.close();
}
// Parent class loader cannot see Snappy.class }
ClassLoader parent = this.getClass().getClassLoader().getParent();
ClassWorld cw = new ClassWorld(); @Test
ClassRealm P = cw.newRealm("P", parent); public void loadSnappyByDiffentClassloadersInTheSameJVM()
try { throws Exception
P.loadClass("org.xerial.snappy.Snappy"); {
fail("org.xerial.snappy.Snappy is found in the parent");
} // Parent class loader cannot see Snappy.class
catch (ClassNotFoundException e) { ClassLoader parent = this.getClass().getClassLoader().getParent();
// OK ClassWorld cw = new ClassWorld();
} ClassRealm P = cw.newRealm("P", parent);
try {
// Prepare the child class loaders which can load Snappy.class P.loadClass("org.xerial.snappy.Snappy");
URL classPath = new File("target/classes").toURI().toURL(); fail("org.xerial.snappy.Snappy is found in the parent");
ClassRealm L1 = cw.newRealm("l1", URLClassLoader.newInstance(new URL[] { classPath }, parent)); }
ClassRealm L2 = cw.newRealm("l2", URLClassLoader.newInstance(new URL[] { classPath }, parent)); catch (ClassNotFoundException e) {
// OK
// Actually load Snappy.class in a child class loader }
Class< ? > S1 = L1.loadClass("org.xerial.snappy.Snappy"); // Prepare the child class loaders which can load Snappy.class
Method m = S1.getMethod("compress", String.class); URL classPath = new File("target/classes").toURI().toURL();
byte[] v = (byte[]) m.invoke(null, "hello world"); ClassRealm L1 = cw.newRealm("l1", URLClassLoader.newInstance(new URL[] {classPath}, parent));
ClassRealm L2 = cw.newRealm("l2", URLClassLoader.newInstance(new URL[] {classPath}, parent));
// Load Snappy.class from another child class loader
Class< ? > S2 = L2.loadClass("org.xerial.snappy.Snappy"); // Actually load Snappy.class in a child class loader
Method m2 = S2.getMethod("compress", String.class);
byte[] v2 = (byte[]) m2.invoke(null, "hello world"); Class<?> S1 = L1.loadClass("org.xerial.snappy.Snappy");
Method m = S1.getMethod("compress", String.class);
assertArrayEquals(v, v2); byte[] v = (byte[]) m.invoke(null, "hello world");
}
// Load Snappy.class from another child class loader
@Test Class<?> S2 = L2.loadClass("org.xerial.snappy.Snappy");
public void load() throws Exception { Method m2 = S2.getMethod("compress", String.class);
SnappyLoader.load(); byte[] v2 = (byte[]) m2.invoke(null, "hello world");
_logger.debug(Snappy.maxCompressedLength(1024));
} assertArrayEquals(v, v2);
}
@Test
public void autoLoad() throws Exception { @Test
_logger.debug(Snappy.maxCompressedLength(1024)); public void load()
} throws Exception
{
public static void main(String[] args) { SnappyLoader.load();
// Test for loading native library specified in -Djava.library.path _logger.debug(Snappy.maxCompressedLength(1024));
System.setProperty(SnappyLoader.KEY_SNAPPY_USE_SYSTEMLIB, "true"); }
_logger.debug(Snappy.maxCompressedLength(1024));
} @Test
} public void autoLoad()
throws Exception
{
_logger.debug(Snappy.maxCompressedLength(1024));
}
public static void main(String[] args)
{
// Test for loading native library specified in -Djava.library.path
System.setProperty(SnappyLoader.KEY_SNAPPY_USE_SYSTEMLIB, "true");
_logger.debug(Snappy.maxCompressedLength(1024));
}
}

View File

@ -29,8 +29,13 @@ import static org.junit.Assert.*;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import org.junit.Test; import org.junit.Test;
import org.xerial.snappy.buffer.BufferAllocatorFactory;
import org.xerial.snappy.buffer.CachedBufferAllocator;
import org.xerial.snappy.buffer.DefaultBufferAllocator;
import org.xerial.util.FileResource; import org.xerial.util.FileResource;
import org.xerial.util.log.Logger; import org.xerial.util.log.Logger;
@ -39,7 +44,9 @@ public class SnappyOutputStreamTest
private static Logger _logger = Logger.getLogger(SnappyOutputStreamTest.class); private static Logger _logger = Logger.getLogger(SnappyOutputStreamTest.class);
@Test @Test
public void test() throws Exception { public void test()
throws Exception
{
ByteArrayOutputStream buf = new ByteArrayOutputStream(); ByteArrayOutputStream buf = new ByteArrayOutputStream();
SnappyOutputStream sout = new SnappyOutputStream(buf); SnappyOutputStream sout = new SnappyOutputStream(buf);
@ -49,7 +56,7 @@ public class SnappyOutputStreamTest
ByteArrayOutputStream orig = new ByteArrayOutputStream(); ByteArrayOutputStream orig = new ByteArrayOutputStream();
byte[] tmp = new byte[1024]; byte[] tmp = new byte[1024];
for (int readBytes = 0; (readBytes = input.read(tmp)) != -1;) { for (int readBytes = 0; (readBytes = input.read(tmp)) != -1; ) {
sout.write(tmp, 0, readBytes); sout.write(tmp, 0, readBytes);
orig.write(tmp, 0, readBytes); // preserve the original data orig.write(tmp, 0, readBytes); // preserve the original data
} }
@ -63,7 +70,7 @@ public class SnappyOutputStreamTest
ByteArrayOutputStream decompressed = new ByteArrayOutputStream(); ByteArrayOutputStream decompressed = new ByteArrayOutputStream();
byte[] compressed = buf.toByteArray(); byte[] compressed = buf.toByteArray();
// decompress // decompress
for (int cursor = SnappyCodec.headerSize(); cursor < compressed.length;) { for (int cursor = SnappyCodec.headerSize(); cursor < compressed.length; ) {
int chunkSize = SnappyOutputStream.readInt(compressed, cursor); int chunkSize = SnappyOutputStream.readInt(compressed, cursor);
cursor += 4; cursor += 4;
byte[] tmpOut = new byte[Snappy.uncompressedLength(compressed, cursor, chunkSize)]; byte[] tmpOut = new byte[Snappy.uncompressedLength(compressed, cursor, chunkSize)];
@ -78,7 +85,9 @@ public class SnappyOutputStreamTest
} }
@Test @Test
public void bufferSize() throws Exception { public void bufferSize()
throws Exception
{
ByteArrayOutputStream b = new ByteArrayOutputStream(); ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b, 1500); SnappyOutputStream os = new SnappyOutputStream(b, 1500);
final int bytesToWrite = 5000; final int bytesToWrite = 5000;
@ -91,18 +100,21 @@ public class SnappyOutputStreamTest
os.close(); os.close();
SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray())); SnappyInputStream is = new SnappyInputStream(new ByteArrayInputStream(b.toByteArray()));
byte[] buf = new byte[bytesToWrite / 101]; byte[] buf = new byte[bytesToWrite / 101];
while (is.read(buf) != -1) {} while (is.read(buf) != -1) {
}
is.close(); is.close();
} }
@Test @Test
public void smallWrites() throws Exception { public void smallWrites()
throws Exception
{
byte[] orig = CalgaryTest.readFile("alice29.txt"); byte[] orig = CalgaryTest.readFile("alice29.txt");
ByteArrayOutputStream b = new ByteArrayOutputStream(); ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream out = new SnappyOutputStream(b); SnappyOutputStream out = new SnappyOutputStream(b);
for(byte c : orig) { for (byte c : orig) {
out.write(c); out.write(c);
} }
out.close(); out.close();
@ -111,15 +123,149 @@ public class SnappyOutputStreamTest
byte[] decompressed = new byte[orig.length]; byte[] decompressed = new byte[orig.length];
int cursor = 0; int cursor = 0;
int readLen = 0; int readLen = 0;
for(int i=0; i < decompressed.length && (readLen = is.read(decompressed, i, decompressed.length-i)) != -1; ) { for (int i = 0; i < decompressed.length && (readLen = is.read(decompressed, i, decompressed.length - i)) != -1; ) {
i += readLen; i += readLen;
} }
is.close(); is.close();
assertArrayEquals(orig, decompressed); assertArrayEquals(orig, decompressed);
} }
/**
* Compress the input array by passing it chunk-by-chunk to a SnappyOutputStream.
*
* @param orig the data to compress
* @param maxChunkSize the maximum chunk size, in bytes.
* @return the compressed bytes
*/
private static byte[] compressAsChunks(byte[] orig, int maxChunkSize)
throws Exception
{
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream out = new SnappyOutputStream(b);
int remaining = orig.length;
for (int start = 0; start < orig.length; start += maxChunkSize) {
out.write(orig, start, remaining < maxChunkSize ? remaining : maxChunkSize);
remaining -= maxChunkSize;
}
out.close();
return b.toByteArray();
}
@Test @Test
public void longArrayCompress() throws Exception { public void batchingOfWritesShouldNotAffectCompressedDataSize()
throws Exception
{
// Regression test for issue #100, a bug where the size of compressed data could be affected
// by the batching of writes to the SnappyOutputStream rather than the total amount of data
// written to the stream.
byte[] orig = CalgaryTest.readFile("alice29.txt");
// Compress the data once so that we know the expected size:
byte[] expectedCompressedData = compressAsChunks(orig, Integer.MAX_VALUE);
// Hardcoding an expected compressed size here will catch regressions that lower the
// compression quality:
assertEquals(91013, expectedCompressedData.length);
// The chunk size should not affect the size of the compressed output:
int[] chunkSizes = new int[] {1, 100, 1023, 1024, 10000};
for (int chunkSize : chunkSizes) {
byte[] compressedData = compressAsChunks(orig, chunkSize);
assertEquals(String.format("when chunk size = %,d", chunkSize), expectedCompressedData.length, compressedData.length);
assertArrayEquals(expectedCompressedData, compressedData);
}
}
@Test
public void closeShouldBeIdempotent()
throws Exception
{
// Regression test for issue #107, a bug where close() was non-idempotent and would release
// its buffers to the allocator multiple times, which could cause scenarios where two open
// SnappyOutputStreams could share the same buffers, leading to stream corruption issues.
final BufferAllocatorFactory bufferAllocatorFactory = CachedBufferAllocator.getBufferAllocatorFactory();
final int BLOCK_SIZE = 4096;
// Create a stream, use it, then close it once:
ByteArrayOutputStream ba1 = new ByteArrayOutputStream();
SnappyOutputStream os1 = new SnappyOutputStream(ba1, BLOCK_SIZE, bufferAllocatorFactory);
os1.write(42);
os1.close();
// Create a new output stream, which should end up re-using the first stream's freed buffers
ByteArrayOutputStream ba2 = new ByteArrayOutputStream();
SnappyOutputStream os2 = new SnappyOutputStream(ba2, BLOCK_SIZE, bufferAllocatorFactory);
// Close the first stream a second time, which is supposed to be safe due to idempotency:
os1.close();
// Allocate a third output stream, which is supposed to get its own fresh set of buffers:
ByteArrayOutputStream ba3 = new ByteArrayOutputStream();
SnappyOutputStream os3 = new SnappyOutputStream(ba3, BLOCK_SIZE, bufferAllocatorFactory);
// Since the second and third streams should have distinct sets of buffers, writes to these
// streams should not interfere with one another:
os2.write(2);
os3.write(3);
os2.close();
os3.close();
SnappyInputStream in2 = new SnappyInputStream(new ByteArrayInputStream(ba2.toByteArray()));
assertEquals(2, in2.read());
in2.close();
SnappyInputStream in3 = new SnappyInputStream(new ByteArrayInputStream(ba3.toByteArray()));
assertEquals(3, in3.read());
in3.close();
}
@Test
public void writingToClosedStreamShouldThrowIOException()
throws IOException
{
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
os.close();
try {
os.write(4);
fail("Expected write() to throw IOException");
}
catch (IOException e) {
// Expected exception
}
try {
os.write(new int[] {1, 2, 3, 4});
fail("Expected write() to throw IOException");
}
catch (IOException e) {
// Expected exception
}
}
@Test
public void flushingClosedStreamShouldThrowIOException()
throws IOException
{
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b);
os.close();
try {
os.flush();
}
catch (IOException e) {
// Expected exception
}
}
@Test
public void closingStreamShouldMakeBuffersEligibleForGarbageCollection()
throws IOException
{
ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b, 4095, DefaultBufferAllocator.factory);
WeakReference<byte[]> inputBuffer = new WeakReference<byte[]>(os.inputBuffer);
WeakReference<byte[]> outputBuffer = new WeakReference<byte[]>(os.inputBuffer);
os.close();
System.gc();
assertNull(inputBuffer.get());
assertNull(outputBuffer.get());
}
@Test
public void longArrayCompress()
throws Exception
{
long[] l = new long[10]; long[] l = new long[10];
for (int i = 0; i < l.length; ++i) { for (int i = 0; i < l.length; ++i) {
l[i] = i % 3 + i * 11; l[i] = i % 3 + i * 11;
@ -137,15 +283,16 @@ public class SnappyOutputStreamTest
assertEquals(10 * 8, readBytes); assertEquals(10 * 8, readBytes);
assertArrayEquals(l, l2); assertArrayEquals(l, l2);
} }
@Test @Test
public void writeDoubleArray() throws Exception { public void writeDoubleArray()
throws Exception
{
ByteArrayOutputStream b = new ByteArrayOutputStream(); ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b); SnappyOutputStream os = new SnappyOutputStream(b);
double[] orig = new double[] { 1.0, 2.0, 1.4, 0.00343430014, -4.4, 4e-20 }; double[] orig = new double[] {1.0, 2.0, 1.4, 0.00343430014, -4.4, 4e-20};
os.write(orig); os.write(orig);
os.close(); os.close();
@ -158,11 +305,13 @@ public class SnappyOutputStreamTest
} }
@Test @Test
public void writeFloatArray() throws Exception { public void writeFloatArray()
throws Exception
{
ByteArrayOutputStream b = new ByteArrayOutputStream(); ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b); SnappyOutputStream os = new SnappyOutputStream(b);
float[] orig = new float[] { 1.0f, 2.0f, 1.4f, 0.00343430014f, -4.4f, 4e-20f }; float[] orig = new float[] {1.0f, 2.0f, 1.4f, 0.00343430014f, -4.4f, 4e-20f};
os.write(orig); os.write(orig);
os.close(); os.close();
@ -175,11 +324,13 @@ public class SnappyOutputStreamTest
} }
@Test @Test
public void writeIntArray() throws Exception { public void writeIntArray()
throws Exception
{
ByteArrayOutputStream b = new ByteArrayOutputStream(); ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b); SnappyOutputStream os = new SnappyOutputStream(b);
int[] orig = new int[] { 0, -1, -34, 43, 234, 34324, -234 }; int[] orig = new int[] {0, -1, -34, 43, 234, 34324, -234};
os.write(orig); os.write(orig);
os.close(); os.close();
@ -192,11 +343,13 @@ public class SnappyOutputStreamTest
} }
@Test @Test
public void writeShortArray() throws Exception { public void writeShortArray()
throws Exception
{
ByteArrayOutputStream b = new ByteArrayOutputStream(); ByteArrayOutputStream b = new ByteArrayOutputStream();
SnappyOutputStream os = new SnappyOutputStream(b); SnappyOutputStream os = new SnappyOutputStream(b);
short[] orig = new short[] { 0, -1, -34, 43, 234, 324, -234 }; short[] orig = new short[] {0, -1, -34, 43, 234, 324, -234};
os.write(orig); os.write(orig);
os.close(); os.close();
@ -207,5 +360,4 @@ public class SnappyOutputStreamTest
assertArrayEquals(orig, uncompressed); assertArrayEquals(orig, uncompressed);
} }
} }

View File

@ -1,304 +1,332 @@
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
* Copyright 2011 Taro L. Saito * Copyright 2011 Taro L. Saito
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*--------------------------------------------------------------------------*/ *--------------------------------------------------------------------------*/
//-------------------------------------- //--------------------------------------
// snappy-java Project // snappy-java Project
// //
// SnappyTest.java // SnappyTest.java
// Since: 2011/03/30 // Since: 2011/03/30
// //
// $URL$ // $URL$
// $Author$ // $Author$
//-------------------------------------- //--------------------------------------
package org.xerial.snappy; package org.xerial.snappy;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.xerial.util.log.Logger; import org.xerial.util.log.Logger;
public class SnappyTest public class SnappyTest
{ {
private static Logger _logger = Logger.getLogger(SnappyTest.class); private static Logger _logger = Logger.getLogger(SnappyTest.class);
@Test @Test
public void getVersion() throws Exception { public void getVersion()
String version = Snappy.getNativeLibraryVersion(); throws Exception
_logger.debug("version: " + version); {
} String version = Snappy.getNativeLibraryVersion();
_logger.debug("version: " + version);
@Test }
public void directBufferCheck() throws Exception {
@Test
try { public void directBufferCheck()
ByteBuffer src = ByteBuffer.allocate(1024); throws Exception
src.put("hello world".getBytes()); {
src.flip();
ByteBuffer dest = ByteBuffer.allocate(1024); try {
int maxCompressedLen = Snappy.compress(src, dest); ByteBuffer src = ByteBuffer.allocate(1024);
} src.put("hello world".getBytes());
catch (SnappyError e) { src.flip();
Assert.assertTrue(e.errorCode == SnappyErrorCode.NOT_A_DIRECT_BUFFER); ByteBuffer dest = ByteBuffer.allocate(1024);
return; int maxCompressedLen = Snappy.compress(src, dest);
} }
catch (SnappyError e) {
fail("shouldn't reach here"); Assert.assertTrue(e.errorCode == SnappyErrorCode.NOT_A_DIRECT_BUFFER);
return;
} }
@Test fail("shouldn't reach here");
public void directBuffer() throws Exception { }
StringBuilder s = new StringBuilder(); @Test
for (int i = 0; i < 20; ++i) { public void directBuffer()
s.append("Hello world!"); throws Exception
} {
String origStr = s.toString();
byte[] orig = origStr.getBytes(); StringBuilder s = new StringBuilder();
int BUFFER_SIZE = orig.length; for (int i = 0; i < 20; ++i) {
ByteBuffer src = ByteBuffer.allocateDirect(orig.length); s.append("Hello world!");
src.put(orig); }
src.flip(); String origStr = s.toString();
_logger.debug("input size: " + src.remaining()); byte[] orig = origStr.getBytes();
int maxCompressedLen = Snappy.maxCompressedLength(src.remaining()); int BUFFER_SIZE = orig.length;
_logger.debug("max compressed length:" + maxCompressedLen); ByteBuffer src = ByteBuffer.allocateDirect(orig.length);
src.put(orig);
ByteBuffer compressed = ByteBuffer.allocateDirect(maxCompressedLen); src.flip();
int compressedSize = Snappy.compress(src, compressed); _logger.debug("input size: " + src.remaining());
_logger.debug("compressed length: " + compressedSize); int maxCompressedLen = Snappy.maxCompressedLength(src.remaining());
_logger.debug("max compressed length:" + maxCompressedLen);
assertTrue(Snappy.isValidCompressedBuffer(compressed));
ByteBuffer compressed = ByteBuffer.allocateDirect(maxCompressedLen);
assertEquals(0, src.position()); int compressedSize = Snappy.compress(src, compressed);
assertEquals(orig.length, src.remaining()); _logger.debug("compressed length: " + compressedSize);
assertEquals(orig.length, src.limit());
assertTrue(Snappy.isValidCompressedBuffer(compressed));
assertEquals(0, compressed.position());
assertEquals(compressedSize, compressed.limit()); assertEquals(0, src.position());
assertEquals(compressedSize, compressed.remaining()); assertEquals(orig.length, src.remaining());
assertEquals(orig.length, src.limit());
int uncompressedLen = Snappy.uncompressedLength(compressed);
_logger.debug("uncompressed length: " + uncompressedLen); assertEquals(0, compressed.position());
ByteBuffer extract = ByteBuffer.allocateDirect(uncompressedLen); assertEquals(compressedSize, compressed.limit());
int uncompressedLen2 = Snappy.uncompress(compressed, extract); assertEquals(compressedSize, compressed.remaining());
assertEquals(uncompressedLen, uncompressedLen2);
assertEquals(uncompressedLen, extract.remaining()); int uncompressedLen = Snappy.uncompressedLength(compressed);
_logger.debug("uncompressed length: " + uncompressedLen);
byte[] b = new byte[uncompressedLen]; ByteBuffer extract = ByteBuffer.allocateDirect(uncompressedLen);
extract.get(b); int uncompressedLen2 = Snappy.uncompress(compressed, extract);
String decompressed = new String(b); assertEquals(uncompressedLen, uncompressedLen2);
_logger.debug(decompressed); assertEquals(uncompressedLen, extract.remaining());
assertEquals(origStr, decompressed); byte[] b = new byte[uncompressedLen];
} extract.get(b);
String decompressed = new String(b);
@Test _logger.debug(decompressed);
public void bufferOffset() throws Exception {
assertEquals(origStr, decompressed);
String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA"; }
byte[] orig = m.getBytes();
final int offset = 100; @Test
ByteBuffer input = ByteBuffer.allocateDirect(orig.length + offset); public void bufferOffset()
input.position(offset); throws Exception
input.put(orig); {
input.flip();
input.position(offset); String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA";
byte[] orig = m.getBytes();
// compress final int offset = 100;
int maxCompressedLength = Snappy.maxCompressedLength(input.remaining()); ByteBuffer input = ByteBuffer.allocateDirect(orig.length + offset);
final int offset2 = 40; input.position(offset);
ByteBuffer compressed = ByteBuffer.allocateDirect(maxCompressedLength + offset2); input.put(orig);
compressed.position(offset2); input.flip();
Snappy.compress(input, compressed); input.position(offset);
assertTrue(Snappy.isValidCompressedBuffer(compressed));
// compress
// uncompress int maxCompressedLength = Snappy.maxCompressedLength(input.remaining());
final int offset3 = 80; final int offset2 = 40;
int uncompressedLength = Snappy.uncompressedLength(compressed); ByteBuffer compressed = ByteBuffer.allocateDirect(maxCompressedLength + offset2);
ByteBuffer uncompressed = ByteBuffer.allocateDirect(uncompressedLength + offset3); compressed.position(offset2);
uncompressed.position(offset3); Snappy.compress(input, compressed);
Snappy.uncompress(compressed, uncompressed); assertTrue(Snappy.isValidCompressedBuffer(compressed));
assertEquals(offset3, uncompressed.position());
assertEquals(offset3 + uncompressedLength, uncompressed.limit()); // uncompress
assertEquals(uncompressedLength, uncompressed.remaining()); final int offset3 = 80;
int uncompressedLength = Snappy.uncompressedLength(compressed);
// extract string ByteBuffer uncompressed = ByteBuffer.allocateDirect(uncompressedLength + offset3);
byte[] recovered = new byte[uncompressedLength]; uncompressed.position(offset3);
uncompressed.get(recovered); Snappy.uncompress(compressed, uncompressed);
String m2 = new String(recovered); assertEquals(offset3, uncompressed.position());
assertEquals(offset3 + uncompressedLength, uncompressed.limit());
assertEquals(m, m2); assertEquals(uncompressedLength, uncompressed.remaining());
}
// extract string
@Test byte[] recovered = new byte[uncompressedLength];
public void byteArrayCompress() throws Exception { uncompressed.get(recovered);
String m2 = new String(recovered);
String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA";
byte[] input = m.getBytes(); assertEquals(m, m2);
byte[] output = new byte[Snappy.maxCompressedLength(input.length)]; }
int compressedSize = Snappy.compress(input, 0, input.length, output, 0);
byte[] uncompressed = new byte[input.length]; @Test
public void byteArrayCompress()
assertTrue(Snappy.isValidCompressedBuffer(output, 0, compressedSize)); throws Exception
int uncompressedSize = Snappy.uncompress(output, 0, compressedSize, uncompressed, 0); {
String m2 = new String(uncompressed);
assertEquals(m, m2); String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA";
byte[] input = m.getBytes();
} byte[] output = new byte[Snappy.maxCompressedLength(input.length)];
int compressedSize = Snappy.compress(input, 0, input.length, output, 0);
@Test byte[] uncompressed = new byte[input.length];
public void rangeCheck() throws Exception {
String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA"; assertTrue(Snappy.isValidCompressedBuffer(output, 0, compressedSize));
byte[] input = m.getBytes(); int uncompressedSize = Snappy.uncompress(output, 0, compressedSize, uncompressed, 0);
byte[] output = new byte[Snappy.maxCompressedLength(input.length)]; String m2 = new String(uncompressed);
int compressedSize = Snappy.compress(input, 0, input.length, output, 0); assertEquals(m, m2);
}
assertTrue(Snappy.isValidCompressedBuffer(output, 0, compressedSize));
// Intentionally set an invalid range @Test
assertFalse(Snappy.isValidCompressedBuffer(output, 0, compressedSize + 1)); public void rangeCheck()
assertFalse(Snappy.isValidCompressedBuffer(output, 1, compressedSize)); throws Exception
{
// Test the ByteBuffer API String m = "ACCAGGGGGGGGGGGGGGGGGGGGATAGATATTTCCCGAGATATTTTATATAAAAAAA";
ByteBuffer bin = ByteBuffer.allocateDirect(input.length); byte[] input = m.getBytes();
bin.put(input); byte[] output = new byte[Snappy.maxCompressedLength(input.length)];
bin.flip(); int compressedSize = Snappy.compress(input, 0, input.length, output, 0);
ByteBuffer bout = ByteBuffer.allocateDirect(Snappy.maxCompressedLength(bin.remaining()));
int compressedSize2 = Snappy.compress(bin, bout); assertTrue(Snappy.isValidCompressedBuffer(output, 0, compressedSize));
assertEquals(compressedSize, compressedSize2); // Intentionally set an invalid range
assertFalse(Snappy.isValidCompressedBuffer(output, 0, compressedSize + 1));
assertTrue(Snappy.isValidCompressedBuffer(bout)); assertFalse(Snappy.isValidCompressedBuffer(output, 1, compressedSize));
// Intentionally set an invalid range
bout.limit(bout.limit() + 1); // Test the ByteBuffer API
assertFalse(Snappy.isValidCompressedBuffer(bout)); ByteBuffer bin = ByteBuffer.allocateDirect(input.length);
bout.limit(bout.limit() - 1); bin.put(input);
bout.position(1); bin.flip();
assertFalse(Snappy.isValidCompressedBuffer(bout)); ByteBuffer bout = ByteBuffer.allocateDirect(Snappy.maxCompressedLength(bin.remaining()));
int compressedSize2 = Snappy.compress(bin, bout);
} assertEquals(compressedSize, compressedSize2);
@Test assertTrue(Snappy.isValidCompressedBuffer(bout));
public void highLevelAPI() throws Exception { // Intentionally set an invalid range
bout.limit(bout.limit() + 1);
String m = "Hello! 01234 ACGDSFSDFJ World. FDSDF02394234 fdsfda03924"; assertFalse(Snappy.isValidCompressedBuffer(bout));
byte[] input = m.getBytes(); bout.limit(bout.limit() - 1);
byte[] output = Snappy.compress(input); bout.position(1);
assertFalse(Snappy.isValidCompressedBuffer(bout));
byte[] uncompressed = Snappy.uncompress(output); }
String m2 = new String(uncompressed);
assertEquals(m, m2); @Test
} public void highLevelAPI()
throws Exception
@Test {
public void lowLevelAPI() throws Exception {
String m = "Hello! 01234 ACGDSFSDFJ World. FDSDF02394234 fdsfda03924";
String m = "Hello! 01234 ACGDSFSDFJ World. FDSDF02394234 fdsfda03924"; byte[] input = m.getBytes();
byte[] input = m.getBytes(); byte[] output = Snappy.compress(input);
byte[] output = Snappy.rawCompress(input, input.length);
byte[] uncompressed = Snappy.uncompress(output);
byte[] uncompressed = Snappy.uncompress(output); String m2 = new String(uncompressed);
String m2 = new String(uncompressed); assertEquals(m, m2);
assertEquals(m, m2); }
}
@Test
@Test public void lowLevelAPI()
public void simpleUsage() throws Exception { throws Exception
{
String input = "Hello snappy-java! Snappy-java is a JNI-based wrapper"
+ " for using Snappy from Google (written in C++), a fast compresser/decompresser."; String m = "Hello! 01234 ACGDSFSDFJ World. FDSDF02394234 fdsfda03924";
byte[] compressed = Snappy.compress(input.getBytes("UTF-8")); byte[] input = m.getBytes();
byte[] uncompressed = Snappy.uncompress(compressed); byte[] output = Snappy.rawCompress(input, input.length);
String result = new String(uncompressed, "UTF-8");
_logger.debug(result); byte[] uncompressed = Snappy.uncompress(output);
String m2 = new String(uncompressed);
} assertEquals(m, m2);
}
@Test
public void floatArray() throws Exception { @Test
float[] data = new float[] { 1.0f, -0.3f, 1.3f, 234.4f, 34 }; public void simpleUsage()
byte[] compressed = Snappy.compress(data); throws Exception
float[] result = Snappy.uncompressFloatArray(compressed); {
assertArrayEquals(data, result, 0.0f);
} String input = "Hello snappy-java! Snappy-java is a JNI-based wrapper"
+ " for using Snappy from Google (written in C++), a fast compresser/decompresser.";
@Test byte[] compressed = Snappy.compress(input.getBytes("UTF-8"));
public void doubleArray() throws Exception { byte[] uncompressed = Snappy.uncompress(compressed);
double[] data = new double[] { 1.0, -0.3, 1.3, 234.4, 34 }; String result = new String(uncompressed, "UTF-8");
byte[] compressed = Snappy.compress(data); _logger.debug(result);
double[] result = Snappy.uncompressDoubleArray(compressed); }
assertArrayEquals(data, result, 0.0f);
} @Test
public void floatArray()
@Test throws Exception
public void longArray() throws Exception { {
long[] data = new long[] { 2, 3, 15, 4234, 43251531412342342L, 23423422342L }; float[] data = new float[] {1.0f, -0.3f, 1.3f, 234.4f, 34};
byte[] compressed = Snappy.compress(data); byte[] compressed = Snappy.compress(data);
long[] result = Snappy.uncompressLongArray(compressed); float[] result = Snappy.uncompressFloatArray(compressed);
assertArrayEquals(data, result); assertArrayEquals(data, result, 0.0f);
} }
@Test @Test
public void shortArray() throws Exception { public void doubleArray()
short[] data = new short[] { 432, -32267, 1, 3, 34, 43, 34, Short.MAX_VALUE, -1 }; throws Exception
byte[] compressed = Snappy.compress(data); {
short[] result = Snappy.uncompressShortArray(compressed); double[] data = new double[] {1.0, -0.3, 1.3, 234.4, 34};
assertArrayEquals(data, result); byte[] compressed = Snappy.compress(data);
} double[] result = Snappy.uncompressDoubleArray(compressed);
assertArrayEquals(data, result, 0.0f);
@Test }
public void intArray() throws Exception {
int[] data = new int[] { 432, -32267, 1, 3, 34, 43, 34, Short.MAX_VALUE, -1, Integer.MAX_VALUE, 3424, 43 }; @Test
byte[] compressed = Snappy.compress(data); public void longArray()
int[] result = Snappy.uncompressIntArray(compressed); throws Exception
assertArrayEquals(data, result); {
} long[] data = new long[] {2, 3, 15, 4234, 43251531412342342L, 23423422342L};
byte[] compressed = Snappy.compress(data);
@Test long[] result = Snappy.uncompressLongArray(compressed);
public void charArray() throws Exception { assertArrayEquals(data, result);
char[] data = new char[] { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!' }; }
byte[] compressed = Snappy.compress(data);
char[] result = Snappy.uncompressCharArray(compressed); @Test
assertArrayEquals(data, result); public void shortArray()
} throws Exception
{
@Test short[] data = new short[] {432, -32267, 1, 3, 34, 43, 34, Short.MAX_VALUE, -1};
public void string() throws Exception { byte[] compressed = Snappy.compress(data);
String s = "Hello Snappy! Snappy! Snappy!"; short[] result = Snappy.uncompressShortArray(compressed);
byte[] compressed = Snappy.compress(s); assertArrayEquals(data, result);
String uncompressedString = Snappy.uncompressString(compressed); }
assertEquals(s, uncompressedString);
} @Test
public void intArray()
@Test throws Exception
public void isValidCompressedData() throws Exception { {
int[] data = new int[] {432, -32267, 1, 3, 34, 43, 34, Short.MAX_VALUE, -1, Integer.MAX_VALUE, 3424, 43};
byte[] b = new byte[] { (byte) 91, (byte) 34, (byte) 80, (byte) 73, (byte) 34, (byte) 93 }; byte[] compressed = Snappy.compress(data);
int[] result = Snappy.uncompressIntArray(compressed);
assertFalse(Snappy.isValidCompressedBuffer(b)); assertArrayEquals(data, result);
}
try {
byte[] uncompressed = Snappy.uncompress(b); @Test
fail("cannot reach here since the input is invalid data"); public void charArray()
} throws Exception
catch (IOException e) { {
_logger.debug(e); char[] data = new char[] {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', '!'};
} byte[] compressed = Snappy.compress(data);
char[] result = Snappy.uncompressCharArray(compressed);
} assertArrayEquals(data, result);
}
}
@Test
public void string()
throws Exception
{
String s = "Hello Snappy! Snappy! Snappy!";
byte[] compressed = Snappy.compress(s);
String uncompressedString = Snappy.uncompressString(compressed);
assertEquals(s, uncompressedString);
}
@Test
public void isValidCompressedData()
throws Exception
{
byte[] b = new byte[] {(byte) 91, (byte) 34, (byte) 80, (byte) 73, (byte) 34, (byte) 93};
assertFalse(Snappy.isValidCompressedBuffer(b));
try {
byte[] uncompressed = Snappy.uncompress(b);
fail("cannot reach here since the input is invalid data");
}
catch (IOException e) {
_logger.debug(e);
}
}
}

View File

@ -1,2 +1 @@
version in ThisBuild := "1.1.1.7-SNAPSHOT" version in ThisBuild := "1.1.2-SNAPSHOT"