private synchronized String readNextChunk(int capacity) throws IOException {
    if (capacity == 0) {
      throw new EndOfFileException("Zero chunk size, possibly end of file reached.");
    }

    ByteBuffer buf = ByteBuffer.allocateDirect(capacity);
    byte[] dst = new byte[capacity];

    int cnt = file.read(buf);
    // log.debug("Read " + cnt);
    if (cnt != capacity) {
      throw new IOException(
          "Expected chunk size (" + capacity + ") differs from read bytes count (" + cnt + ")");
    }

    buf.flip();
    buf.get(dst);
    if (log.isDebugEnabled()) {
      log.debug("Chunk : " + new String(dst));
    }

    if (isHexEncode()) {
      return JOrphanUtils.baToHexString(dst);
    } else {
      return new String(dst, binaryCharset);
    }
  }
  // package protected so can be accessed by test class
  static String baMD5Hex(byte ba[]) {
    byte[] md5Result = {};

    try {
      MessageDigest md;
      md = MessageDigest.getInstance("MD5");
      md5Result = md.digest(ba);
    } catch (NoSuchAlgorithmException e) {
      log.error("", e);
    }
    return JOrphanUtils.baToHexString(md5Result);
  }
  /**
   * Reads data until the defined EOM byte is reached. If there is no EOM byte defined, then reads
   * until the end of the stream is reached. Response data is converted to hex-encoded binary
   *
   * @return hex-encoded binary string
   * @throws ReadException
   */
  public String read(InputStream is) throws ReadException {
    ByteArrayOutputStream w = new ByteArrayOutputStream();
    try {
      byte[] buffer = new byte[4096];
      int x = 0;
      while ((x = is.read(buffer)) > -1) {
        w.write(buffer, 0, x);
        if (useEolByte && (buffer[x - 1] == eolByte)) {
          break;
        }
      }

      IOUtils.closeQuietly(w); // For completeness
      final String hexString = JOrphanUtils.baToHexString(w.toByteArray());
      if (log.isDebugEnabled()) {
        log.debug("Read: " + w.size() + "\n" + hexString);
      }
      return hexString;
    } catch (IOException e) {
      throw new ReadException("", e, JOrphanUtils.baToHexString(w.toByteArray()));
    }
  }
 @Test
 public void testEncode_withFlagsMac() throws UnsupportedEncodingException {
   System.out.println("encode f");
   // stackowerflow.com
   String data = "stackowerflow.com. A IN\n\r7\n\r-7";
   DNSJavaDecoder instance = new DNSJavaDecoder();
   ByteBuffer result = instance.encode(data);
   String exp = "3f3c000000010000000000000d737461636b6f776572666c6f7703636f6d0000010001";
   String res =
       JOrphanUtils.baToHexString(JMeterPluginsUtils.byteBufferToString(result).getBytes("cp866"));
   System.out.println(exp);
   System.out.println(res);
   assertEquals(exp.substring(8), res.substring(res.length() - exp.length() + 8));
 }
  /** {@inheritDoc} */
  @Override
  public String read(InputStream is) throws ReadException {
    byte[] msg = new byte[0];
    int msgLen = 0;
    byte[] lengthBuffer = new byte[lengthPrefixLen];
    try {
      if (is.read(lengthBuffer, 0, lengthPrefixLen) == lengthPrefixLen) {
        msgLen = byteArrayToInt(lengthBuffer);
        msg = new byte[msgLen];
        int bytes = JOrphanUtils.read(is, msg, 0, msgLen);
        if (bytes < msgLen) {
          log.warn("Incomplete message read, expected: " + msgLen + " got: " + bytes);
        }
      }

      String buffer = JOrphanUtils.baToHexString(msg);
      if (log.isDebugEnabled()) {
        log.debug("Read: " + msgLen + "\n" + buffer);
      }
      return buffer;
    } catch (IOException e) {
      throw new ReadException("", e, JOrphanUtils.baToHexString(msg));
    }
  }