1
2
3
4
5 package net.java.truecommons.shed;
6
7 import java.nio.ByteBuffer;
8 import java.nio.CharBuffer;
9 import java.nio.charset.CharacterCodingException;
10 import java.nio.charset.CharsetDecoder;
11 import java.nio.charset.CharsetEncoder;
12 import java.nio.charset.CoderResult;
13 import static java.nio.charset.CodingErrorAction.*;
14 import static java.nio.charset.StandardCharsets.*;
15 import javax.annotation.Nullable;
16 import javax.annotation.Nullable;
17
18
19
20
21
22
23
24
25
26
27
28 public final class Buffers {
29
30 private Buffers() { }
31
32 public static @Nullable ByteBuffer byteBuffer(@Nullable String string) {
33 return null == string ? null : byteBuffer(CharBuffer.wrap(string));
34 }
35
36 public static @Nullable ByteBuffer byteBuffer(@Nullable char[] password) {
37 return null == password ? null : byteBuffer(CharBuffer.wrap(password));
38 }
39
40 public static @Nullable ByteBuffer byteBuffer(
41 final @Nullable CharBuffer cb) {
42 if (null == cb) return null;
43 try {
44 return encode(cb, UTF_8.newEncoder()
45 .onMalformedInput(REPLACE)
46 .onUnmappableCharacter(REPLACE));
47 } catch (final CharacterCodingException cannotHappen) {
48 throw new AssertionError(cannotHappen);
49 }
50 }
51
52 private static ByteBuffer encode(
53 final CharBuffer icb,
54 final CharsetEncoder enc)
55 throws CharacterCodingException {
56 int bytes = (int) (icb.remaining() * enc.averageBytesPerChar());
57 while (true) {
58 final ByteBuffer obb = ByteBuffer.allocateDirect(bytes);
59 final CoderResult cr = enc.encode(icb.duplicate(), obb, true);
60 if (cr.isUnderflow())
61 enc.flush(obb);
62 obb.flip();
63 if (cr.isUnderflow())
64 return obb;
65 if (!cr.isOverflow()) {
66 cr.throwException();
67 throw new AssertionError();
68 }
69 fill(obb, (byte) 0);
70 bytes = 2 * bytes + 1;
71 }
72 }
73
74 public static @Nullable String string(@Nullable ByteBuffer bb) {
75 return null == bb ? null : charBuffer(bb).toString();
76 }
77
78 public static @Nullable char[] charArray(
79 final @Nullable ByteBuffer bb) {
80 if (null == bb)
81 return null;
82 final CharBuffer ocb = charBuffer(bb);
83 final char[] oca = new char[ocb.remaining()];
84 ocb.duplicate().get(oca);
85 fill(ocb, (char) 0);
86 return oca;
87 }
88
89 public static @Nullable CharBuffer charBuffer(
90 final @Nullable ByteBuffer bb) {
91 if (null == bb)
92 return null;
93 final CharsetDecoder dec = UTF_8.newDecoder()
94 .onMalformedInput(REPLACE)
95 .onUnmappableCharacter(REPLACE);
96 try {
97 return decode(bb, dec);
98 } catch (final CharacterCodingException cannotHappen) {
99 throw new AssertionError(cannotHappen);
100 }
101 }
102
103 private static CharBuffer decode(ByteBuffer ibb, CharsetDecoder dec)
104 throws CharacterCodingException {
105 int bytes = (int) (2 * ibb.remaining() * dec.averageCharsPerByte());
106 while (true) {
107 final CharBuffer ocb = ByteBuffer
108 .allocateDirect(bytes)
109 .asCharBuffer();
110 final CoderResult cr = dec.decode(ibb.duplicate(), ocb, true);
111 if (cr.isUnderflow())
112 dec.flush(ocb);
113 ocb.flip();
114 if (cr.isUnderflow())
115 return ocb;
116 if (!cr.isOverflow()) {
117 cr.throwException();
118 throw new AssertionError();
119 }
120 fill(ocb, (char) 0);
121 bytes = 2 * bytes + 2;
122 }
123 }
124
125
126
127
128
129
130
131
132
133 public static void fill(
134 final @Nullable ByteBuffer bb,
135 final byte value) {
136 if (null == bb)
137 return;
138 final int position = bb.position();
139 final int limit = bb.limit();
140 for (int i = position; i < limit; i++)
141 bb.put(i, value);
142 }
143
144
145
146
147
148
149
150
151
152 public static void fill(
153 final @Nullable CharBuffer cb,
154 final char value) {
155 if (null == cb)
156 return;
157 final int position = cb.position();
158 final int limit = cb.limit();
159 for (int i = position; i < limit; i++)
160 cb.put(i, value);
161 }
162
163
164
165
166
167
168
169
170 public static @Nullable ByteBuffer copy(@Nullable ByteBuffer bb) {
171 return null == bb
172 ? null
173 : (ByteBuffer) ByteBuffer
174 .allocateDirect(bb.remaining())
175 .put(bb.duplicate())
176 .rewind();
177 }
178 }