Esempio n. 1
0
  /**
   * Identify where the end of the middle / payload section ends.
   *
   * @param row row of black/white values to search
   * @return Array, containing index of start of 'end block' and end of 'end block'
   * @throws NotFoundException
   */
  int[] decodeEnd(BitArray row) throws NotFoundException {

    // For convenience, reverse the row and then
    // search from 'the start' for the end block
    row.reverse();
    try {
      int endStart = skipWhiteSpace(row);
      int[] endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED);

      // The start & end patterns must be pre/post fixed by a quiet zone. This
      // zone must be at least 10 times the width of a narrow line.
      // ref: http://www.barcode-1.net/i25code.html
      validateQuietZone(row, endPattern[0]);

      // Now recalculate the indices of where the 'endblock' starts & stops to
      // accommodate
      // the reversed nature of the search
      int temp = endPattern[0];
      endPattern[0] = row.getSize() - endPattern[1];
      endPattern[1] = row.getSize() - temp;

      return endPattern;
    } finally {
      // Put the row back the right way.
      row.reverse();
    }
  }
Esempio n. 2
0
 /** Moves the cursor to a free block (either new or existing empty one). */
 private void freeBlock() {
   final int b = usedPages.nextFree(0);
   usedPages.set(b);
   readBlock(b);
   ++used;
   ++page;
 }
  // Applies simple sharpening to the row data to improve performance of the 1D Readers.
  @Override
  public BitArray getBlackRow(int y, BitArray row) throws NotFoundException {
    LuminanceSource source = getLuminanceSource();
    int width = source.getWidth();
    if (row == null || row.getSize() < width) {
      row = new BitArray(width);
    } else {
      row.clear();
    }

    initArrays(width);
    byte[] localLuminances = source.getRow(y, luminances);
    int[] localBuckets = buckets;
    for (int x = 0; x < width; x++) {
      int pixel = localLuminances[x] & 0xff;
      localBuckets[pixel >> LUMINANCE_SHIFT]++;
    }
    int blackPoint = estimateBlackPoint(localBuckets);

    int left = localLuminances[0] & 0xff;
    int center = localLuminances[1] & 0xff;
    for (int x = 1; x < width - 1; x++) {
      int right = localLuminances[x + 1] & 0xff;
      // A simple -1 4 -1 box filter with a weight of 2.
      int luminance = ((center * 4) - left - right) / 2;
      if (luminance < blackPoint) {
        row.set(x);
      }
      left = center;
      center = right;
    }
    return row;
  }
Esempio n. 4
0
 /**
  * Reads a bit from the stream. Returns a boolean (true for 1; false for 0) if a bit is available,
  * or throws an EOFException if the end of stream is reached.
  *
  * @return the bit that was read (true = 1; false = 0)
  * @throws IOException if the stream is closed or another I/O error occurs
  * @throws EOFException when the next bit cannot be read because the end of stream is reached
  */
 protected boolean doReadBit() throws IOException, EOFException {
   if (currentIndex
       >= bitArray
           .length()) // also reads a new byte from underlying stream if needed! (will also check
     // for closedness)
     throw new EOFException("End of stream reached");
   return bitArray.get(currentIndex++);
 }
Esempio n. 5
0
  @AndroidIncompatible // OutOfMemoryError
  public void testLargeBloomFilterDoesntOverflow() {
    long numBits = Integer.MAX_VALUE;
    numBits++;

    BitArray bitArray = new BitArray(numBits);
    assertTrue(
        "BitArray.bitSize() must return a positive number, but was " + bitArray.bitSize(),
        bitArray.bitSize() > 0);

    // Ideally we would also test the bitSize() overflow of this BF, but it runs out of heap space
    // BloomFilter.create(Funnels.unencodedCharsFunnel(), 244412641, 1e-11);
  }
Esempio n. 6
0
  /**
   * Skip all whitespace until we get to the first black line.
   *
   * @param row row of black/white values to search
   * @return index of the first black line.
   * @throws NotFoundException Throws exception if no black lines are found in the row
   */
  private static int skipWhiteSpace(BitArray row) throws NotFoundException {
    int width = row.getSize();
    int endStart = 0;
    while (endStart < width) {
      if (row.get(endStart)) {
        break;
      }
      endStart++;
    }
    if (endStart == width) {
      throw NotFoundException.getNotFoundInstance();
    }

    return endStart;
  }
Esempio n. 7
0
 @Override
 public <T> void put(T object, Funnel<? super T> funnel, int numHashFunctions, BitArray bits) {
   // TODO(user): when the murmur's shortcuts are implemented, update this code
   long hash64 = Hashing.murmur3_128().newHasher().putObject(object, funnel).hash().asLong();
   int hash1 = (int) hash64;
   int hash2 = (int) (hash64 >>> 32);
   for (int i = 1; i <= numHashFunctions; i++) {
     int nextHash = hash1 + i * hash2;
     if (nextHash < 0) {
       nextHash = ~nextHash;
     }
     // up to here, the code is identical with the next method
     bits.set(nextHash % bits.size());
   }
 }
  /**
   * Dispatch the character content of a node to an output handler.
   *
   * <p>The escape setting should be taken care of when outputting to a handler.
   */
  public void characters(final int node, SerializationHandler handler) throws TransletException {
    int nodeID = getNodeIdent(node);
    if (nodeID == RTF_ROOT || nodeID == RTF_TEXT) {
      boolean escapeBit = false;
      boolean oldEscapeSetting = false;

      try {
        for (int i = 0; i < _size; i++) {

          if (_dontEscape != null) {
            escapeBit = _dontEscape.getBit(i);
            if (escapeBit) {
              oldEscapeSetting = handler.setEscaping(false);
            }
          }

          handler.characters(_textArray[i]);

          if (escapeBit) {
            handler.setEscaping(oldEscapeSetting);
          }
        }
      } catch (SAXException e) {
        throw new TransletException(e);
      }
    }
  }
Esempio n. 9
0
 @Override
 public <T> boolean mightContain(
     T object, Funnel<? super T> funnel, int numHashFunctions, BitArray bits) {
   long hash64 = Hashing.murmur3_128().newHasher().putObject(object, funnel).hash().asLong();
   int hash1 = (int) hash64;
   int hash2 = (int) (hash64 >>> 32);
   for (int i = 1; i <= numHashFunctions; i++) {
     int nextHash = hash1 + i * hash2;
     if (nextHash < 0) {
       nextHash = ~nextHash;
     }
     // up to here, the code is identical with the previous method
     if (!bits.get(nextHash % bits.size())) {
       return false;
     }
   }
   return true;
 }
  public void characters(char[] ch, int offset, int length) throws SAXException {
    if (_size >= _textArray.length) {
      String[] newTextArray = new String[_textArray.length * 2];
      System.arraycopy(_textArray, 0, newTextArray, 0, _textArray.length);
      _textArray = newTextArray;
    }

    if (!_escaping) {
      if (_dontEscape == null) {
        _dontEscape = new BitArray(8);
      }

      if (_size >= _dontEscape.size()) _dontEscape.resize(_dontEscape.size() * 2);

      _dontEscape.setBit(_size);
    }

    _textArray[_size++] = new String(ch, offset, length);
  }
Esempio n. 11
0
 @Override
 boolean clean(final IntObjMap<Var> decl, final BitArray used) {
   // [LW] does not fix {@link #vars}
   final int len = preExpr.length;
   for (int p = 0; p < post.length; p++) {
     if (!used.get(post[p].id)) {
       preExpr = Array.delete(preExpr, p);
       post = Array.delete(post, p--);
     }
   }
   return preExpr.length < len;
 }
Esempio n. 12
0
  /**
   * @param row row of black/white values to search
   * @param rowOffset position to start search
   * @param pattern pattern of counts of number of black and white pixels that are being searched
   *     for as a pattern
   * @return start/end horizontal offset of guard pattern, as an array of two ints
   * @throws NotFoundException if pattern is not found
   */
  private static int[] findGuardPattern(BitArray row, int rowOffset, int[] pattern)
      throws NotFoundException {

    // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
    // merged to a single method.
    int patternLength = pattern.length;
    int[] counters = new int[patternLength];
    int width = row.getSize();
    boolean isWhite = false;

    int counterPosition = 0;
    int patternStart = rowOffset;
    for (int x = rowOffset; x < width; x++) {
      boolean pixel = row.get(x);
      if (pixel ^ isWhite) {
        counters[counterPosition]++;
      } else {
        if (counterPosition == patternLength - 1) {
          if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
            return new int[] {patternStart, x};
          }
          patternStart += counters[0] + counters[1];
          for (int y = 2; y < patternLength; y++) {
            counters[y - 2] = counters[y];
          }
          counters[patternLength - 2] = 0;
          counters[patternLength - 1] = 0;
          counterPosition--;
        } else {
          counterPosition++;
        }
        counters[counterPosition] = 1;
        isWhite = !isWhite;
      }
    }
    throw NotFoundException.getNotFoundInstance();
  }
  public void characters(String str) throws SAXException {
    // Resize the text array if necessary
    if (_size >= _textArray.length) {
      String[] newTextArray = new String[_textArray.length * 2];
      System.arraycopy(_textArray, 0, newTextArray, 0, _textArray.length);
      _textArray = newTextArray;
    }

    // If the escape setting is false, set the corresponding bit in
    // the _dontEscape BitArray.
    if (!_escaping) {
      // The _dontEscape array is only created when needed.
      if (_dontEscape == null) {
        _dontEscape = new BitArray(8);
      }

      // Resize the _dontEscape array if necessary
      if (_size >= _dontEscape.size()) _dontEscape.resize(_dontEscape.size() * 2);

      _dontEscape.setBit(_size);
    }

    _textArray[_size++] = str;
  }
Esempio n. 14
0
  /**
   * The start & end patterns must be pre/post fixed by a quiet zone. This zone must be at least 10
   * times the width of a narrow line. Scan back until we either get to the start of the barcode or
   * match the necessary number of quiet zone pixels.
   *
   * <p>Note: Its assumed the row is reversed when using this method to find quiet zone after the
   * end pattern.
   *
   * <p>ref: http://www.barcode-1.net/i25code.html
   *
   * @param row bit array representing the scanned barcode.
   * @param startPattern index into row of the start or end pattern.
   * @throws NotFoundException if the quiet zone cannot be found, a ReaderException is thrown.
   */
  private void validateQuietZone(BitArray row, int startPattern) throws NotFoundException {

    int quietCount = this.narrowLineWidth * 10; // expect to find this many pixels of quiet zone

    for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {
      if (row.get(i)) {
        break;
      }
      quietCount--;
    }
    if (quietCount != 0) {
      // Unable to find the necessary number of quiet zone pixels.
      throw NotFoundException.getNotFoundInstance();
    }
  }
Esempio n. 15
0
  @Override
  public synchronized void flush() throws IOException {
    for (final Buffer b : bm.all()) if (b.dirty) writeBlock(b);
    if (!dirty) return;

    try (final DataOutput out = new DataOutput(meta.dbfile(DATATBL + 'i'))) {
      out.writeNum(blocks);
      out.writeNum(used);

      // due to legacy issues, number of blocks is written several times
      out.writeNum(blocks);
      for (int a = 0; a < blocks; a++) out.writeNum(fpres[a]);
      out.writeNum(blocks);
      for (int a = 0; a < blocks; a++) out.writeNum(pages[a]);

      out.writeLongs(usedPages.toArray());
    }
    dirty = false;
  }
Esempio n. 16
0
 /**
  * The (estimated) number of bits left available for reading. Calls atEnd().
  *
  * @return
  */
 public int bitsAvailable() throws IOException {
   return bitArray.length() - currentIndex;
 }
Esempio n. 17
0
  @Override
  public void insert(final int pre, final byte[] entries) {
    final int nnew = entries.length;
    if (nnew == 0) return;
    dirty();

    // number of records to be inserted
    final int nr = nnew >>> IO.NODEPOWER;

    int split = 0;
    if (used == 0) {
      // special case: insert new data into first block if database is empty
      readPage(0);
      usedPages.set(0);
      ++used;
    } else if (pre > 0) {
      // find the offset within the block where the new records will be inserted
      split = cursor(pre - 1) + IO.NODESIZE;
    } else {
      // all insert operations will add data after first node.
      // i.e., there is no "insert before first document" statement
      throw Util.notExpected("Insertion at beginning of populated table.");
    }

    // number of bytes occupied by old records in the current block
    final int nold = npre - fpre << IO.NODEPOWER;
    // number of bytes occupied by old records which will be moved at the end
    final int moved = nold - split;

    // special case: all entries fit in the current block
    Buffer bf = bm.current();
    if (nold + nnew <= IO.BLOCKSIZE) {
      Array.move(bf.data, split, nnew, moved);
      System.arraycopy(entries, 0, bf.data, split, nnew);
      bf.dirty = true;

      // increment first pre-values of blocks after the last modified block
      for (int i = page + 1; i < used; ++i) fpres[i] += nr;
      // update cached variables (fpre is not changed)
      npre += nr;
      meta.size += nr;
      return;
    }

    // append old entries at the end of the new entries
    final byte[] all = new byte[nnew + moved];
    System.arraycopy(entries, 0, all, 0, nnew);
    System.arraycopy(bf.data, split, all, nnew, moved);

    // fill in the current block with new entries
    // number of bytes which fit in the first block
    int nrem = IO.BLOCKSIZE - split;
    if (nrem > 0) {
      System.arraycopy(all, 0, bf.data, split, nrem);
      bf.dirty = true;
    }

    // number of new required blocks and remaining bytes
    final int req = all.length - nrem;
    int needed = req / IO.BLOCKSIZE;
    final int remain = req % IO.BLOCKSIZE;

    if (remain > 0) {
      // check if the last entries can fit in the block after the current one
      if (page + 1 < used) {
        final int o = occSpace(page + 1) << IO.NODEPOWER;
        if (remain <= IO.BLOCKSIZE - o) {
          // copy the last records
          readPage(page + 1);
          bf = bm.current();
          System.arraycopy(bf.data, 0, bf.data, remain, o);
          System.arraycopy(all, all.length - remain, bf.data, 0, remain);
          bf.dirty = true;
          // reduce the pre value, since it will be later incremented with nr
          fpres[page] -= remain >>> IO.NODEPOWER;
          // go back to the previous block
          readPage(page - 1);
        } else {
          // there is not enough space in the block - allocate a new one
          ++needed;
        }
      } else {
        // this is the last block - allocate a new one
        ++needed;
      }
    }

    // number of expected blocks: existing blocks + needed block - empty blocks
    final int exp = blocks + needed - (blocks - used);
    if (exp > fpres.length) {
      // resize directory arrays if existing ones are too small
      final int ns = Math.max(fpres.length << 1, exp);
      fpres = Arrays.copyOf(fpres, ns);
      pages = Arrays.copyOf(pages, ns);
    }

    // make place for the blocks where the new entries will be written
    Array.move(fpres, page + 1, needed, used - page - 1);
    Array.move(pages, page + 1, needed, used - page - 1);

    // write the all remaining entries
    while (needed-- > 0) {
      freeBlock();
      nrem += write(all, nrem);
      fpres[page] = fpres[page - 1] + IO.ENTRIES;
      pages[page] = (int) bm.current().pos;
    }

    // increment all fpre values after the last modified block
    for (int i = page + 1; i < used; ++i) fpres[i] += nr;

    meta.size += nr;

    // update cached variables
    fpre = fpres[page];
    npre = page + 1 < used && fpres[page + 1] < meta.size ? fpres[page + 1] : meta.size;
  }
Esempio n. 18
0
  @Override
  public void delete(final int pre, final int nr) {
    if (nr == 0) return;
    dirty();

    // get first block
    cursor(pre);

    // some useful variables to make code more readable
    int from = pre - fpre;
    final int last = pre + nr;

    // check if all entries are in current block: handle and return
    if (last - 1 < npre) {
      final Buffer bf = bm.current();
      copy(bf.data, from + nr, bf.data, from, npre - last);
      updatePre(nr);

      // if whole block was deleted, remove it from the index
      if (npre == fpre) {
        // mark the block as empty
        usedPages.clear(pages[page]);

        Array.move(fpres, page + 1, -1, used - page - 1);
        Array.move(pages, page + 1, -1, used - page - 1);

        --used;
        readPage(page);
      }
      return;
    }

    // handle blocks whose entries are to be deleted entirely

    // first count them
    int unused = 0;
    while (npre < last) {
      if (from == 0) {
        ++unused;
        // mark the blocks as empty; range clear cannot be used because the
        // blocks may not be consecutive
        usedPages.clear(pages[page]);
      }
      setPage(page + 1);
      from = 0;
    }

    // if the last block is empty, clear the corresponding bit
    readBlock(pages[page]);
    final Buffer bf = bm.current();
    if (npre == last) {
      usedPages.clear((int) bf.pos);
      ++unused;
      if (page < used - 1) readPage(page + 1);
      else ++page;
    } else {
      // delete entries at beginning of current (last) block
      copy(bf.data, last - fpre, bf.data, 0, npre - last);
    }

    // now remove them from the index
    if (unused > 0) {
      Array.move(fpres, page, -unused, used - page);
      Array.move(pages, page, -unused, used - page);
      used -= unused;
      page -= unused;
    }

    // update index entry for this block
    fpres[page] = pre;
    fpre = pre;
    updatePre(nr);
  }