1
16 package io.netty.handler.codec.compression;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.util.ByteProcessor;
20 import io.netty.util.internal.ObjectUtil;
21 import io.netty.util.internal.PlatformDependent;
22
23 import java.lang.reflect.Method;
24 import java.nio.ByteBuffer;
25 import java.util.zip.Adler32;
26 import java.util.zip.CRC32;
27 import java.util.zip.Checksum;
28
29
35 abstract class ByteBufChecksum implements Checksum {
36 private static final Method ADLER32_UPDATE_METHOD;
37 private static final Method CRC32_UPDATE_METHOD;
38
39 static {
40
41
42 ADLER32_UPDATE_METHOD = updateByteBuffer(new Adler32());
43 CRC32_UPDATE_METHOD = updateByteBuffer(new CRC32());
44 }
45
46 private final ByteProcessor updateProcessor = new ByteProcessor() {
47 @Override
48 public boolean process(byte value) throws Exception {
49 update(value);
50 return true;
51 }
52 };
53
54 private static Method updateByteBuffer(Checksum checksum) {
55 if (PlatformDependent.javaVersion() >= 8) {
56 try {
57 Method method = checksum.getClass().getDeclaredMethod("update", ByteBuffer.class);
58 method.invoke(checksum, ByteBuffer.allocate(1));
59 return method;
60 } catch (Throwable ignore) {
61 return null;
62 }
63 }
64 return null;
65 }
66
67 static ByteBufChecksum wrapChecksum(Checksum checksum) {
68 ObjectUtil.checkNotNull(checksum, "checksum");
69 if (checksum instanceof ByteBufChecksum) {
70 return (ByteBufChecksum) checksum;
71 }
72 if (checksum instanceof Adler32 && ADLER32_UPDATE_METHOD != null) {
73 return new ReflectiveByteBufChecksum(checksum, ADLER32_UPDATE_METHOD);
74 }
75 if (checksum instanceof CRC32 && CRC32_UPDATE_METHOD != null) {
76 return new ReflectiveByteBufChecksum(checksum, CRC32_UPDATE_METHOD);
77 }
78 return new SlowByteBufChecksum(checksum);
79 }
80
81
84 public void update(ByteBuf b, int off, int len) {
85 if (b.hasArray()) {
86 update(b.array(), b.arrayOffset() + off, len);
87 } else {
88 b.forEachByte(off, len, updateProcessor);
89 }
90 }
91
92 private static final class ReflectiveByteBufChecksum extends SlowByteBufChecksum {
93 private final Method method;
94
95 ReflectiveByteBufChecksum(Checksum checksum, Method method) {
96 super(checksum);
97 this.method = method;
98 }
99
100 @Override
101 public void update(ByteBuf b, int off, int len) {
102 if (b.hasArray()) {
103 update(b.array(), b.arrayOffset() + off, len);
104 } else {
105 try {
106 method.invoke(checksum, CompressionUtil.safeNioBuffer(b, off, len));
107 } catch (Throwable cause) {
108 throw new Error();
109 }
110 }
111 }
112 }
113
114 private static class SlowByteBufChecksum extends ByteBufChecksum {
115
116 protected final Checksum checksum;
117
118 SlowByteBufChecksum(Checksum checksum) {
119 this.checksum = checksum;
120 }
121
122 @Override
123 public void update(int b) {
124 checksum.update(b);
125 }
126
127 @Override
128 public void update(byte[] b, int off, int len) {
129 checksum.update(b, off, len);
130 }
131
132 @Override
133 public long getValue() {
134 return checksum.getValue();
135 }
136
137 @Override
138 public void reset() {
139 checksum.reset();
140 }
141 }
142 }
143