1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.protobuf;
17
18 import com.google.protobuf.CodedInputStream;
19 import com.google.protobuf.nano.CodedInputByteBufferNano;
20 import io.netty.buffer.ByteBuf;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.handler.codec.ByteToMessageDecoder;
23 import io.netty.handler.codec.CorruptedFrameException;
24 import io.netty.handler.codec.TooLongFrameException;
25
26 import java.util.List;
27
28 import static io.netty.util.internal.ObjectUtil.checkPositive;
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 public class ProtobufVarint32FrameDecoder extends ByteToMessageDecoder {
47
48 private final int maxFrameLength;
49 private long bytesToDiscard;
50
51
52
53
54 public ProtobufVarint32FrameDecoder() {
55 this(Integer.MAX_VALUE);
56 }
57
58
59
60
61
62
63
64
65 public ProtobufVarint32FrameDecoder(int maxFrameLength) {
66 this.maxFrameLength = checkPositive(maxFrameLength, "maxFrameLength");
67 }
68
69 @Override
70 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
71 throws Exception {
72 if (bytesToDiscard > 0) {
73 int localBytesToDiscard = (int) Math.min(bytesToDiscard, in.readableBytes());
74 in.skipBytes(localBytesToDiscard);
75 bytesToDiscard -= localBytesToDiscard;
76 return;
77 }
78
79 in.markReaderIndex();
80 int preIndex = in.readerIndex();
81 int length = readRawVarint32(in);
82 if (preIndex == in.readerIndex()) {
83 return;
84 }
85 if (length < 0) {
86 throw new CorruptedFrameException("negative length: " + length);
87 }
88
89 if (length > maxFrameLength) {
90 long discard = length - in.readableBytes();
91 if (discard <= 0) {
92 in.skipBytes(length);
93 } else {
94 bytesToDiscard = discard;
95 in.skipBytes(in.readableBytes());
96 }
97 throw new TooLongFrameException(
98 "Frame length exceeds " + maxFrameLength
99 + ": " + length);
100 }
101
102 if (in.readableBytes() < length) {
103 in.resetReaderIndex();
104 } else {
105 out.add(in.readRetainedSlice(length));
106 }
107 }
108
109
110
111
112
113
114 static int readRawVarint32(ByteBuf buffer) {
115 if (buffer.readableBytes() < 4) {
116 return readRawVarint24(buffer);
117 }
118 int wholeOrMore = buffer.getIntLE(buffer.readerIndex());
119 int firstOneOnStop = ~wholeOrMore & 0x80808080;
120 if (firstOneOnStop == 0) {
121 return readRawVarint40(buffer, wholeOrMore);
122 }
123 int bitsToKeep = Integer.numberOfTrailingZeros(firstOneOnStop) + 1;
124 buffer.skipBytes(bitsToKeep >> 3);
125 int thisVarintMask = firstOneOnStop ^ (firstOneOnStop - 1);
126 int wholeWithContinuations = wholeOrMore & thisVarintMask;
127
128
129
130
131
132
133
134 wholeWithContinuations = (wholeWithContinuations & 0x7F007F) | ((wholeWithContinuations & 0x7F007F00) >> 1);
135
136
137
138 return (wholeWithContinuations & 0x3FFF) | ((wholeWithContinuations & 0x3FFF0000) >> 2);
139 }
140
141 private static int readRawVarint40(ByteBuf buffer, int wholeOrMore) {
142 byte lastByte;
143 if (buffer.readableBytes() == 4 || (lastByte = buffer.getByte(buffer.readerIndex() + 4)) < 0) {
144 throw new CorruptedFrameException("malformed varint.");
145 }
146 buffer.skipBytes(5);
147
148 return wholeOrMore & 0x7F |
149 (((wholeOrMore >> 8) & 0x7F) << 7) |
150 (((wholeOrMore >> 16) & 0x7F) << 14) |
151 (((wholeOrMore >> 24) & 0x7F) << 21) |
152 (lastByte << 28);
153 }
154
155 private static int readRawVarint24(ByteBuf buffer) {
156 if (!buffer.isReadable()) {
157 return 0;
158 }
159 buffer.markReaderIndex();
160
161 byte tmp = buffer.readByte();
162 if (tmp >= 0) {
163 return tmp;
164 }
165 int result = tmp & 127;
166 if (!buffer.isReadable()) {
167 buffer.resetReaderIndex();
168 return 0;
169 }
170 if ((tmp = buffer.readByte()) >= 0) {
171 return result | tmp << 7;
172 }
173 result |= (tmp & 127) << 7;
174 if (!buffer.isReadable()) {
175 buffer.resetReaderIndex();
176 return 0;
177 }
178 if ((tmp = buffer.readByte()) >= 0) {
179 return result | tmp << 14;
180 }
181 return result | (tmp & 127) << 14;
182 }
183 }