<commit_before>package au.com.southsky.jfreesane;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * This class represents a SANE device option. An option may be active or inactive (see
 * {@link #isActive}). Active options may be read (see {@link #isReadable}) and modified (see
 * {@link #isWriteable}).
 *
 * <p>
 * Options have a type (see {@link #getType}), in order to read or write an option's value, you must
 * call the getter or setter method corresponding to the option's type. For example, for an option
 * of type {@link OptionValueType#STRING}, you will call {@link #setStringValue} or
 * {@link #getStringValue}.
 *
 * <p>
 * Options may have constraints that impose restrictions on the range of values the option may take.
 * Constraints have a type which may be obtained using {@link #getConstraintType}. You may read the
 * actual constraints by calling the constraint getter method corresponding to the constraint type.
 * For example, an option of type {@link OptionValueType#INT} may have a constraint of type
 * {@link OptionValueConstraintType#VALUE_LIST_CONSTRAINT}, which you may obtain by calling
 * {@link #getIntegerValueListConstraint}.
 *
 * @author <NAME> (<EMAIL>)
 */
public class SaneOption {

  private final static Logger logger = Logger.getLogger(SaneOption.class.getName());

  private enum OptionAction implements SaneEnum {
    GET_VALUE(0), SET_VALUE(1), SET_AUTO(2);

    private int actionNo;

    OptionAction(int actionNo) {
      this.actionNo = actionNo;
    }

    @Override
    public int getWireValue() {
      return actionNo;
    }
  }

  /**
   * Instances of this enum are returned by {@link SaneOption#getUnits} indicating what units, if
   * any, the value has.
   */
  public enum OptionUnits implements SaneEnum {
    /**
     * The option has no units.
     */
    UNIT_NONE(0),

    /**
     * The option unit is pixels.
     */
    UNIT_PIXEL(1),

    /**
     * The option unit is bits.
     */
    UNIT_BIT(2),

    /**
     * The option unit is millimeters.
     */
    UNIT_MM(3),

    /**
     * The option unit is dots per inch.
     */
    UNIT_DPI(4),

    /**
     * The option unit is a percentage.
     */
    UNIT_PERCENT(5),

    /**
     * The option unit is microseconds.
     */
    UNIT_MICROSECOND(6);

    private final int wireValue;

    OptionUnits(int wireValue) {
      this.wireValue = wireValue;
    }

    @Override
    public int getWireValue() {
      return wireValue;
    }
  }

  /**
   * Represents the information that the SANE daemon returns about the effect of modifying an
   * option.
   */
  public enum OptionWriteInfo implements SaneEnum {
    /**
     * The value passed to SANE was accepted, but the SANE daemon has chosen a slightly different
     * value than the one specified.
     */
    INEXACT(1),

    /**
     * Setting the option may have resulted in changes to other options and the client should
     * re-read options whose values it needs.
     */
    RELOAD_OPTIONS(2),

    /**
     * Setting the option may have caused a parameter set by the user to have changed.
     */
    RELOAD_PARAMETERS(4);

    private final int wireValue;

    OptionWriteInfo(int wireValue) {
      this.wireValue = wireValue;
    }

    @Override
    public int getWireValue() {
      return wireValue;
    }

  }

  private final SaneDevice device;
  private final int optionNumber;
  private final SaneOptionDescriptor descriptor;

  SaneOption(SaneDevice device, int optionNumber, SaneOptionDescriptor descriptor) {
    this.device = device;
    this.optionNumber = optionNumber;
    this.descriptor = descriptor;

    if (descriptor.getGroup() != null && getValueType() != OptionValueType.GROUP) {
      descriptor.getGroup().addOption(this);
    }
  }

  static List<SaneOption> optionsFor(SaneDevice device) throws IOException {
    Preconditions.checkState(device.isOpen(), "you must open() the device first");
    List<SaneOption> options = Lists.newArrayList();
    SaneSession session = device.getSession();

    SaneInputStream inputStream = session.getInputStream();
    SaneOutputStream outputStream = session.getOutputStream();

    // send RPC 4

    outputStream.write(SaneWord.forInt(4));

    // select device

    outputStream.write(device.getHandle().getHandle());

    // first word of response in number of option entries

    int length = inputStream.readWord().integerValue() - 1;

    if (length <= 0) {
      return ImmutableList.of();
    }

    for (int i = 0; i <= length; i++) {
      SaneOption option = SaneOption.fromStream(inputStream, device, i);

      // http://code.google.com/p/jfreesane/issues/detail?id=1
      // The first option always has an empty name. Sometimes we see options after the first option
      // that have empty names. Elsewhere we assume that option names are unique, so this option is
      // omitted
      if (option == null || (i > 0 && Strings.isNullOrEmpty(option.getName()))) {
        logger.fine(String.format("ignoring null or empty option with id %d: %s", i, option));
        continue;
      }

      if (option.getValueType() == OptionValueType.GROUP) {
        device.addOptionGroup(option.getGroup());
      } else {
        options.add(option);
      }
    }

    return options;
  }

  private static SaneOption fromStream(SaneInputStream inputStream, SaneDevice device,
      int optionNumber) throws IOException {
    return new SaneOption(device, optionNumber, inputStream.readOptionDescriptor());
  }

  public SaneDevice getDevice() {
    return device;<commit_msg>fix option groups being ignored: they always have an empty name but should not be ignored<commit_after>package au.com.southsky.jfreesane;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import com.google.common.base.Charsets;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * This class represents a SANE device option. An option may be active or inactive (see
 * {@link #isActive}). Active options may be read (see {@link #isReadable}) and modified (see
 * {@link #isWriteable}).
 *
 * <p>
 * Options have a type (see {@link #getType}), in order to read or write an option's value, you must
 * call the getter or setter method corresponding to the option's type. For example, for an option
 * of type {@link OptionValueType#STRING}, you will call {@link #setStringValue} or
 * {@link #getStringValue}.
 *
 * <p>
 * Options may have constraints that impose restrictions on the range of values the option may take.
 * Constraints have a type which may be obtained using {@link #getConstraintType}. You may read the
 * actual constraints by calling the constraint getter method corresponding to the constraint type.
 * For example, an option of type {@link OptionValueType#INT} may have a constraint of type
 * {@link OptionValueConstraintType#VALUE_LIST_CONSTRAINT}, which you may obtain by calling
 * {@link #getIntegerValueListConstraint}.
 *
 * @author <NAME> (<EMAIL>)
 */
public class SaneOption {

  private final static Logger logger = Logger.getLogger(SaneOption.class.getName());

  private enum OptionAction implements SaneEnum {
    GET_VALUE(0), SET_VALUE(1), SET_AUTO(2);

    private int actionNo;

    OptionAction(int actionNo) {
      this.actionNo = actionNo;
    }

    @Override
    public int getWireValue() {
      return actionNo;
    }
  }

  /**
   * Instances of this enum are returned by {@link SaneOption#getUnits} indicating what units, if
   * any, the value has.
   */
  public enum OptionUnits implements SaneEnum {
    /**
     * The option has no units.
     */
    UNIT_NONE(0),

    /**
     * The option unit is pixels.
     */
    UNIT_PIXEL(1),

    /**
     * The option unit is bits.
     */
    UNIT_BIT(2),

    /**
     * The option unit is millimeters.
     */
    UNIT_MM(3),

    /**
     * The option unit is dots per inch.
     */
    UNIT_DPI(4),

    /**
     * The option unit is a percentage.
     */
    UNIT_PERCENT(5),

    /**
     * The option unit is microseconds.
     */
    UNIT_MICROSECOND(6);

    private final int wireValue;

    OptionUnits(int wireValue) {
      this.wireValue = wireValue;
    }

    @Override
    public int getWireValue() {
      return wireValue;
    }
  }

  /**
   * Represents the information that the SANE daemon returns about the effect of modifying an
   * option.
   */
  public enum OptionWriteInfo implements SaneEnum {
    /**
     * The value passed to SANE was accepted, but the SANE daemon has chosen a slightly different
     * value than the one specified.
     */
    INEXACT(1),

    /**
     * Setting the option may have resulted in changes to other options and the client should
     * re-read options whose values it needs.
     */
    RELOAD_OPTIONS(2),

    /**
     * Setting the option may have caused a parameter set by the user to have changed.
     */
    RELOAD_PARAMETERS(4);

    private final int wireValue;

    OptionWriteInfo(int wireValue) {
      this.wireValue = wireValue;
    }

    @Override
    public int getWireValue() {
      return wireValue;
    }

  }

  private final SaneDevice device;
  private final int optionNumber;
  private final SaneOptionDescriptor descriptor;

  SaneOption(SaneDevice device, int optionNumber, SaneOptionDescriptor descriptor) {
    this.device = device;
    this.optionNumber = optionNumber;
    this.descriptor = descriptor;

    if (descriptor.getGroup() != null && getValueType() != OptionValueType.GROUP) {
      descriptor.getGroup().addOption(this);
    }
  }

  static List<SaneOption> optionsFor(SaneDevice device) throws IOException {
    Preconditions.checkState(device.isOpen(), "you must open() the device first");
    List<SaneOption> options = Lists.newArrayList();
    SaneSession session = device.getSession();

    SaneInputStream inputStream = session.getInputStream();
    SaneOutputStream outputStream = session.getOutputStream();

    // send RPC 4

    outputStream.write(SaneWord.forInt(4));

    // select device

    outputStream.write(device.getHandle().getHandle());

    // first word of response in number of option entries

    int length = inputStream.readWord().integerValue() - 1;

    if (length <= 0) {
      return ImmutableList.of();
    }

    for (int i = 0; i <= length; i++) {
      SaneOption option = SaneOption.fromStream(inputStream, device, i);

      if (option == null) {
        continue;
      }

      if (option.getValueType() == OptionValueType.GROUP) {
        device.addOptionGroup(option.getGroup());
      } else {
        // http://code.google.com/p/jfreesane/issues/detail?id=1
        // The first option always has an empty name. Sometimes we see options after the first option
        // that have empty names. Elsewhere we assume that option names are unique, so this option is
        // omitted
        if (i > 0 && Strings.isNullOrEmpty(option.getName())) {
          logger.fine(String.format("ignoring null or empty option with id %d: %s", i, option));
          continue;
        }

        options.add(option);
      }
    }

    return options;
  }

  private static SaneOption fromStream(SaneInputStream inputStream, SaneDevice device,
      int optionNumber) throws IOException {
    return new SaneOption(device, optionNumber, inputStream.readOptionDescriptor());
  }

  public SaneDevice getDevice() {
    return device;
{'fraction_non_alphanumeric': 0.09935817287655248, 'fraction_numerical': 0.0033341668750520963, 'mean_word_length': 3.0315860215053765, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6983709', 'n_tokens_mistral': 3502, 'n_tokens_neox': 3363, 'n_words': 1122}