Skip to content

Commit

Permalink
Merge 2803df7 into 49c3f66
Browse files Browse the repository at this point in the history
  • Loading branch information
sjamesr committed Jan 1, 2020
2 parents 49c3f66 + 2803df7 commit ae13d94
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 185 deletions.
48 changes: 48 additions & 0 deletions src/main/java/au/com/southsky/jfreesane/ByteStreams.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package au.com.southsky.jfreesane;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

final class ByteStreams {
private static final int COPY_BUF_SIZE = 8192;

private ByteStreams() {}

/**
* A stand-in for {@code InputStream.readAllBytes} available in Java 9+. We currently support Java
* 8, so this is what we have to do.
*/
static int readAllBytes(InputStream in, byte[] dst) throws IOException {
int pos = 0;
while (pos < dst.length) {
int r = in.read(dst, pos, dst.length - pos);
if (r == -1) {
return pos;
}

pos += r;
}

return pos;
}

/**
* Copies up to maxBytes from src to dst, returning how many were copied.
*/
static int copy(InputStream src, OutputStream dst, int maxBytes) throws IOException {
byte[] buf = new byte[Math.min(maxBytes, COPY_BUF_SIZE)];
int total = 0;

while (total < maxBytes) {
int r = src.read(buf, 0, Math.min(maxBytes - total, COPY_BUF_SIZE));
if (r == -1) {
break;
}
dst.write(buf, 0, r);
total += r;
}

return total;
}
}
16 changes: 2 additions & 14 deletions src/main/java/au/com/southsky/jfreesane/FrameReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.common.base.MoreObjects;
import com.google.common.io.ByteStreams;
import com.google.common.primitives.UnsignedInteger;

/**
* Represents a reader of {@link Frame frames}.
*/
Expand Down Expand Up @@ -116,20 +112,12 @@ private int readRecord(OutputStream destination) throws IOException, SaneExcepti
return -1;
}

if (UnsignedInteger.fromIntBits(length).longValue() > Integer.MAX_VALUE) {
if (Integer.toUnsignedLong(length) > Integer.MAX_VALUE) {
throw new IllegalStateException("TODO: support massive records");
}

int bytesRead = (int) ByteStreams.copy(ByteStreams.limit(inputStream, length), destination);
int bytesRead = ByteStreams.copy(inputStream, destination, length);
log.log(Level.FINE, "Read a record of {0} bytes", bytesRead);
return bytesRead;
}

@Override
public String toString() {
return MoreObjects.toStringHelper(FrameReader.class)
.add("isBigEndian", bigEndian)
.add("parameters", parameters)
.toString();
}
}
12 changes: 4 additions & 8 deletions src/main/java/au/com/southsky/jfreesane/OptionGroup.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package au.com.southsky.jfreesane;

import java.util.ArrayList;
import java.util.List;

import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;

/**
* Represents a group of options. The SANE backend may group options together. These may be handy
* if, for example, a JFreeSane user wants to present the options to the user in logical groups.
Expand All @@ -15,7 +11,7 @@
*/
public class OptionGroup {
private final String title;
private List<SaneOption> options = Lists.newArrayList();
private List<SaneOption> options = new ArrayList<>();

public OptionGroup(String title) {
this.title = title;
Expand All @@ -33,7 +29,7 @@ public OptionValueType getValueType() {
* Returns an immutable copy of the options in this group.
*/
public List<SaneOption> getOptions() {
return ImmutableList.copyOf(options);
return new ArrayList<>(options);
}

/**
Expand All @@ -46,6 +42,6 @@ void addOption(SaneOption option) {

@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("title", title).add("options", options).toString();
return "OptionGroup{" + "title='" + title + '\'' + ", options=" + options + '}';
}
}
43 changes: 43 additions & 0 deletions src/main/java/au/com/southsky/jfreesane/Preconditions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package au.com.southsky.jfreesane;

final class Preconditions {
private Preconditions() {}

static void checkState(boolean state, String message, Object... args) {
if (!state) {
throw new IllegalStateException(String.format(message, args));
}
}

static void checkState(boolean state, String message) {
if (!state) {
throw new IllegalStateException(message);
}
}

static void checkState(boolean state) {
if (!state) {
throw new IllegalStateException();
}
}

static void checkArgument(boolean arg) {
if (!arg) {
throw new IllegalArgumentException();
}
}

static void checkArgument(boolean arg, String message, Object... args) {
if (!arg) {
throw new IllegalArgumentException(String.format(message, args));
}
}

static <T> T checkNotNull(T obj) {
if (obj == null) {
throw new NullPointerException();
}

return obj;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package au.com.southsky.jfreesane;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.google.common.collect.Maps;

/**
* A static factory of listeners that limit the rate at which they send
* {@link ScanListener#recordRead} notifications. The primary purpose of this class is to allow
Expand Down Expand Up @@ -48,7 +47,7 @@ public static ScanListener noMoreFrequentlyThan(
final ScanListener listener, final long time, final TimeUnit timeUnit) {
return new ScanListener() {
// Most users will only scan from one device at a time.
private Map<SaneDevice, Long> lastSentTime = Maps.newHashMapWithExpectedSize(1);
private Map<SaneDevice, Long> lastSentTime = new HashMap<>(1);

@Override
public void scanningStarted(SaneDevice device) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package au.com.southsky.jfreesane;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.HashBasedTable;
Expand All @@ -14,6 +13,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
Expand Down Expand Up @@ -48,7 +48,7 @@ public SaneClientAuthentication(final String path) {
new CharSource() {
@Override
public Reader openStream() throws IOException {
return new InputStreamReader(new FileInputStream(path), Charsets.US_ASCII);
return new InputStreamReader(new FileInputStream(path), StandardCharsets.US_ASCII);
}
});
}
Expand Down
40 changes: 15 additions & 25 deletions src/main/java/au/com/southsky/jfreesane/SaneDevice.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package au.com.southsky.jfreesane;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import java.awt.image.BufferedImage;
import java.io.Closeable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
* Represents a SANE device within a session. SANE devices are obtained from a {@link SaneSession}.
Expand All @@ -31,8 +26,8 @@ public class SaneDevice implements Closeable {

private SaneDeviceHandle handle;

private Map<String, SaneOption> optionTitleMap = null;
private final List<OptionGroup> groups = Lists.newArrayList();
private List<SaneOption> options = null;
private final List<OptionGroup> groups = new ArrayList<>();

SaneDevice(SaneSession session, String name, String vendor, String model, String type) {
this.session = session;
Expand Down Expand Up @@ -165,21 +160,12 @@ SaneDeviceHandle getHandle() {
* @throws IOException if a problem occurred talking to the SANE backend
*/
public List<SaneOption> listOptions() throws IOException {
if (optionTitleMap == null) {
if (options == null) {
groups.clear();
optionTitleMap =
Maps.uniqueIndex(
SaneOption.optionsFor(this),
new Function<SaneOption, String>() {
@Override
public String apply(SaneOption input) {
return input.getName();
}
});
options = SaneOption.optionsFor(this);
}

// Maps.uniqueIndex guarantees the order of optionTitleMap.values()
return ImmutableList.copyOf(optionTitleMap.values());
return new ArrayList<>(options);
}

void addOptionGroup(OptionGroup group) {
Expand All @@ -191,16 +177,20 @@ void addOptionGroup(OptionGroup group) {
*/
public List<OptionGroup> getOptionGroups() throws IOException {
listOptions();
return ImmutableList.copyOf(groups);
return new ArrayList<>(groups);
}

/**
* Returns the option with the given name for this device. If the option does not exist,
* {@code null} is returned. Name matching is case-sensitive.
*/
public SaneOption getOption(String title) throws IOException {
public SaneOption getOption(String optionName) throws IOException {
listOptions();
return optionTitleMap.get(title);
return options
.stream()
.filter(o -> Objects.equals(optionName, o.getName()))
.findFirst()
.orElse(null);
}

SaneSession getSession() {
Expand All @@ -212,6 +202,6 @@ SaneSession getSession() {
* options after an option was set).
*/
void invalidateOptions() {
optionTitleMap = null;
options = null;
}
}
37 changes: 9 additions & 28 deletions src/main/java/au/com/southsky/jfreesane/SaneEnums.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
package au.com.southsky.jfreesane;

import java.util.List;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
* Utilities for dealing with instances of {@link SaneEnum}.
*
* @author James Ring (sjr@jdns.org)
*/
final class SaneEnums {
private static Map<Class<?>, Map<Integer, ?>> cachedTypeMaps = Maps.newHashMap();
private static Map<Class<?>, Map<Integer, ?>> cachedTypeMaps = new HashMap<>();

// no public constructor
private SaneEnums() {}
Expand All @@ -27,14 +24,13 @@ private static synchronized <T extends Enum<T> & SaneEnum> Map<Integer, T> mapFo
return (Map<Integer, T>) cachedTypeMaps.get(enumType);
}

ImmutableMap.Builder<Integer, T> mapBuilder = ImmutableMap.builder();
Map<Integer, T> map = new HashMap<>();

for (T value : enumType.getEnumConstants()) {
mapBuilder.put(value.getWireValue(), value);
map.put(value.getWireValue(), value);
}

Map<Integer, T> result = mapBuilder.build();

Map<Integer, T> result = Collections.unmodifiableMap(map);
cachedTypeMaps.put(enumType, result);
return result;
}
Expand All @@ -44,30 +40,15 @@ private static synchronized <T extends Enum<T> & SaneEnum> Map<Integer, T> mapFo
* represent the wire values of the enum constants of the given {@code enumType}.
*/
public static <T extends Enum<T> & SaneEnum> Set<T> enumSet(Class<T> enumType, int wireValue) {
Set<T> result = EnumSet.noneOf(enumType);
T[] enumConstants = enumType.getEnumConstants();
List<T> values = Lists.newArrayListWithCapacity(enumConstants.length);

for (T value : enumConstants) {
if ((wireValue & value.getWireValue()) != 0) {
values.add(value);
result.add(value);
}
}

return Sets.immutableEnumSet(values);
}

/**
* Returns the result of bitwise-ORing the wire values of the given {@code SaneEnum} set. This
* method does not check to make sure the result is sensible: the caller must ensure that the set
* contains members whose wire values can be ORed together in a logically correct fashion.
*/
public static <T extends SaneEnum> int wireValue(Set<T> values) {
int result = 0;

for (T value : values) {
result |= value.getWireValue();
}

return result;
}

Expand Down

0 comments on commit ae13d94

Please sign in to comment.