public byte[] getData(final long address, final int length) {
    Preconditions.checkArgument(address >= 0, "Error: Address can't be less than 0");
    Preconditions.checkArgument(length > 0, "Error: Length must be positive");

    m_readLock.lock();

    MemoryChunk nextChunk = findChunk(address);
    int nextLength = length;
    long nextAddress = address;

    final byte[] data = new byte[length];

    int copied = 0;

    try {
      do {
        if (nextChunk == null) {
          // The chunk with the address could not be found
          // => The data is not available.
          throw new IllegalArgumentException("Error: Data is not available");
        } else if (((nextChunk.getAddress() + nextChunk.getLength()) - nextAddress) >= nextLength) {
          // Enough data is available in the chunk.
          // => The data is available.

          final int start = (int) (nextAddress - nextChunk.getAddress());

          System.arraycopy(nextChunk.getBytes(), start, data, copied, nextLength);

          return data;
        } else {
          // There is not enough data available in the
          // current chunk but the data could be in the
          // next chunk.

          // Copy the whole current chunk into the output
          // array.

          final int start = (int) (nextAddress - nextChunk.getAddress());
          final int toCopy = nextChunk.getLength() - start;

          System.arraycopy(nextChunk.getBytes(), start, data, copied, toCopy);

          copied += toCopy;

          // The next length is the required length minus
          // the length of the current chunk that was consumed.
          nextLength -= (nextChunk.getAddress() + nextChunk.getLength()) - nextAddress;

          // The next address is exactly the address behind
          // the current chunk because the whole current chunk
          // was consumed already.
          nextAddress = nextChunk.getAddress() + nextChunk.getLength();

          nextChunk = findChunk(nextAddress);
        }

      } while (true);
    } finally {
      m_readLock.unlock();
    }
  }
Returns memory data. Note that it is necessary to call the function hasData before to make sure
that the data actually exists.

@param address The start address of the memory data.
@param length The length of the retrieved data.
@return The retrieved data.
@throws IllegalArgumentException Thrown if the address is negative or if the length is not
    positive.
@throws IllegalArgumentException Thrown if not all data is available.
java/zylib/src/main/java/com/google/security/zynamics/zylib/general/memmanager/Memory.java