Skip to content

Package: Buffers

Buffers

nameinstructionbranchcomplexitylinemethod
Buffers()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
appendBuffers(MemoryManager, Buffer, Buffer)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
appendBuffers(MemoryManager, Buffer, Buffer, boolean)
M: 70 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 19 C: 0
0%
M: 1 C: 0
0%
cloneBuffer(Buffer)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
cloneBuffer(Buffer, int, int)
M: 28 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
dumpBuffer(Appendable, Buffer)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
dumpBuffer0(Formatter, Appendable, Buffer)
M: 54 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 11 C: 0
0%
M: 1 C: 0
0%
dumpBuffer0(Formatter, Buffer)
M: 371 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 32 C: 0
0%
M: 1 C: 0
0%
fill(Buffer, byte)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
fill(Buffer, int, int, byte)
M: 43 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 13 C: 0
0%
M: 1 C: 0
0%
fill(ByteBuffer, byte)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
fill(ByteBuffer, int, int, byte)
M: 30 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
get(ByteBuffer, byte[], int, int)
M: 37 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getBufferAppender(boolean)
M: 6 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getChar(int)
M: 13 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
getDefaultMemoryManager()
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
put(Buffer, int, int, Buffer)
M: 107 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 22 C: 0
0%
M: 1 C: 0
0%
put(ByteBuffer, int, int, ByteBuffer)
M: 63 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
put(byte[], int, int, ByteBuffer)
M: 37 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
readFromFileChannel(FileChannel, Buffer)
M: 49 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 13 C: 0
0%
M: 1 C: 0
0%
setPositionLimit(Buffer, int, int)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
setPositionLimit(ByteBuffer, int, int)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
slice(ByteBuffer, int)
M: 22 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
slice(ByteBuffer, int, int)
M: 19 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 26 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
toStringContent(Buffer, int, int)
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
toStringContent(Buffer, int, int, Charset)
M: 92 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 17 C: 0
0%
M: 1 C: 0
0%
toStringContent(ByteBuffer, Charset, int, int)
M: 25 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
wrap(MemoryManager, ByteBuffer)
M: 28 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
wrap(MemoryManager, String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
wrap(MemoryManager, String, Charset)
M: 15 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
wrap(MemoryManager, byte[])
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
wrap(MemoryManager, byte[], int, int)
M: 29 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
writeToFileChannel(FileChannel, Buffer)
M: 49 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 13 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2008, 2020 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package org.glassfish.grizzly.memory;
18:
19: import java.io.IOException;
20: import java.io.UnsupportedEncodingException;
21: import java.nio.BufferOverflowException;
22: import java.nio.BufferUnderflowException;
23: import java.nio.ByteBuffer;
24: import java.nio.channels.FileChannel;
25: import java.nio.charset.Charset;
26: import java.util.Arrays;
27: import java.util.Formatter;
28: import java.util.logging.Level;
29: import java.util.logging.Logger;
30:
31: import org.glassfish.grizzly.Appender;
32: import org.glassfish.grizzly.Buffer;
33: import org.glassfish.grizzly.Grizzly;
34: import org.glassfish.grizzly.localization.LogMessages;
35:
36: /**
37: * Class has useful methods to simplify the work with {@link Buffer}s.
38: *
39: * @see Buffer
40: *
41: * @author Alexey Stashok
42: */
43:
44: public class Buffers {
45: private static final Logger LOGGER = Grizzly.logger(Buffers.class);
46:
47: private static final Appender<Buffer> APPENDER_DISPOSABLE = new BuffersAppender(true);
48: private static final Appender<Buffer> APPENDER_NOT_DISPOSABLE = new BuffersAppender(false);
49:
50: /**
51: * Get the {@link Appender} which knows how to append {@link Buffer}s. Returned {@link Appender} uses the same
52: * {@link Buffer} appending rules as described here
53: * {@link Buffers#appendBuffers(org.glassfish.grizzly.memory.MemoryManager, org.glassfish.grizzly.Buffer, org.glassfish.grizzly.Buffer, boolean)}.
54: *
55: * @param isCompositeBufferDisposable if as the result of {@link Buffer}s appending a new {@link CompositeBuffer} will
56: * be created - its {@link CompositeBuffer#allowBufferDispose(boolean)} value will be set according to this parameter.
57: * @return the {@link Buffer} {@link Appender}.
58: */
59: public static Appender<Buffer> getBufferAppender(final boolean isCompositeBufferDisposable) {
60:• return isCompositeBufferDisposable ? APPENDER_DISPOSABLE : APPENDER_NOT_DISPOSABLE;
61: }
62:
63: private static class BuffersAppender implements Appender<Buffer> {
64: private final boolean isCompositeBufferDisposable;
65:
66: public BuffersAppender(boolean isCompositeBufferDisposable) {
67: this.isCompositeBufferDisposable = isCompositeBufferDisposable;
68: }
69:
70: @Override
71: public Buffer append(final Buffer element1, final Buffer element2) {
72: return Buffers.appendBuffers(null, element1, element2, isCompositeBufferDisposable);
73: }
74: }
75:
76: public static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0);
77: @SuppressWarnings("unused")
78: public static final ByteBuffer[] EMPTY_BYTE_BUFFER_ARRAY = new ByteBuffer[0];
79:
80: public static final Buffer EMPTY_BUFFER;
81:
82: static {
83: EMPTY_BUFFER = new ByteBufferWrapper(ByteBuffer.allocate(0)) {
84: @Override
85: public void dispose() {
86: }
87: };
88: }
89:
90: /**
91: * Returns {@link Buffer}, which wraps the {@link String}.
92: *
93: * @param memoryManager {@link MemoryManager}, which should be used for wrapping.
94: * @param s {@link String}
95: *
96: * @return {@link Buffer} wrapper on top of passed {@link String}.
97: */
98: public static Buffer wrap(final MemoryManager memoryManager, final String s) {
99: return wrap(memoryManager, s, Charset.defaultCharset());
100: }
101:
102: /**
103: * Returns {@link Buffer}, which wraps the {@link String} with the specific {@link Charset}.
104: *
105: * @param memoryManager {@link MemoryManager}, which should be used for wrapping.
106: * @param s {@link String}
107: * @param charset {@link Charset}, which will be used, when converting {@link String} to byte array.
108: *
109: * @return {@link Buffer} wrapper on top of passed {@link String}.
110: */
111: public static Buffer wrap(final MemoryManager memoryManager, final String s, final Charset charset) {
112: try {
113: final byte[] byteRepresentation = s.getBytes(charset.name());
114: return wrap(memoryManager, byteRepresentation);
115: } catch (UnsupportedEncodingException e) {
116: throw new IllegalStateException(e);
117: }
118: }
119:
120: /**
121: * Returns {@link Buffer}, which wraps the byte array.
122: *
123: * @param memoryManager {@link MemoryManager}, which should be used for wrapping.
124: * @param array byte array to wrap.
125: *
126: * @return {@link Buffer} wrapper on top of passed byte array.
127: */
128: public static Buffer wrap(final MemoryManager memoryManager, final byte[] array) {
129: return wrap(memoryManager, array, 0, array.length);
130: }
131:
132: /**
133: * Returns {@link Buffer}, which wraps the part of byte array with specific offset and length.
134: *
135: * @param memoryManager {@link MemoryManager}, which should be used for wrapping.
136: * @param array byte array to wrap
137: * @param offset byte buffer offset
138: * @param length byte buffer length
139: *
140: * @return {@link Buffer} wrapper on top of passed byte array.
141: */
142: public static Buffer wrap(MemoryManager memoryManager, final byte[] array, final int offset, final int length) {
143:• if (memoryManager == null) {
144: memoryManager = getDefaultMemoryManager();
145: }
146:
147:• if (memoryManager instanceof WrapperAware) {
148: return ((WrapperAware) memoryManager).wrap(array, offset, length);
149: }
150:
151: final Buffer buffer = memoryManager.allocate(length);
152: buffer.put(array, offset, length);
153: buffer.flip();
154: return buffer;
155: }
156:
157: /**
158: * Returns {@link Buffer}, which wraps the {@link ByteBuffer}.
159: *
160: * @param memoryManager {@link MemoryManager}, which should be used for wrapping.
161: * @param byteBuffer {@link ByteBuffer} to wrap
162: *
163: * @return {@link Buffer} wrapper on top of passed {@link ByteBuffer}.
164: */
165: public static Buffer wrap(final MemoryManager memoryManager, final ByteBuffer byteBuffer) {
166:• if (memoryManager instanceof WrapperAware) {
167: return ((WrapperAware) memoryManager).wrap(byteBuffer);
168:• } else if (byteBuffer.hasArray()) {
169: return wrap(memoryManager, byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining());
170: }
171:
172: throw new IllegalStateException("Can not wrap ByteBuffer");
173: }
174:
175: /**
176: * Slice {@link ByteBuffer} of required size from big chunk. Passed chunk position will be changed, after the slicing
177: * (chunk.position += size).
178: *
179: * @param chunk big {@link ByteBuffer} pool.
180: * @param size required slice size.
181: *
182: * @return sliced {@link ByteBuffer} of required size.
183: */
184: public static ByteBuffer slice(final ByteBuffer chunk, final int size) {
185: chunk.limit(chunk.position() + size);
186: final ByteBuffer view = chunk.slice();
187: chunk.position(chunk.limit());
188: chunk.limit(chunk.capacity());
189:
190: return view;
191: }
192:
193: /**
194: * Get the {@link ByteBuffer}'s slice basing on its passed position and limit. Position and limit values of the passed
195: * {@link ByteBuffer} won't be changed. The result {@link ByteBuffer} position will be equal to 0, and limit equal to
196: * number of sliced bytes (limit - position).
197: *
198: * @param byteBuffer {@link ByteBuffer} to slice/
199: * @param position the position in the passed byteBuffer, the slice will start from.
200: * @param limit the limit in the passed byteBuffer, the slice will be ended.
201: *
202: * @return sliced {@link ByteBuffer} of required size.
203: */
204: public static ByteBuffer slice(final ByteBuffer byteBuffer, final int position, final int limit) {
205: final int oldPos = byteBuffer.position();
206: final int oldLimit = byteBuffer.limit();
207:
208: setPositionLimit(byteBuffer, position, limit);
209:
210: final ByteBuffer slice = byteBuffer.slice();
211:
212: setPositionLimit(byteBuffer, oldPos, oldLimit);
213:
214: return slice;
215: }
216:
217: public static String toStringContent(final ByteBuffer byteBuffer, Charset charset, final int position, final int limit) {
218:
219:• if (charset == null) {
220: charset = Charset.defaultCharset();
221: }
222:
223: final int oldPosition = byteBuffer.position();
224: final int oldLimit = byteBuffer.limit();
225: setPositionLimit(byteBuffer, position, limit);
226:
227: try {
228: return charset.decode(byteBuffer).toString();
229: } finally {
230: setPositionLimit(byteBuffer, oldPosition, oldLimit);
231: }
232: }
233:
234: public static void setPositionLimit(final Buffer buffer, final int position, final int limit) {
235: buffer.limit(limit);
236: buffer.position(position);
237: }
238:
239: public static void setPositionLimit(final ByteBuffer buffer, final int position, final int limit) {
240: buffer.limit(limit);
241: buffer.position(position);
242: }
243:
244: public static void put(final ByteBuffer srcBuffer, final int srcOffset, final int length, final ByteBuffer dstBuffer) {
245:
246:• if (dstBuffer.remaining() < length) {
247: LOGGER.log(Level.WARNING, LogMessages.WARNING_GRIZZLY_BUFFERS_OVERFLOW_EXCEPTION(srcBuffer, srcOffset, length, dstBuffer));
248: throw new BufferOverflowException();
249: }
250:
251:• if (srcBuffer.hasArray() && dstBuffer.hasArray()) {
252:
253: System.arraycopy(srcBuffer.array(), srcBuffer.arrayOffset() + srcOffset, dstBuffer.array(), dstBuffer.arrayOffset() + dstBuffer.position(), length);
254: dstBuffer.position(dstBuffer.position() + length);
255: } else {
256:• for (int i = srcOffset; i < srcOffset + length; i++) {
257: dstBuffer.put(srcBuffer.get(i));
258: }
259: }
260: }
261:
262: public static void put(final Buffer src, final int position, final int length, final Buffer dstBuffer) {
263:
264:• if (dstBuffer.remaining() < length) {
265: throw new BufferOverflowException();
266: }
267:
268:• if (!src.isComposite()) {
269: final ByteBuffer srcByteBuffer = src.toByteBuffer();
270:• if (srcByteBuffer.hasArray()) {
271: dstBuffer.put(srcByteBuffer.array(), srcByteBuffer.arrayOffset() + position, length);
272: } else {
273:• for (int i = 0; i < length; i++) {
274: dstBuffer.put(srcByteBuffer.get(position + i));
275: }
276: }
277: } else {
278: final ByteBufferArray array = src.toByteBufferArray(position, position + length);
279:
280: final ByteBuffer[] srcByteBuffers = array.getArray();
281:• for (int i = 0; i < array.size(); i++) {
282: final ByteBuffer srcByteBuffer = srcByteBuffers[i];
283: final int initialPosition = srcByteBuffer.position();
284: final int srcByteBufferLen = srcByteBuffer.remaining();
285:
286:• if (srcByteBuffer.hasArray()) {
287: dstBuffer.put(srcByteBuffer.array(), srcByteBuffer.arrayOffset() + initialPosition, srcByteBufferLen);
288: } else {
289:• for (int j = 0; j < srcByteBufferLen; j++) {
290: dstBuffer.put(srcByteBuffer.get(initialPosition + j));
291: }
292: }
293: }
294:
295: array.restore();
296: array.recycle();
297: }
298: }
299:
300: public static void get(final ByteBuffer srcBuffer, final byte[] dstBytes, final int dstOffset, final int length) {
301:
302:• if (srcBuffer.hasArray()) {
303:• if (length > srcBuffer.remaining()) {
304: throw new BufferUnderflowException();
305: }
306:
307: System.arraycopy(srcBuffer.array(), srcBuffer.arrayOffset() + srcBuffer.position(), dstBytes, dstOffset, length);
308: srcBuffer.position(srcBuffer.position() + length);
309: } else {
310: srcBuffer.get(dstBytes, dstOffset, length);
311: }
312: }
313:
314: public static void put(final byte[] srcBytes, final int srcOffset, final int length, final ByteBuffer dstBuffer) {
315:• if (dstBuffer.hasArray()) {
316:• if (length > dstBuffer.remaining()) {
317: throw new BufferOverflowException();
318: }
319:
320: System.arraycopy(srcBytes, srcOffset, dstBuffer.array(), dstBuffer.arrayOffset() + dstBuffer.position(), length);
321: dstBuffer.position(dstBuffer.position() + length);
322: } else {
323: dstBuffer.put(srcBytes, srcOffset, length);
324: }
325: }
326:
327: /**
328: * Append two {@link Buffer}s. If one of the {@link Buffer}s is null - then another {@link Buffer} will be returned as
329: * result. If the first {@link Buffer} is {@link CompositeBuffer} then the second {@link Buffer} will be appended to it
330: * via {@link CompositeBuffer#append(Buffer)}, else if the second {@link Buffer} is {@link CompositeBuffer} then the
331: * first {@link Buffer} will be prepended to it via {@link CompositeBuffer#prepend(org.glassfish.grizzly.Buffer)}. If
332: * none of the {@link Buffer} parameters is null nor {@link CompositeBuffer}s - then new {@link CompositeBuffer} will be
333: * created and both {@link Buffer}s will be added there. The resulting {@link CompositeBuffer} will be disallowed for
334: * disposal.
335: *
336: * @param memoryManager the {@link MemoryManager} to use if a new {@link Buffer} needs to be allocated in order to
337: * perform the requested operation.
338: * @param buffer1 the {@link Buffer} to append to.
339: * @param buffer2 the {@link Buffer} to append.
340: *
341: * @return the result of appending of two {@link Buffer}s.
342: */
343: public static Buffer appendBuffers(final MemoryManager memoryManager, final Buffer buffer1, final Buffer buffer2) {
344: return appendBuffers(memoryManager, buffer1, buffer2, false);
345: }
346:
347: /**
348: * Append two {@link Buffer}s. If one of the {@link Buffer}s is null - then another {@link Buffer} will be returned as
349: * result. If the first {@link Buffer} is {@link CompositeBuffer} then the second {@link Buffer} will be appended to it
350: * via {@link CompositeBuffer#append(Buffer)}, else if the second {@link Buffer} is {@link CompositeBuffer} then the
351: * first {@link Buffer} will be prepended to it via {@link CompositeBuffer#prepend(org.glassfish.grizzly.Buffer)}. If
352: * none of the {@link Buffer} parameters is null nor {@link CompositeBuffer}s - then new {@link CompositeBuffer} will be
353: * created and both {@link Buffer}s will be added there. The resulting {@link CompositeBuffer} will be assigned
354: * according to the <code>isCompositeBufferDisposable</code> parameter.
355: *
356: * @param memoryManager the {@link MemoryManager} to use if a new {@link Buffer} needs to be allocated in order to
357: * perform the requested operation.
358: * @param buffer1 the {@link Buffer} to append to.
359: * @param buffer2 the {@link Buffer} to append.
360: * @param isCompositeBufferDisposable flag indicating whether or not the resulting composite buffer may be disposed.
361: *
362: * @return the result of appending of two {@link Buffer}s.
363: */
364: public static Buffer appendBuffers(final MemoryManager memoryManager, final Buffer buffer1, final Buffer buffer2,
365: final boolean isCompositeBufferDisposable) {
366:
367:• if (buffer1 == null) {
368: return buffer2;
369:• } else if (buffer2 == null) {
370: return buffer1;
371: }
372:
373:• if (buffer1.order() != buffer2.order()) {
374: LOGGER.fine("Appending buffers with different ByteOrder." + "The result Buffer's order will be the same as the first Buffer's ByteOrder");
375: buffer2.order(buffer1.order());
376: }
377:
378: // we can only append to or prepend buffer1 if the limit()
379: // is the same as capacity. If it's not, then appending or
380: // prepending effectively clobbers the limit causing an invalid
381: // view of the data. So instead, we allocate a new CompositeBuffer
382: // and append buffer1 and buffer2 to it. The underlying buffers
383: // aren't changed so the limit they have is maintained.
384:• if (buffer1.isComposite() && buffer1.capacity() == buffer1.limit()) {
385: ((CompositeBuffer) buffer1).append(buffer2);
386: return buffer1;
387: }
388:• if (buffer2.isComposite() && buffer2.position() == 0) {
389: ((CompositeBuffer) buffer2).prepend(buffer1);
390: return buffer2;
391: } else {
392: final CompositeBuffer compositeBuffer = CompositeBuffer.newBuffer(memoryManager);
393:
394: compositeBuffer.order(buffer1.order());
395: compositeBuffer.append(buffer1);
396: compositeBuffer.append(buffer2);
397: compositeBuffer.allowBufferDispose(isCompositeBufferDisposable);
398:
399: return compositeBuffer;
400: }
401: }
402:
403: /**
404: * Fill the {@link Buffer} with the specific byte value. {@link Buffer}'s position won't be changed.
405: *
406: * @param buffer {@link Buffer}
407: * @param b value
408: */
409: public static void fill(final Buffer buffer, final byte b) {
410: fill(buffer, buffer.position(), buffer.limit(), b);
411: }
412:
413: /**
414: * Fill the {@link Buffer}'s part [position, limit) with the specific byte value starting from the {@link Buffer}'s
415: * position won't be changed.
416: *
417: * @param buffer {@link Buffer}
418: * @param position {@link Buffer} position to start with (inclusive)
419: * @param limit {@link Buffer} limit, where filling ends (exclusive)
420: * @param b value
421: */
422: public static void fill(final Buffer buffer, final int position, final int limit, final byte b) {
423:• if (!buffer.isComposite()) {
424: final ByteBuffer byteBuffer = buffer.toByteBuffer();
425: fill(byteBuffer, position, limit, b);
426: } else {
427: final ByteBufferArray array = buffer.toByteBufferArray(position, limit);
428: final ByteBuffer[] byteBuffers = array.getArray();
429: final int size = array.size();
430:
431:• for (int i = 0; i < size; i++) {
432: final ByteBuffer byteBuffer = byteBuffers[i];
433: fill(byteBuffer, b);
434: }
435:
436: array.restore();
437: array.recycle();
438: }
439: }
440:
441: /**
442: * Fill the {@link ByteBuffer} with the specific byte value. {@link ByteBuffer}'s position won't be changed.
443: *
444: * @param byteBuffer {@link ByteBuffer}
445: * @param b value
446: */
447: public static void fill(final ByteBuffer byteBuffer, final byte b) {
448: fill(byteBuffer, byteBuffer.position(), byteBuffer.limit(), b);
449: }
450:
451: /**
452: * Fill the {@link ByteBuffer}'s part [position, limit) with the specific byte value starting from the
453: * {@link ByteBuffer}'s position won't be changed.
454: *
455: * @param byteBuffer {@link ByteBuffer}
456: * @param position {@link ByteBuffer} position to start with (inclusive)
457: * @param limit {@link Buffer} limit, where filling ends (exclusive)
458: * @param b value
459: */
460: public static void fill(final ByteBuffer byteBuffer, final int position, final int limit, final byte b) {
461:• if (byteBuffer.hasArray()) {
462: final int arrayOffset = byteBuffer.arrayOffset();
463: Arrays.fill(byteBuffer.array(), arrayOffset + position, arrayOffset + limit, b);
464: } else {
465:• for (int i = position; i < limit; i++) {
466: byteBuffer.put(i, b);
467: }
468: }
469: }
470:
471: /**
472: * Clones the source {@link Buffer}. The method returns a new {@link Buffer} instance, which has the same content.
473: * Please note, source and result {@link Buffer}s have the same content, but it is *not* shared, so the following
474: * content changes in one of the {@link Buffer}s won't be visible in another one.
475: *
476: * @param srcBuffer the source {@link Buffer}.
477: * @return the cloned {@link Buffer}.
478: */
479: public static Buffer cloneBuffer(final Buffer srcBuffer) {
480: return cloneBuffer(srcBuffer, srcBuffer.position(), srcBuffer.limit());
481: }
482:
483: /**
484: * Clones the source {@link Buffer}. The method returns a new {@link Buffer} instance, which has the same content.
485: * Please note, source and result {@link Buffer}s have the same content, but it is *not* shared, so the following
486: * content changes in one of the {@link Buffer}s won't be visible in another one.
487: *
488: * @param srcBuffer the source {@link Buffer}.
489: * @param position the start position in the srcBuffer
490: * @param limit the end position in the srcBuffer
491: * @return the cloned {@link Buffer}.
492: */
493: public static Buffer cloneBuffer(final Buffer srcBuffer, final int position, final int limit) {
494: final int srcLength = limit - position;
495:• if (srcLength == 0) { // make sure clone doesn't return EMPTY_BUFFER
496: return wrap(getDefaultMemoryManager(), EMPTY_BYTE_BUFFER);
497: }
498:
499: final Buffer clone = getDefaultMemoryManager().allocate(srcLength);
500: clone.put(srcBuffer, position, srcLength);
501: clone.order(srcBuffer.order());
502:
503: return clone.flip();
504: }
505:
506: /**
507: * Reads data from the {@link FileChannel} into the {@link Buffer}.
508: *
509: * @param fileChannel the {@link FileChannel} to read data from.
510: * @param buffer the destination {@link Buffer}.
511: * @return the number of bytes read, or <tt>-1</tt> if the end of file is reached.
512: *
513: * @throws IOExceptionif an error occurs reading the {@link FileChannel}.
514: */
515: public static long readFromFileChannel(final FileChannel fileChannel, final Buffer buffer) throws IOException {
516:
517: final long bytesRead;
518:
519:• if (!buffer.isComposite()) {
520: final ByteBuffer bb = buffer.toByteBuffer();
521: final int oldPos = bb.position();
522: bytesRead = fileChannel.read(bb);
523: bb.position(oldPos);
524: } else {
525: final ByteBufferArray array = buffer.toByteBufferArray();
526: bytesRead = fileChannel.read(array.getArray(), 0, array.size());
527:
528: array.restore();
529: array.recycle();
530: }
531:
532:• if (bytesRead > 0) {
533: buffer.position(buffer.position() + (int) bytesRead);
534: }
535:
536: return bytesRead;
537: }
538:
539: /**
540: * Writes data from the {@link Buffer} into the {@link FileChannel}.
541: *
542: * @param fileChannel the {@link FileChannel} to write data to.
543: * @param buffer the source {@link Buffer}.
544: * @return the number of bytes written, possibly zero.
545: *
546: * @throws IOExceptionif an error occurs writing to the {@link FileChannel}.
547: */
548: @SuppressWarnings("UnusedDeclaration")
549: public static long writeToFileChannel(final FileChannel fileChannel, final Buffer buffer) throws IOException {
550:
551: final long bytesWritten;
552:
553:• if (!buffer.isComposite()) {
554: final ByteBuffer bb = buffer.toByteBuffer();
555: final int oldPos = bb.position();
556: bytesWritten = fileChannel.write(bb);
557: bb.position(oldPos);
558: } else {
559: final ByteBufferArray array = buffer.toByteBufferArray();
560: bytesWritten = fileChannel.write(array.getArray(), 0, array.size());
561:
562: array.restore();
563: array.recycle();
564: }
565:
566:• if (bytesWritten > 0) {
567: buffer.position(buffer.position() + (int) bytesWritten);
568: }
569:
570: return bytesWritten;
571: }
572:
573: /**
574: * Returns the {@link Buffer}'s {@link String} representation in a form: {@link Buffer#toString()} + "[" + <head-chunk>
575: * + "..." + <tail-chunk> + "]" For example:
576: *
577: * <pre>
578: * HeapBuffer (1781633478) [pos=0 lim=285 cap=285][abcde...xyz]
579: * </pre>
580: *
581: * @param buffer the {@link Buffer}, could be <tt>null</tt>
582: * @param headBytesCount the number of heading bytes to include (larger or equal to 0)
583: * @param tailBytesCount the number of tailing bytes to include (larger or equal to 0)
584: * @return the {@link Buffer}'s {@link String} representation, or <tt>null</tt>, if the {@link Buffer} is <tt>null</tt>
585: */
586: public String toStringContent(final Buffer buffer, final int headBytesCount, final int tailBytesCount) {
587:• if (buffer == null) {
588: return null;
589: }
590:
591: return toStringContent(buffer, headBytesCount, tailBytesCount, Charset.defaultCharset());
592: }
593:
594: /**
595: * Returns the {@link Buffer}'s {@link String} representation in a form: {@link Buffer#toString()} + "[" + <head-chunk>
596: * + "..." + <tail-chunk> + "]" For example:
597: *
598: * <pre>
599: * HeapBuffer (1781633478) [pos=0 lim=285 cap=285][abcde...xyz]
600: * </pre>
601: *
602: * @param buffer the {@link Buffer}, could be <tt>null</tt>
603: * @param headBytesCount the number of heading bytes to include (larger or equal to 0)
604: * @param tailBytesCount the number of tailing bytes to include (larger or equal to 0)
605: * @param charset {@link Charset}, if null the {@link Charset#defaultCharset()} will be used
606: * @return the {@link Buffer}'s {@link String} representation, or <tt>null</tt>, if the {@link Buffer} is <tt>null</tt>
607: */
608: public String toStringContent(final Buffer buffer, final int headBytesCount, final int tailBytesCount, final Charset charset) {
609:• if (buffer == null) {
610: return null;
611: }
612:
613:• if (headBytesCount < 0 || tailBytesCount < 0) {
614: throw new IllegalArgumentException("count can't be negative");
615: }
616:
617: final String toString = buffer.toString();
618: final StringBuilder sb = new StringBuilder(toString.length() + headBytesCount + tailBytesCount + 5);
619:
620: sb.append(toString);
621:
622:• if (buffer.remaining() <= headBytesCount + tailBytesCount) {
623: sb.append('[').append(buffer.toStringContent(charset)).append(']');
624: } else {
625: sb.append('[');
626:• if (headBytesCount > 0) {
627: sb.append(buffer.toStringContent(charset, buffer.position(), buffer.position() + headBytesCount));
628: }
629: sb.append("...");
630:• if (tailBytesCount > 0) {
631: sb.append(buffer.toStringContent(charset, buffer.limit() - tailBytesCount, buffer.limit()));
632: }
633: sb.append(']');
634: }
635:
636: return sb.toString();
637: }
638:
639: /**
640: * Generates a hex dump of the provided {@link Buffer}.
641: *
642: * @param appendable the {@link Appendable} to write the hex dump to.
643: * @param buffer the {@link Buffer} to dump.
644: *
645: * @since 2.3.23
646: */
647: @SuppressWarnings("unused")
648: public static void dumpBuffer(final Appendable appendable, final Buffer buffer) {
649: final Formatter formatter = new Formatter(appendable);
650: dumpBuffer0(formatter, appendable, buffer);
651: }
652:
653: @SuppressWarnings("UnusedParameters")
654: private static void dumpBuffer0(final Formatter formatter, final Appendable appendable, final Buffer buffer) {
655:• if (buffer.isComposite()) {
656: final BufferArray bufferArray = buffer.toBufferArray();
657: final int size = bufferArray.size();
658: final Buffer[] buffers = bufferArray.getArray();
659: formatter.format("%s\n", buffer.toString());
660:• for (int i = 0; i < size; i++) {
661: dumpBuffer0(formatter, appendable, buffers[i]);
662: }
663: formatter.format("End CompositeBuffer (%d)", System.identityHashCode(buffer));
664: } else {
665: dumpBuffer0(formatter, buffer);
666: }
667: }
668:
669: private static void dumpBuffer0(final Formatter formatter, final Buffer buffer) {
670: formatter.format("%s\n", buffer.toString());
671: int line = 0;
672:• for (int i = 0, len = buffer.remaining() / 16; i < len; i++, line += 16) {
673: byte b0 = buffer.get(line);
674: byte b1 = buffer.get(line + 1);
675: byte b2 = buffer.get(line + 2);
676: byte b3 = buffer.get(line + 3);
677: byte b4 = buffer.get(line + 4);
678: byte b5 = buffer.get(line + 5);
679: byte b6 = buffer.get(line + 6);
680: byte b7 = buffer.get(line + 7);
681: byte b8 = buffer.get(line + 8);
682: byte b9 = buffer.get(line + 9);
683: byte b10 = buffer.get(line + 10);
684: byte b11 = buffer.get(line + 11);
685: byte b12 = buffer.get(line + 12);
686: byte b13 = buffer.get(line + 13);
687: byte b14 = buffer.get(line + 14);
688: byte b15 = buffer.get(line + 15);
689:
690: formatter.format(DumpStrings.DUMP_STRINGS[15], line, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, getChar(b0), getChar(b1),
691: getChar(b2), getChar(b3), getChar(b4), getChar(b5), getChar(b6), getChar(b7), getChar(b8), getChar(b9), getChar(b10), getChar(b11),
692: getChar(b12), getChar(b13), getChar(b14), getChar(b15));
693: }
694: int remaining = buffer.remaining() % 16;
695:• if (remaining > 0) {
696: final Object[] args = new Object[(remaining << 1) + 1];
697: args[0] = remaining + line;
698:• for (int i = 0, aIdx = 1; i < remaining; i++, aIdx++) {
699: final int b = buffer.get(line + i);
700: args[aIdx] = b & 0xFF;
701: args[aIdx + remaining] = getChar(b);
702: }
703: formatter.format(DumpStrings.DUMP_STRINGS[remaining - 1], args);
704: }
705: }
706:
707: // --------------------------------------------------------- Private Methods
708:
709: private static char getChar(final int val) {
710: final char c = (char) val;
711:• return Character.isWhitespace(c) || Character.isISOControl(c) ? '.' : c;
712: }
713:
714: private static MemoryManager getDefaultMemoryManager() {
715: return MemoryManager.DEFAULT_MEMORY_MANAGER;
716: }
717:
718: // ---------------------------------------------------------- Nested Classes
719:
720: private static final class DumpStrings {
721:
722: private static final String[] DUMP_STRINGS = { "%10d %02x %c\n",
723: "%10d %02x %02x %c%c\n",
724: "%10d %02x %02x %02x %c%c%c\n",
725: "%10d %02x %02x %02x %02x %c%c%c%c\n",
726: "%10d %02x %02x %02x %02x %02x %c%c%c%c%c\n",
727: "%10d %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c\n",
728: "%10d %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c\n",
729: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c\n",
730: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c\n",
731: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c\n",
732: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c\n",
733: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c\n",
734: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c\n",
735: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
736: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
737: "%10d %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n" };
738:
739: } // END DumpStrings
740: }