001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.util;
019
020import java.io.ByteArrayOutputStream;
021import java.io.DataInput;
022import java.io.DataInputStream;
023import java.io.DataOutput;
024import java.io.IOException;
025import java.io.InputStream;
026import java.io.OutputStream;
027import java.math.BigDecimal;
028import java.math.BigInteger;
029import java.nio.ByteBuffer;
030import java.util.Arrays;
031import org.apache.hadoop.hbase.io.ByteBufferWriter;
032import org.apache.hadoop.hbase.io.util.StreamUtils;
033import org.apache.hadoop.hbase.nio.ByteBuff;
034import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
035import org.apache.hadoop.io.IOUtils;
036import org.apache.hadoop.io.WritableUtils;
037import org.apache.yetus.audience.InterfaceAudience;
038
039/**
040 * Utility functions for working with byte buffers, such as reading/writing variable-length long
041 * numbers.
042 * @deprecated This class will become IA.Private in HBase 3.0. Downstream folks shouldn't use it.
043 */
044@Deprecated
045@InterfaceAudience.Public
046public final class ByteBufferUtils {
047  // "Compressed integer" serialization helper constants.
048  public final static int VALUE_MASK = 0x7f;
049  public final static int NEXT_BIT_SHIFT = 7;
050  public final static int NEXT_BIT_MASK = 1 << 7;
051  @InterfaceAudience.Private
052  final static boolean UNSAFE_AVAIL = HBasePlatformDependent.isUnsafeAvailable();
053  public final static boolean UNSAFE_UNALIGNED = HBasePlatformDependent.unaligned();
054
055  private ByteBufferUtils() {
056  }
057
058  static abstract class Comparer {
059    abstract int compareTo(byte[] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2);
060
061    abstract int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2);
062  }
063
064  static abstract class Converter {
065    abstract short toShort(ByteBuffer buffer, int offset);
066
067    abstract int toInt(ByteBuffer buffer);
068
069    abstract int toInt(ByteBuffer buffer, int offset);
070
071    abstract long toLong(ByteBuffer buffer, int offset);
072
073    abstract void putInt(ByteBuffer buffer, int val);
074
075    abstract int putInt(ByteBuffer buffer, int index, int val);
076
077    abstract void putShort(ByteBuffer buffer, short val);
078
079    abstract int putShort(ByteBuffer buffer, int index, short val);
080
081    abstract void putLong(ByteBuffer buffer, long val);
082
083    abstract int putLong(ByteBuffer buffer, int index, long val);
084  }
085
086  static abstract class CommonPrefixer {
087    abstract int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, byte[] right,
088      int rightOffset, int rightLength);
089
090    abstract int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, ByteBuffer right,
091      int rightOffset, int rightLength);
092  }
093
094  static class ComparerHolder {
095    static final String UNSAFE_COMPARER_NAME = ComparerHolder.class.getName() + "$UnsafeComparer";
096
097    static final Comparer BEST_COMPARER = getBestComparer();
098
099    static Comparer getBestComparer() {
100      try {
101        Class<? extends Comparer> theClass =
102          Class.forName(UNSAFE_COMPARER_NAME).asSubclass(Comparer.class);
103
104        return theClass.getConstructor().newInstance();
105      } catch (Throwable t) { // ensure we really catch *everything*
106        return PureJavaComparer.INSTANCE;
107      }
108    }
109
110    static final class PureJavaComparer extends Comparer {
111      static final PureJavaComparer INSTANCE = new PureJavaComparer();
112
113      private PureJavaComparer() {
114      }
115
116      @Override
117      public int compareTo(byte[] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
118        int end1 = o1 + l1;
119        int end2 = o2 + l2;
120        for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
121          int a = buf1[i] & 0xFF;
122          int b = buf2.get(j) & 0xFF;
123          if (a != b) {
124            return a - b;
125          }
126        }
127        return l1 - l2;
128      }
129
130      @Override
131      public int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
132        int end1 = o1 + l1;
133        int end2 = o2 + l2;
134        for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
135          int a = buf1.get(i) & 0xFF;
136          int b = buf2.get(j) & 0xFF;
137          if (a != b) {
138            return a - b;
139          }
140        }
141        return l1 - l2;
142      }
143    }
144
145    static final class UnsafeComparer extends Comparer {
146
147      public UnsafeComparer() {
148      }
149
150      static {
151        if (!UNSAFE_UNALIGNED) {
152          throw new Error();
153        }
154      }
155
156      @Override
157      public int compareTo(byte[] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
158        long offset2Adj;
159        Object refObj2 = null;
160        if (buf2.isDirect()) {
161          offset2Adj = o2 + UnsafeAccess.directBufferAddress(buf2);
162        } else {
163          offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
164          refObj2 = buf2.array();
165        }
166        return compareToUnsafe(buf1, o1 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, l1, refObj2,
167          offset2Adj, l2);
168      }
169
170      @Override
171      public int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
172        long offset1Adj, offset2Adj;
173        Object refObj1 = null, refObj2 = null;
174        if (buf1.isDirect()) {
175          offset1Adj = o1 + UnsafeAccess.directBufferAddress(buf1);
176        } else {
177          offset1Adj = o1 + buf1.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
178          refObj1 = buf1.array();
179        }
180        if (buf2.isDirect()) {
181          offset2Adj = o2 + UnsafeAccess.directBufferAddress(buf2);
182        } else {
183          offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
184          refObj2 = buf2.array();
185        }
186        return compareToUnsafe(refObj1, offset1Adj, l1, refObj2, offset2Adj, l2);
187      }
188    }
189  }
190
191  static class ConverterHolder {
192    static final String UNSAFE_CONVERTER_NAME =
193      ConverterHolder.class.getName() + "$UnsafeConverter";
194    static final Converter BEST_CONVERTER = getBestConverter();
195
196    static Converter getBestConverter() {
197      try {
198        Class<? extends Converter> theClass =
199          Class.forName(UNSAFE_CONVERTER_NAME).asSubclass(Converter.class);
200
201        // yes, UnsafeComparer does implement Comparer<byte[]>
202        return theClass.getConstructor().newInstance();
203      } catch (Throwable t) { // ensure we really catch *everything*
204        return PureJavaConverter.INSTANCE;
205      }
206    }
207
208    static final class PureJavaConverter extends Converter {
209      static final PureJavaConverter INSTANCE = new PureJavaConverter();
210
211      private PureJavaConverter() {
212      }
213
214      @Override
215      short toShort(ByteBuffer buffer, int offset) {
216        return buffer.getShort(offset);
217      }
218
219      @Override
220      int toInt(ByteBuffer buffer) {
221        return buffer.getInt();
222      }
223
224      @Override
225      int toInt(ByteBuffer buffer, int offset) {
226        return buffer.getInt(offset);
227      }
228
229      @Override
230      long toLong(ByteBuffer buffer, int offset) {
231        return buffer.getLong(offset);
232      }
233
234      @Override
235      void putInt(ByteBuffer buffer, int val) {
236        buffer.putInt(val);
237      }
238
239      @Override
240      int putInt(ByteBuffer buffer, int index, int val) {
241        buffer.putInt(index, val);
242        return index + Bytes.SIZEOF_INT;
243      }
244
245      @Override
246      void putShort(ByteBuffer buffer, short val) {
247        buffer.putShort(val);
248      }
249
250      @Override
251      int putShort(ByteBuffer buffer, int index, short val) {
252        buffer.putShort(index, val);
253        return index + Bytes.SIZEOF_SHORT;
254      }
255
256      @Override
257      void putLong(ByteBuffer buffer, long val) {
258        buffer.putLong(val);
259      }
260
261      @Override
262      int putLong(ByteBuffer buffer, int index, long val) {
263        buffer.putLong(index, val);
264        return index + Bytes.SIZEOF_LONG;
265      }
266    }
267
268    static final class UnsafeConverter extends Converter {
269
270      public UnsafeConverter() {
271      }
272
273      static {
274        if (!UNSAFE_UNALIGNED) {
275          throw new Error();
276        }
277      }
278
279      @Override
280      short toShort(ByteBuffer buffer, int offset) {
281        return UnsafeAccess.toShort(buffer, offset);
282      }
283
284      @Override
285      int toInt(ByteBuffer buffer) {
286        int i = UnsafeAccess.toInt(buffer, buffer.position());
287        buffer.position(buffer.position() + Bytes.SIZEOF_INT);
288        return i;
289      }
290
291      @Override
292      int toInt(ByteBuffer buffer, int offset) {
293        return UnsafeAccess.toInt(buffer, offset);
294      }
295
296      @Override
297      long toLong(ByteBuffer buffer, int offset) {
298        return UnsafeAccess.toLong(buffer, offset);
299      }
300
301      @Override
302      void putInt(ByteBuffer buffer, int val) {
303        int newPos = UnsafeAccess.putInt(buffer, buffer.position(), val);
304        buffer.position(newPos);
305      }
306
307      @Override
308      int putInt(ByteBuffer buffer, int index, int val) {
309        return UnsafeAccess.putInt(buffer, index, val);
310      }
311
312      @Override
313      void putShort(ByteBuffer buffer, short val) {
314        int newPos = UnsafeAccess.putShort(buffer, buffer.position(), val);
315        buffer.position(newPos);
316      }
317
318      @Override
319      int putShort(ByteBuffer buffer, int index, short val) {
320        return UnsafeAccess.putShort(buffer, index, val);
321      }
322
323      @Override
324      void putLong(ByteBuffer buffer, long val) {
325        int newPos = UnsafeAccess.putLong(buffer, buffer.position(), val);
326        buffer.position(newPos);
327      }
328
329      @Override
330      int putLong(ByteBuffer buffer, int index, long val) {
331        return UnsafeAccess.putLong(buffer, index, val);
332      }
333    }
334  }
335
336  static class CommonPrefixerHolder {
337    static final String UNSAFE_COMMON_PREFIXER_NAME =
338      CommonPrefixerHolder.class.getName() + "$UnsafeCommonPrefixer";
339
340    static final CommonPrefixer BEST_COMMON_PREFIXER = getBestCommonPrefixer();
341
342    static CommonPrefixer getBestCommonPrefixer() {
343      try {
344        Class<? extends CommonPrefixer> theClass =
345          Class.forName(UNSAFE_COMMON_PREFIXER_NAME).asSubclass(CommonPrefixer.class);
346
347        return theClass.getConstructor().newInstance();
348      } catch (Throwable t) { // ensure we really catch *everything*
349        return PureJavaCommonPrefixer.INSTANCE;
350      }
351    }
352
353    static final class PureJavaCommonPrefixer extends CommonPrefixer {
354      static final PureJavaCommonPrefixer INSTANCE = new PureJavaCommonPrefixer();
355
356      private PureJavaCommonPrefixer() {
357      }
358
359      @Override
360      public int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, byte[] right,
361        int rightOffset, int rightLength) {
362        int length = Math.min(leftLength, rightLength);
363        int result = 0;
364
365        while (
366          result < length
367            && ByteBufferUtils.toByte(left, leftOffset + result) == right[rightOffset + result]
368        ) {
369          result++;
370        }
371
372        return result;
373      }
374
375      @Override
376      int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, ByteBuffer right,
377        int rightOffset, int rightLength) {
378        int length = Math.min(leftLength, rightLength);
379        int result = 0;
380
381        while (
382          result < length && ByteBufferUtils.toByte(left, leftOffset + result)
383              == ByteBufferUtils.toByte(right, rightOffset + result)
384        ) {
385          result++;
386        }
387
388        return result;
389      }
390    }
391
392    static final class UnsafeCommonPrefixer extends CommonPrefixer {
393
394      static {
395        if (!UNSAFE_UNALIGNED) {
396          throw new Error();
397        }
398      }
399
400      public UnsafeCommonPrefixer() {
401      }
402
403      @Override
404      public int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, byte[] right,
405        int rightOffset, int rightLength) {
406        long offset1Adj;
407        Object refObj1 = null;
408        if (left.isDirect()) {
409          offset1Adj = leftOffset + UnsafeAccess.directBufferAddress(left);
410        } else {
411          offset1Adj = leftOffset + left.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
412          refObj1 = left.array();
413        }
414        return findCommonPrefixUnsafe(refObj1, offset1Adj, leftLength, right,
415          rightOffset + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, rightLength);
416      }
417
418      @Override
419      public int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, ByteBuffer right,
420        int rightOffset, int rightLength) {
421        long offset1Adj, offset2Adj;
422        Object refObj1 = null, refObj2 = null;
423        if (left.isDirect()) {
424          offset1Adj = leftOffset + UnsafeAccess.directBufferAddress(left);
425        } else {
426          offset1Adj = leftOffset + left.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
427          refObj1 = left.array();
428        }
429        if (right.isDirect()) {
430          offset2Adj = rightOffset + UnsafeAccess.directBufferAddress(right);
431        } else {
432          offset2Adj = rightOffset + right.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
433          refObj2 = right.array();
434        }
435        return findCommonPrefixUnsafe(refObj1, offset1Adj, leftLength, refObj2, offset2Adj,
436          rightLength);
437      }
438    }
439  }
440
441  /**
442   * Similar to {@link WritableUtils#writeVLong(java.io.DataOutput, long)}, but writes to a
443   * {@link ByteBuffer}.
444   */
445  public static void writeVLong(ByteBuffer out, long i) {
446    if (i >= -112 && i <= 127) {
447      out.put((byte) i);
448      return;
449    }
450
451    int len = -112;
452    if (i < 0) {
453      i ^= -1L; // take one's complement
454      len = -120;
455    }
456
457    long tmp = i;
458    while (tmp != 0) {
459      tmp = tmp >> 8;
460      len--;
461    }
462
463    out.put((byte) len);
464
465    len = (len < -120) ? -(len + 120) : -(len + 112);
466
467    for (int idx = len; idx != 0; idx--) {
468      int shiftbits = (idx - 1) * 8;
469      long mask = 0xFFL << shiftbits;
470      out.put((byte) ((i & mask) >> shiftbits));
471    }
472  }
473
474  private interface ByteVisitor {
475    byte get();
476  }
477
478  private static long readVLong(ByteVisitor visitor) {
479    byte firstByte = visitor.get();
480    int len = WritableUtils.decodeVIntSize(firstByte);
481    if (len == 1) {
482      return firstByte;
483    }
484    long i = 0;
485    for (int idx = 0; idx < len - 1; idx++) {
486      byte b = visitor.get();
487      i = i << 8;
488      i = i | (b & 0xFF);
489    }
490    return (WritableUtils.isNegativeVInt(firstByte) ? (i ^ -1L) : i);
491  }
492
493  /**
494   * Similar to {@link WritableUtils#readVLong(DataInput)} but reads from a {@link ByteBuffer}.
495   */
496  public static long readVLong(ByteBuffer in) {
497    return readVLong(in::get);
498  }
499
500  /**
501   * Similar to {@link WritableUtils#readVLong(java.io.DataInput)} but reads from a
502   * {@link ByteBuff}.
503   */
504  public static long readVLong(ByteBuff in) {
505    return readVLong(in::get);
506  }
507
508  /**
509   * Put in buffer integer using 7 bit encoding. For each written byte: 7 bits are used to store
510   * value 1 bit is used to indicate whether there is next bit.
511   * @param value Int to be compressed.
512   * @param out   Where to put compressed data
513   * @return Number of bytes written.
514   * @throws IOException on stream error
515   */
516  public static int putCompressedInt(OutputStream out, final int value) throws IOException {
517    int i = 0;
518    int tmpvalue = value;
519    do {
520      byte b = (byte) (tmpvalue & VALUE_MASK);
521      tmpvalue >>>= NEXT_BIT_SHIFT;
522      if (tmpvalue != 0) {
523        b |= (byte) NEXT_BIT_MASK;
524      }
525      out.write(b);
526      i++;
527    } while (tmpvalue != 0);
528    return i;
529  }
530
531  /**
532   * Put in output stream 32 bit integer (Big Endian byte order).
533   * @param out   Where to put integer.
534   * @param value Value of integer.
535   * @throws IOException On stream error.
536   */
537  public static void putInt(OutputStream out, final int value) throws IOException {
538    // We have writeInt in ByteBufferOutputStream so that it can directly write
539    // int to underlying
540    // ByteBuffer in one step.
541    if (out instanceof ByteBufferWriter) {
542      ((ByteBufferWriter) out).writeInt(value);
543    } else {
544      StreamUtils.writeInt(out, value);
545    }
546  }
547
548  public static byte toByte(ByteBuffer buffer, int offset) {
549    if (UNSAFE_AVAIL) {
550      return UnsafeAccess.toByte(buffer, offset);
551    } else {
552      return buffer.get(offset);
553    }
554  }
555
556  /**
557   * Copy the data to the output stream and update position in buffer.
558   * @param out    the stream to write bytes to
559   * @param in     the buffer to read bytes from
560   * @param length the number of bytes to copy
561   */
562  public static void moveBufferToStream(OutputStream out, ByteBuffer in, int length)
563    throws IOException {
564    copyBufferToStream(out, in, in.position(), length);
565    skip(in, length);
566  }
567
568  /**
569   * Copy data from a buffer to an output stream. Does not update the position in the buffer.
570   * @param out    the stream to write bytes to
571   * @param in     the buffer to read bytes from
572   * @param offset the offset in the buffer (from the buffer's array offset) to start copying bytes
573   *               from
574   * @param length the number of bytes to copy
575   */
576  public static void copyBufferToStream(OutputStream out, ByteBuffer in, int offset, int length)
577    throws IOException {
578    if (out instanceof ByteBufferWriter) {
579      ((ByteBufferWriter) out).write(in, offset, length);
580    } else if (in.hasArray()) {
581      out.write(in.array(), in.arrayOffset() + offset, length);
582    } else {
583      for (int i = 0; i < length; ++i) {
584        out.write(toByte(in, offset + i));
585      }
586    }
587  }
588
589  /**
590   * Copy data from a buffer to an output stream. Does not update the position in the buffer.
591   * @param out    the output stream to write bytes to
592   * @param in     the buffer to read bytes from
593   * @param offset the offset in the buffer (from the buffer's array offset) to start copying bytes
594   *               from
595   * @param length the number of bytes to copy
596   */
597  public static void copyBufferToStream(DataOutput out, ByteBuffer in, int offset, int length)
598    throws IOException {
599    if (out instanceof ByteBufferWriter) {
600      ((ByteBufferWriter) out).write(in, offset, length);
601    } else if (in.hasArray()) {
602      out.write(in.array(), in.arrayOffset() + offset, length);
603    } else {
604      for (int i = 0; i < length; ++i) {
605        out.write(toByte(in, offset + i));
606      }
607    }
608  }
609
610  public static int putLong(OutputStream out, final long value, final int fitInBytes)
611    throws IOException {
612    long tmpValue = value;
613    for (int i = 0; i < fitInBytes; ++i) {
614      out.write((byte) (tmpValue & 0xff));
615      tmpValue >>>= 8;
616    }
617    return fitInBytes;
618  }
619
620  public static int putByte(ByteBuffer buffer, int offset, byte b) {
621    if (UNSAFE_AVAIL) {
622      return UnsafeAccess.putByte(buffer, offset, b);
623    } else {
624      buffer.put(offset, b);
625      return offset + 1;
626    }
627  }
628
629  /**
630   * Check how many bytes are required to store value.
631   * @param value Value which size will be tested.
632   * @return How many bytes are required to store value.
633   */
634  public static int longFitsIn(final long value) {
635    if (value < 0) {
636      return 8;
637    }
638
639    if (value < (1L << (4 * 8))) {
640      // no more than 4 bytes
641      if (value < (1L << (2 * 8))) {
642        if (value < (1L << (1 * 8))) {
643          return 1;
644        }
645        return 2;
646      }
647      if (value < (1L << (3 * 8))) {
648        return 3;
649      }
650      return 4;
651    }
652    // more than 4 bytes
653    if (value < (1L << (6 * 8))) {
654      if (value < (1L << (5 * 8))) {
655        return 5;
656      }
657      return 6;
658    }
659    if (value < (1L << (7 * 8))) {
660      return 7;
661    }
662    return 8;
663  }
664
665  /**
666   * Check how many bytes is required to store value.
667   * @param value Value which size will be tested.
668   * @return How many bytes are required to store value.
669   */
670  public static int intFitsIn(final int value) {
671    if (value < 0) {
672      return 4;
673    }
674
675    if (value < (1 << (2 * 8))) {
676      if (value < (1 << (1 * 8))) {
677        return 1;
678      }
679      return 2;
680    }
681    if (value <= (1 << (3 * 8))) {
682      return 3;
683    }
684    return 4;
685  }
686
687  /**
688   * Read integer from stream coded in 7 bits and increment position.
689   * @return the integer that has been read
690   * @throws IOException on stream error
691   */
692  public static int readCompressedInt(InputStream input) throws IOException {
693    int result = 0;
694    int i = 0;
695    byte b;
696    do {
697      b = (byte) input.read();
698      result += (b & VALUE_MASK) << (NEXT_BIT_SHIFT * i);
699      i++;
700      if (i > Bytes.SIZEOF_INT + 1) {
701        throw new IllegalStateException(
702          "Corrupted compressed int (too long: " + (i + 1) + " bytes)");
703      }
704    } while (0 != (b & NEXT_BIT_MASK));
705    return result;
706  }
707
708  /**
709   * Read integer from buffer coded in 7 bits and increment position.
710   * @return Read integer.
711   */
712  public static int readCompressedInt(ByteBuffer buffer) {
713    byte b = buffer.get();
714    if ((b & NEXT_BIT_MASK) != 0) {
715      return (b & VALUE_MASK) + (readCompressedInt(buffer) << NEXT_BIT_SHIFT);
716    }
717    return b & VALUE_MASK;
718  }
719
720  /**
721   * Read long which was written to fitInBytes bytes and increment position.
722   * @param fitInBytes In how many bytes given long is stored.
723   * @return The value of parsed long.
724   * @throws IOException on stream error
725   */
726  public static long readLong(InputStream in, final int fitInBytes) throws IOException {
727    long tmpLong = 0;
728    for (int i = 0; i < fitInBytes; ++i) {
729      tmpLong |= (in.read() & 0xffL) << (8 * i);
730    }
731    return tmpLong;
732  }
733
734  /**
735   * Read long which was written to fitInBytes bytes and increment position.
736   * @param fitInBytes In how many bytes given long is stored.
737   * @return The value of parsed long.
738   */
739  public static long readLong(ByteBuffer in, final int fitInBytes) {
740    long tmpLength = 0;
741    for (int i = 0; i < fitInBytes; ++i) {
742      tmpLength |= (in.get() & 0xffL) << (8L * i);
743    }
744    return tmpLength;
745  }
746
747  /**
748   * Copy the given number of bytes from the given stream and put it at the current position of the
749   * given buffer, updating the position in the buffer.
750   * @param out    the buffer to write data to
751   * @param in     the stream to read data from
752   * @param length the number of bytes to read/write
753   */
754  public static void copyFromStreamToBuffer(ByteBuffer out, DataInputStream in, int length)
755    throws IOException {
756    if (out.hasArray()) {
757      in.readFully(out.array(), out.position() + out.arrayOffset(), length);
758      skip(out, length);
759    } else {
760      for (int i = 0; i < length; ++i) {
761        out.put(in.readByte());
762      }
763    }
764  }
765
766  /**
767   * Copy from the InputStream to a new heap ByteBuffer until the InputStream is exhausted.
768   */
769  public static ByteBuffer drainInputStreamToBuffer(InputStream is) throws IOException {
770    ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
771    IOUtils.copyBytes(is, baos, 4096, true);
772    ByteBuffer buffer = ByteBuffer.wrap(baos.toByteArray());
773    buffer.rewind();
774    return buffer;
775  }
776
777  /**
778   * Copy one buffer's whole data to another. Write starts at the current position of 'out' buffer.
779   * Note : This will advance the position marker of {@code out} and also change the position maker
780   * for {@code in}.
781   * @param in  source buffer
782   * @param out destination buffer
783   */
784  public static void copyFromBufferToBuffer(ByteBuffer in, ByteBuffer out) {
785    if (in.hasArray() && out.hasArray()) {
786      int length = in.remaining();
787      System.arraycopy(in.array(), in.arrayOffset(), out.array(), out.arrayOffset(), length);
788      out.position(out.position() + length);
789      in.position(in.limit());
790    } else if (UNSAFE_AVAIL) {
791      int length = in.remaining();
792      UnsafeAccess.copy(in, in.position(), out, out.position(), length);
793      out.position(out.position() + length);
794      in.position(in.limit());
795    } else {
796      out.put(in);
797    }
798  }
799
800  /**
801   * Copy from one buffer to another from given offset. This will be absolute positional copying and
802   * won't affect the position of any of the buffers.
803   * @param in                input bytebuffer
804   * @param out               destination bytebuffer
805   * @param sourceOffset      offset of source buffer
806   * @param destinationOffset offset of destination buffer
807   * @param length            the number of bytes to copy
808   */
809  public static void copyFromBufferToBuffer(ByteBuffer in, ByteBuffer out, int sourceOffset,
810    int destinationOffset, int length) {
811    if (in.hasArray() && out.hasArray()) {
812      System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out.array(),
813        out.arrayOffset() + destinationOffset, length);
814    } else if (UNSAFE_AVAIL) {
815      UnsafeAccess.copy(in, sourceOffset, out, destinationOffset, length);
816    } else {
817      ByteBuffer outDup = out.duplicate();
818      outDup.position(destinationOffset);
819      ByteBuffer inDup = in.duplicate();
820      inDup.position(sourceOffset).limit(sourceOffset + length);
821      outDup.put(inDup);
822    }
823    // We used to return a result but disabled; return destinationOffset + length;
824  }
825
826  /**
827   * Copy from one buffer to another from given offset.
828   * <p>
829   * Note : This will advance the position marker of {@code out} but not change the position maker
830   * for {@code in}
831   * @param in           source buffer
832   * @param out          destination buffer
833   * @param sourceOffset offset in the source buffer
834   * @param length       how many bytes to copy
835   */
836  public static void copyFromBufferToBuffer(ByteBuffer in, ByteBuffer out, int sourceOffset,
837    int length) {
838    if (in.hasArray() && out.hasArray()) {
839      System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out.array(),
840        out.position() + out.arrayOffset(), length);
841      skip(out, length);
842    } else if (UNSAFE_AVAIL) {
843      UnsafeAccess.copy(in, sourceOffset, out, out.position(), length);
844      skip(out, length);
845    } else {
846      ByteBuffer inDup = in.duplicate();
847      inDup.position(sourceOffset).limit(sourceOffset + length);
848      out.put(inDup);
849    }
850  }
851
852  /**
853   * Find length of common prefix of two parts in the buffer
854   * @param buffer      Where parts are located.
855   * @param offsetLeft  Offset of the first part.
856   * @param offsetRight Offset of the second part.
857   * @param limit       Maximal length of common prefix.
858   * @return Length of prefix.
859   */
860  @SuppressWarnings("unused")
861  public static int findCommonPrefix(ByteBuffer buffer, int offsetLeft, int offsetRight,
862    int limit) {
863    int prefix = 0;
864
865    for (; prefix < limit; ++prefix) {
866      if (buffer.get(offsetLeft + prefix) != buffer.get(offsetRight + prefix)) {
867        break;
868      }
869    }
870
871    return prefix;
872  }
873
874  /**
875   * Find length of common prefix in two arrays.
876   * @param left        Array to be compared.
877   * @param leftOffset  Offset in left array.
878   * @param leftLength  Length of left array.
879   * @param right       Array to be compared.
880   * @param rightOffset Offset in right array.
881   * @param rightLength Length of right array.
882   */
883  public static int findCommonPrefix(byte[] left, int leftOffset, int leftLength, byte[] right,
884    int rightOffset, int rightLength) {
885    return Bytes.findCommonPrefix(left, right, leftLength, rightLength, leftOffset, rightOffset);
886  }
887
888  /**
889   * Find length of common prefix in two arrays.
890   * @param left        ByteBuffer to be compared.
891   * @param leftOffset  Offset in left ByteBuffer.
892   * @param leftLength  Length of left ByteBuffer.
893   * @param right       ByteBuffer to be compared.
894   * @param rightOffset Offset in right ByteBuffer.
895   * @param rightLength Length of right ByteBuffer.
896   */
897  public static int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength,
898    ByteBuffer right, int rightOffset, int rightLength) {
899    return CommonPrefixerHolder.BEST_COMMON_PREFIXER.findCommonPrefix(left, leftOffset, leftLength,
900      right, rightOffset, rightLength);
901  }
902
903  /**
904   * Find length of common prefix in two arrays.
905   * @param left        ByteBuffer to be compared.
906   * @param leftOffset  Offset in left ByteBuffer.
907   * @param leftLength  Length of left ByteBuffer.
908   * @param right       Array to be compared
909   * @param rightOffset Offset in right Array.
910   * @param rightLength Length of right Array.
911   */
912  public static int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, byte[] right,
913    int rightOffset, int rightLength) {
914    return CommonPrefixerHolder.BEST_COMMON_PREFIXER.findCommonPrefix(left, leftOffset, leftLength,
915      right, rightOffset, rightLength);
916  }
917
918  /**
919   * Check whether two parts in the same buffer are equal.
920   * @param buffer      In which buffer there are parts
921   * @param offsetLeft  Beginning of first part.
922   * @param lengthLeft  Length of the first part.
923   * @param offsetRight Beginning of the second part.
924   * @param lengthRight Length of the second part.
925   * @return True if equal
926   */
927  public static boolean arePartsEqual(ByteBuffer buffer, int offsetLeft, int lengthLeft,
928    int offsetRight, int lengthRight) {
929    if (lengthLeft != lengthRight) {
930      return false;
931    }
932
933    if (buffer.hasArray()) {
934      return 0 == Bytes.compareTo(buffer.array(), buffer.arrayOffset() + offsetLeft, lengthLeft,
935        buffer.array(), buffer.arrayOffset() + offsetRight, lengthRight);
936    }
937
938    for (int i = 0; i < lengthRight; ++i) {
939      if (buffer.get(offsetLeft + i) != buffer.get(offsetRight + i)) {
940        return false;
941      }
942    }
943    return true;
944  }
945
946  /**
947   * Increment position in buffer.
948   * @param buffer In this buffer.
949   * @param length By that many bytes.
950   */
951  public static void skip(ByteBuffer buffer, int length) {
952    buffer.position(buffer.position() + length);
953  }
954
955  public static void extendLimit(ByteBuffer buffer, int numBytes) {
956    buffer.limit(buffer.limit() + numBytes);
957  }
958
959  /**
960   * Copy the bytes from position to limit into a new byte[] of the exact length and sets the
961   * position and limit back to their original values (though not thread safe).
962   * @param buffer        copy from here
963   * @param startPosition put buffer.get(startPosition) into byte[0]
964   * @return a new byte[] containing the bytes in the specified range
965   */
966  public static byte[] toBytes(ByteBuffer buffer, int startPosition) {
967    int originalPosition = buffer.position();
968    byte[] output = new byte[buffer.limit() - startPosition];
969    buffer.position(startPosition);
970    buffer.get(output);
971    buffer.position(originalPosition);
972    return output;
973  }
974
975  /**
976   * Copy the given number of bytes from specified offset into a new byte[]
977   * @param buffer input bytebuffer to read
978   * @param offset input offset where Bytes are
979   * @param length the number of bytes to read
980   * @return a new byte[] containing the bytes in the specified range
981   */
982  public static byte[] toBytes(ByteBuffer buffer, int offset, int length) {
983    byte[] output = new byte[length];
984    for (int i = 0; i < length; i++) {
985      output[i] = buffer.get(offset + i);
986    }
987    return output;
988  }
989
990  public static boolean equals(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
991    if ((l1 == 0) || (l2 == 0)) {
992      // both 0 length, return true, or else false
993      return l1 == l2;
994    }
995    // Since we're often comparing adjacent sorted data,
996    // it's usual to have equal arrays except for the very last byte
997    // so check that first
998    if (toByte(buf1, o1 + l1 - 1) != toByte(buf2, o2 + l2 - 1)) {
999      return false;
1000    }
1001    return compareTo(buf1, o1, l1, buf2, o2, l2) == 0;
1002  }
1003
1004  /**
1005   * ByteBuffer to hash offset to start from length to hash
1006   */
1007  public static int hashCode(ByteBuffer buf, int offset, int length) {
1008    int hash = 1;
1009    for (int i = offset; i < offset + length; i++) {
1010      hash = (31 * hash) + (int) toByte(buf, i);
1011    }
1012    return hash;
1013  }
1014
1015  public static int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
1016    return ComparerHolder.BEST_COMPARER.compareTo(buf1, o1, l1, buf2, o2, l2);
1017  }
1018
1019  public static boolean equals(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
1020    if ((l1 == 0) || (l2 == 0)) {
1021      // both 0 length, return true, or else false
1022      return l1 == l2;
1023    }
1024    // Since we're often comparing adjacent sorted data,
1025    // it's usual to have equal arrays except for the very last byte
1026    // so check that first
1027    if (toByte(buf1, o1 + l1 - 1) != buf2[o2 + l2 - 1]) {
1028      return false;
1029    }
1030    return compareTo(buf1, o1, l1, buf2, o2, l2) == 0;
1031  }
1032
1033  // The below two methods show up in lots of places. Versions of them in commons util and in
1034  // Cassandra. In guava too? They are copied from ByteBufferUtils. They are here as static
1035  // privates. Seems to make code smaller and make Hotspot happier (comes of compares and study
1036  // of compiled code via jitwatch).
1037
1038  public static int compareTo(byte[] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
1039    return ComparerHolder.BEST_COMPARER.compareTo(buf1, o1, l1, buf2, o2, l2);
1040  }
1041
1042  public static int compareTo(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
1043    return compareTo(buf2, o2, l2, buf1, o1, l1) * -1;
1044  }
1045
1046  static int compareToUnsafe(Object obj1, long o1, int l1, Object obj2, long o2, int l2) {
1047    final int stride = 8;
1048    final int minLength = Math.min(l1, l2);
1049    int strideLimit = minLength & ~(stride - 1);
1050    int i;
1051
1052    /*
1053     * Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a time is no slower than
1054     * comparing 4 bytes at a time even on 32-bit. On the other hand, it is substantially faster on
1055     * 64-bit.
1056     */
1057    for (i = 0; i < strideLimit; i += stride) {
1058      long lw = HBasePlatformDependent.getLong(obj1, o1 + (long) i);
1059      long rw = HBasePlatformDependent.getLong(obj2, o2 + (long) i);
1060      if (lw != rw) {
1061        if (!UnsafeAccess.LITTLE_ENDIAN) {
1062          return ((lw + Long.MIN_VALUE) < (rw + Long.MIN_VALUE)) ? -1 : 1;
1063        }
1064
1065        /*
1066         * We want to compare only the first index where left[index] != right[index]. This
1067         * corresponds to the least significant nonzero byte in lw ^ rw, since lw and rw are
1068         * little-endian. Long.numberOfTrailingZeros(diff) tells us the least significant nonzero
1069         * bit, and zeroing out the first three bits of L.nTZ gives us the shift to get that least
1070         * significant nonzero byte. This comparison logic is based on UnsignedBytes from guava v21
1071         */
1072        int n = Long.numberOfTrailingZeros(lw ^ rw) & ~0x7;
1073        return ((int) ((lw >>> n) & 0xFF)) - ((int) ((rw >>> n) & 0xFF));
1074      }
1075    }
1076
1077    // The epilogue to cover the last (minLength % stride) elements.
1078    for (; i < minLength; i++) {
1079      int il = (HBasePlatformDependent.getByte(obj1, o1 + i) & 0xFF);
1080      int ir = (HBasePlatformDependent.getByte(obj2, o2 + i) & 0xFF);
1081      if (il != ir) {
1082        return il - ir;
1083      }
1084    }
1085    return l1 - l2;
1086  }
1087
1088  static int findCommonPrefixUnsafe(Object left, long leftOffset, int leftLength, Object right,
1089    long rightOffset, int rightLength) {
1090    final int stride = 8;
1091    final int minLength = Math.min(leftLength, rightLength);
1092    int strideLimit = minLength & ~(stride - 1);
1093    int result = 0;
1094    int i;
1095
1096    for (i = 0; i < strideLimit; i += stride) {
1097      long lw = HBasePlatformDependent.getLong(left, leftOffset + (long) i);
1098      long rw = HBasePlatformDependent.getLong(right, rightOffset + (long) i);
1099
1100      if (lw != rw) {
1101        if (!UnsafeAccess.LITTLE_ENDIAN) {
1102          return result + (Long.numberOfLeadingZeros(lw ^ rw) / Bytes.SIZEOF_LONG);
1103        } else {
1104          return result + (Long.numberOfTrailingZeros(lw ^ rw) / Bytes.SIZEOF_LONG);
1105        }
1106      } else {
1107        result += Bytes.SIZEOF_LONG;
1108      }
1109    }
1110
1111    // The epilogue to cover the last (minLength % stride) elements.
1112    for (; i < minLength; i++) {
1113      byte il = HBasePlatformDependent.getByte(left, leftOffset + i);
1114      byte ir = HBasePlatformDependent.getByte(right, rightOffset + i);
1115      if (il != ir) {
1116        return result;
1117      } else {
1118        result++;
1119      }
1120    }
1121
1122    return result;
1123  }
1124
1125  /**
1126   * Reads a short value at the given buffer's offset.
1127   * @param buffer input byte buffer to read
1128   * @param offset input offset where short is
1129   * @return short value at offset
1130   */
1131  public static short toShort(ByteBuffer buffer, int offset) {
1132    return ConverterHolder.BEST_CONVERTER.toShort(buffer, offset);
1133  }
1134
1135  /**
1136   * Reads an int value at the given buffer's current position. Also advances the buffer's position
1137   */
1138  public static int toInt(ByteBuffer buffer) {
1139    return ConverterHolder.BEST_CONVERTER.toInt(buffer);
1140  }
1141
1142  /**
1143   * Reads an int value at the given buffer's offset.
1144   * @param buffer input byte buffer to read
1145   * @param offset input offset where int is
1146   * @return int value at offset
1147   */
1148  public static int toInt(ByteBuffer buffer, int offset) {
1149    return ConverterHolder.BEST_CONVERTER.toInt(buffer, offset);
1150  }
1151
1152  /**
1153   * Converts a ByteBuffer to an int value
1154   * @param buf    The ByteBuffer
1155   * @param offset Offset to int value
1156   * @param length Number of bytes used to store the int value.
1157   * @return the int value if there's not enough bytes left in the buffer after the given offset
1158   */
1159  public static int readAsInt(ByteBuffer buf, int offset, final int length) {
1160    if (offset + length > buf.limit()) {
1161      throw new IllegalArgumentException("offset (" + offset + ") + length (" + length
1162        + ") exceed the" + " limit of the buffer: " + buf.limit());
1163    }
1164    int n = 0;
1165    for (int i = offset; i < (offset + length); i++) {
1166      n <<= 8;
1167      n ^= toByte(buf, i) & 0xFF;
1168    }
1169    return n;
1170  }
1171
1172  /**
1173   * Reads a long value at the given buffer's offset.
1174   * @param buffer input byte buffer to read
1175   * @param offset input offset where Long is
1176   * @return long value at offset
1177   */
1178  public static long toLong(ByteBuffer buffer, int offset) {
1179    return ConverterHolder.BEST_CONVERTER.toLong(buffer, offset);
1180  }
1181
1182  /**
1183   * Put an int value out to the given ByteBuffer's current position in big-endian format. This also
1184   * advances the position in buffer by int size.
1185   * @param buffer the ByteBuffer to write to
1186   * @param val    int to write out
1187   */
1188  public static void putInt(ByteBuffer buffer, int val) {
1189    ConverterHolder.BEST_CONVERTER.putInt(buffer, val);
1190  }
1191
1192  public static int putInt(ByteBuffer buffer, int index, int val) {
1193    return ConverterHolder.BEST_CONVERTER.putInt(buffer, index, val);
1194  }
1195
1196  /**
1197   * Reads a double value at the given buffer's offset.
1198   * @param buffer input byte buffer to read
1199   * @param offset offset where double is
1200   * @return double value at offset
1201   */
1202  public static double toDouble(ByteBuffer buffer, int offset) {
1203    return Double.longBitsToDouble(toLong(buffer, offset));
1204  }
1205
1206  /**
1207   * Reads a BigDecimal value at the given buffer's offset.
1208   * @param buffer input bytebuffer to read
1209   * @param offset input offset
1210   * @return BigDecimal value at offset
1211   */
1212  public static BigDecimal toBigDecimal(ByteBuffer buffer, int offset, int length) {
1213    if (buffer == null || length < Bytes.SIZEOF_INT + 1 || (offset + length > buffer.limit())) {
1214      return null;
1215    }
1216
1217    int scale = toInt(buffer, offset);
1218    byte[] tcBytes = new byte[length - Bytes.SIZEOF_INT];
1219    copyFromBufferToArray(tcBytes, buffer, offset + Bytes.SIZEOF_INT, 0, length - Bytes.SIZEOF_INT);
1220    return new BigDecimal(new BigInteger(tcBytes), scale);
1221  }
1222
1223  /**
1224   * Put a short value out to the given ByteBuffer's current position in big-endian format. This
1225   * also advances the position in buffer by short size.
1226   * @param buffer the ByteBuffer to write to
1227   * @param val    short to write out
1228   */
1229  public static void putShort(ByteBuffer buffer, short val) {
1230    ConverterHolder.BEST_CONVERTER.putShort(buffer, val);
1231  }
1232
1233  public static int putShort(ByteBuffer buffer, int index, short val) {
1234    return ConverterHolder.BEST_CONVERTER.putShort(buffer, index, val);
1235  }
1236
1237  public static int putAsShort(ByteBuffer buf, int index, int val) {
1238    buf.put(index + 1, (byte) val);
1239    val >>= 8;
1240    buf.put(index, (byte) val);
1241    return index + Bytes.SIZEOF_SHORT;
1242  }
1243
1244  /**
1245   * Put a long value out to the given ByteBuffer's current position in big-endian format. This also
1246   * advances the position in buffer by long size.
1247   * @param buffer the ByteBuffer to write to
1248   * @param val    long to write out
1249   */
1250  public static void putLong(ByteBuffer buffer, long val) {
1251    ConverterHolder.BEST_CONVERTER.putLong(buffer, val);
1252  }
1253
1254  public static int putLong(ByteBuffer buffer, int index, long val) {
1255    return ConverterHolder.BEST_CONVERTER.putLong(buffer, index, val);
1256  }
1257
1258  /**
1259   * Copies the bytes from given array's offset to length part into the given buffer. Puts the bytes
1260   * to buffer's current position. This also advances the position in the 'out' buffer by 'length'
1261   * @param out      output bytebuffer to copy to
1262   * @param in       input array to copy from
1263   * @param inOffset input offset to copy from
1264   * @param length   the number of bytes to copy
1265   */
1266  public static void copyFromArrayToBuffer(ByteBuffer out, byte[] in, int inOffset, int length) {
1267    if (out.hasArray()) {
1268      System.arraycopy(in, inOffset, out.array(), out.arrayOffset() + out.position(), length);
1269      // Move the position in out by length
1270      out.position(out.position() + length);
1271    } else if (UNSAFE_AVAIL) {
1272      UnsafeAccess.copy(in, inOffset, out, out.position(), length);
1273      // Move the position in out by length
1274      out.position(out.position() + length);
1275    } else {
1276      out.put(in, inOffset, length);
1277    }
1278  }
1279
1280  /**
1281   * Copies bytes from given array's offset to length part into the given buffer. Puts the bytes to
1282   * buffer's given position. This doesn't affect the position of buffer.
1283   * @param out       output bytebuffer to copy to
1284   * @param outOffset output buffer offset
1285   * @param in        input array to copy from
1286   * @param inOffset  input offset to copy from
1287   * @param length    the number of bytes to copy
1288   */
1289  public static void copyFromArrayToBuffer(ByteBuffer out, int outOffset, byte[] in, int inOffset,
1290    int length) {
1291    if (out.hasArray()) {
1292      System.arraycopy(in, inOffset, out.array(), out.arrayOffset() + outOffset, length);
1293    } else if (UNSAFE_AVAIL) {
1294      UnsafeAccess.copy(in, inOffset, out, outOffset, length);
1295    } else {
1296      ByteBuffer outDup = out.duplicate();
1297      outDup.position(outOffset);
1298      outDup.put(in, inOffset, length);
1299    }
1300  }
1301
1302  /**
1303   * Copies specified number of bytes from given offset of 'in' ByteBuffer to the array. This
1304   * doesn't affect the position of buffer.
1305   * @param out               output array to copy input bytebuffer to
1306   * @param in                input bytebuffer to copy from
1307   * @param sourceOffset      offset of source bytebuffer
1308   * @param destinationOffset offset of destination array
1309   * @param length            the number of bytes to copy
1310   */
1311  public static void copyFromBufferToArray(byte[] out, ByteBuffer in, int sourceOffset,
1312    int destinationOffset, int length) {
1313    if (in.hasArray()) {
1314      System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out, destinationOffset, length);
1315    } else if (UNSAFE_AVAIL) {
1316      UnsafeAccess.copy(in, sourceOffset, out, destinationOffset, length);
1317    } else {
1318      ByteBuffer inDup = in.duplicate();
1319      inDup.position(sourceOffset);
1320      inDup.get(out, destinationOffset, length);
1321    }
1322  }
1323
1324  /**
1325   * Similar to {@link Arrays#copyOfRange(byte[], int, int)}
1326   * @param original the buffer from which the copy has to happen
1327   * @param from     the starting index
1328   * @param to       the ending index
1329   * @return a byte[] created out of the copy
1330   */
1331  public static byte[] copyOfRange(ByteBuffer original, int from, int to) {
1332    int newLength = to - from;
1333    if (newLength < 0) {
1334      throw new IllegalArgumentException(from + " > " + to);
1335    }
1336    byte[] copy = new byte[newLength];
1337    ByteBufferUtils.copyFromBufferToArray(copy, original, from, 0, newLength);
1338    return copy;
1339  }
1340
1341  // For testing purpose
1342  public static String toStringBinary(final ByteBuffer b, int off, int len) {
1343    StringBuilder result = new StringBuilder();
1344    // Just in case we are passed a 'len' that is > buffer length...
1345    if (off >= b.capacity()) {
1346      return result.toString();
1347    }
1348    if (off + len > b.capacity()) {
1349      len = b.capacity() - off;
1350    }
1351    for (int i = off; i < off + len; ++i) {
1352      int ch = b.get(i) & 0xFF;
1353      if (
1354        (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
1355          || " `~!@#$%^&*()-_=+[]{}|;:'\",.<>/?".indexOf(ch) >= 0
1356      ) {
1357        result.append((char) ch);
1358      } else {
1359        result.append(String.format("\\x%02X", ch));
1360      }
1361    }
1362    return result.toString();
1363  }
1364
1365  public static String toStringBinary(final ByteBuffer b) {
1366    return toStringBinary(b, 0, b.capacity());
1367  }
1368
1369  /**
1370   * Find index of passed delimiter.
1371   * @return Index of delimiter having started from start of <code>b</code> moving rightward.
1372   */
1373  public static int searchDelimiterIndex(ByteBuffer b, int offset, final int length,
1374    final int delimiter) {
1375    for (int i = offset, n = offset + length; i < n; i++) {
1376      if (b.get(i) == delimiter) {
1377        return i;
1378      }
1379    }
1380    return -1;
1381  }
1382
1383  /**
1384   * Find index of passed delimiter walking from end of buffer backwards.
1385   * @return Index of delimiter
1386   */
1387  public static int searchDelimiterIndexInReverse(ByteBuffer b, int offset, int length,
1388    int delimiter) {
1389    for (int i = offset + length - 1; i >= offset; i--) {
1390      if (b.get(i) == delimiter) {
1391        return i;
1392      }
1393    }
1394    return -1;
1395  }
1396}