Libraryless. Click here for Pure Java version (251L/2K).
1 | import java.nio.ByteBuffer; |
2 | |
3 | /** |
4 | * This is a drop-in replacement for Sun's internal <code>sun.misc.HexDumpEncoder</code> class. It should be completely |
5 | * compatible with the output from Sun's encoder, making it possible to get rid of the now forbidden reference to the |
6 | * internal class without affecting the application's behavior in any way. |
7 | * |
8 | * @author Erik Wramner |
9 | */ |
10 | sclass HexDumpEncoder { |
11 | private static final int BYTES_PER_LINE = 16; |
12 | private static final int BYTES_PER_GROUP = 8; |
13 | private static final String LINE_SEPARATOR = System.getProperty("line.separator", "\n"); |
14 | |
15 | public String encodeBuffer(byte[] buf) { |
16 | try { |
17 | Appendable sb = new StringBuilder(); |
18 | internalEncode(buf, buf.length, 0, sb, false); |
19 | return sb.toString(); |
20 | } catch (IOException e) { |
21 | // This should never happen |
22 | throw new IllegalStateException("IO exception from string builder", e); |
23 | } |
24 | } |
25 | |
26 | public void encodeBuffer(byte[] buf, OutputStream out) throws IOException { |
27 | internalEncode(buf, buf.length, 0, new OutputStreamAppendableAdapter(out), false); |
28 | } |
29 | |
30 | public void encodeBuffer(ByteBuffer byteBuffer, OutputStream out) throws IOException { |
31 | OutputStreamAppendableAdapter appendable = new OutputStreamAppendableAdapter(out); |
32 | internalEncode(byteBuffer, appendable, false); |
33 | } |
34 | |
35 | public String encodeBuffer(ByteBuffer byteBuffer) { |
36 | StringBuilder sb = new StringBuilder(); |
37 | try { |
38 | internalEncode(byteBuffer, sb, false); |
39 | } catch (IOException e) { |
40 | // This should never happen |
41 | throw new IllegalStateException("IO exception from string builder", e); |
42 | } |
43 | return sb.toString(); |
44 | } |
45 | |
46 | public void encodeBuffer(InputStream in, OutputStream out) throws IOException { |
47 | Appendable outAppendable = new OutputStreamAppendableAdapter(out); |
48 | int address = 0; |
49 | byte[] buf = new byte[BYTES_PER_LINE * 100]; |
50 | int bytesRead = fillBuffer(in, buf); |
51 | while (bytesRead > 0) { |
52 | internalEncode(buf, bytesRead, address, outAppendable, false); |
53 | if (bytesRead == buf.length) { |
54 | address += bytesRead; |
55 | bytesRead = fillBuffer(in, buf); |
56 | } else { |
57 | bytesRead = 0; |
58 | } |
59 | } |
60 | } |
61 | |
62 | public String encode(byte[] buf) { |
63 | try { |
64 | Appendable sb = new StringBuilder(); |
65 | internalEncode(buf, buf.length, 0, sb, true); |
66 | return sb.toString(); |
67 | } catch (IOException e) { |
68 | // This should never happen |
69 | throw new IllegalStateException("IO exception from string builder", e); |
70 | } |
71 | } |
72 | |
73 | public void encode(byte[] buf, OutputStream out) throws IOException { |
74 | internalEncode(buf, buf.length, 0, new OutputStreamAppendableAdapter(out), true); |
75 | } |
76 | |
77 | public void encode(ByteBuffer byteBuffer, OutputStream out) throws IOException { |
78 | OutputStreamAppendableAdapter appendable = new OutputStreamAppendableAdapter(out); |
79 | internalEncode(byteBuffer, appendable, true); |
80 | } |
81 | |
82 | public String encode(ByteBuffer byteBuffer) { |
83 | StringBuilder sb = new StringBuilder(); |
84 | try { |
85 | internalEncode(byteBuffer, sb, true); |
86 | } catch (IOException e) { |
87 | // This should never happen |
88 | throw new IllegalStateException("IO exception from string builder", e); |
89 | } |
90 | return sb.toString(); |
91 | } |
92 | |
93 | public void encode(InputStream in, OutputStream out) throws IOException { |
94 | Appendable outAppendable = new OutputStreamAppendableAdapter(out); |
95 | int address = 0; |
96 | byte[] buf = new byte[BYTES_PER_LINE * 100]; |
97 | int bytesRead = fillBuffer(in, buf); |
98 | while (bytesRead > 0) { |
99 | internalEncode(buf, bytesRead, address, outAppendable, true); |
100 | if (bytesRead == buf.length) { |
101 | address += bytesRead; |
102 | bytesRead = fillBuffer(in, buf); |
103 | } else { |
104 | bytesRead = 0; |
105 | } |
106 | } |
107 | } |
108 | |
109 | private int fillBuffer(InputStream in, byte[] buf) throws IOException { |
110 | int totalBytesRead = 0; |
111 | int bytesLeft = buf.length; |
112 | while (bytesLeft > 0) { |
113 | int bytesRead = in.read(buf, totalBytesRead, bytesLeft); |
114 | if (bytesRead == -1) { |
115 | break; |
116 | } else { |
117 | bytesLeft -= bytesRead; |
118 | totalBytesRead += bytesRead; |
119 | } |
120 | } |
121 | return totalBytesRead; |
122 | } |
123 | |
124 | private void internalEncode(ByteBuffer byteBuffer, Appendable appendable, boolean dropAsciiForPartialLine) |
125 | throws IOException { |
126 | int address = 0; |
127 | while (byteBuffer.hasRemaining()) { |
128 | byte[] buf = new byte[Math.min(byteBuffer.remaining(), BYTES_PER_LINE * 100)]; |
129 | byteBuffer.get(buf); |
130 | internalEncode(buf, buf.length, address, appendable, dropAsciiForPartialLine); |
131 | address += buf.length; |
132 | } |
133 | } |
134 | |
135 | private void internalEncode(byte[] buf, int length, int baseAddress, Appendable sb, boolean dropAsciiForPartialLine) |
136 | throws IOException { |
137 | StringBuilder asciiStringBuilder = new StringBuilder(); |
138 | for (int i = 0; i < length; i++) { |
139 | if (i % BYTES_PER_LINE == 0) { |
140 | if (asciiStringBuilder.length() > 0) { |
141 | sb.append(" "); |
142 | sb.append(asciiStringBuilder); |
143 | sb.append(LINE_SEPARATOR); |
144 | asciiStringBuilder.setLength(0); |
145 | } |
146 | appendHexDigit(sb, (byte) (((baseAddress + i) >>> 8) & 0xFF)); |
147 | appendHexDigit(sb, (byte) ((baseAddress + i) & 0xFF)); |
148 | sb.append(':'); |
149 | } else if (i % BYTES_PER_GROUP == 0) { |
150 | sb.append(" "); |
151 | } |
152 | sb.append(' '); |
153 | final byte b = buf[i]; |
154 | appendHexDigit(sb, b); |
155 | if (b >= 0x20 && b <= 0x7a) { |
156 | asciiStringBuilder.append((char) b); |
157 | } else { |
158 | asciiStringBuilder.append('.'); |
159 | } |
160 | } |
161 | |
162 | if (dropAsciiForPartialLine) { |
163 | // Be bug compatible |
164 | if (asciiStringBuilder.length() > 0) { |
165 | sb.append(' '); |
166 | if (length % BYTES_PER_LINE == BYTES_PER_GROUP) { |
167 | sb.append(" "); |
168 | } else if (length % BYTES_PER_LINE == 0) { |
169 | sb.append(' '); |
170 | sb.append(asciiStringBuilder); |
171 | sb.append(LINE_SEPARATOR); |
172 | } |
173 | } |
174 | } else if (asciiStringBuilder.length() > 0) { |
175 | int remainingBytes = BYTES_PER_LINE - length % BYTES_PER_LINE; |
176 | if (remainingBytes != BYTES_PER_LINE) { |
177 | for (int i = 0; i < remainingBytes; i++) { |
178 | sb.append(" "); |
179 | } |
180 | if (remainingBytes >= BYTES_PER_GROUP) { |
181 | sb.append(" "); |
182 | } |
183 | } |
184 | sb.append(" "); |
185 | sb.append(asciiStringBuilder); |
186 | sb.append(LINE_SEPARATOR); |
187 | } |
188 | } |
189 | |
190 | private void appendHexDigit(Appendable sb, byte b) throws IOException { |
191 | int nibble = (char) (b >> 4 & 0xF); |
192 | sb.append((char) (nibble > 9 ? nibble - 10 + 65 : nibble + 48)); |
193 | nibble = (char) (b & 0xF); |
194 | sb.append((char) (nibble > 9 ? nibble - 10 + 65 : nibble + 48)); |
195 | } |
196 | |
197 | private static class OutputStreamAppendableAdapter implements Appendable { |
198 | private final OutputStream _out; |
199 | |
200 | public OutputStreamAppendableAdapter(OutputStream out) { |
201 | _out = out; |
202 | } |
203 | |
204 | @Override |
205 | public Appendable append(CharSequence cs) throws IOException { |
206 | append(cs, 0, cs.length()); |
207 | return this; |
208 | } |
209 | |
210 | @Override |
211 | public Appendable append(CharSequence cs, int start, int end) throws IOException { |
212 | for (int i = start; i < end; i++) { |
213 | append(cs.charAt(i)); |
214 | } |
215 | return this; |
216 | } |
217 | |
218 | @Override |
219 | public Appendable append(char c) throws IOException { |
220 | _out.write(c); |
221 | return this; |
222 | } |
223 | } |
224 | } |
download show line numbers debug dex old transpilations
Travelled to 3 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx
No comments. add comment
Snippet ID: | #1031892 |
Snippet name: | HexDumpEncoder |
Eternal ID of this version: | #1031892/3 |
Text MD5: | 7a9606d36fd6c28e3fa0e834d4090ec0 |
Transpilation MD5: | 0b0cce7809c36fe2e9d436ce0ee2885a |
Author: | stefan |
Category: | javax |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-07-24 05:36:52 |
Source code size: | 8536 bytes / 224 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 164 / 319 |
Version history: | 2 change(s) |
Referenced in: | [show references] |