1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandler.Sharable;
20 import io.netty.channel.ChannelHandlerContext;
21 import io.netty.util.internal.ObjectUtil;
22
23 import java.nio.ByteOrder;
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 @Sharable
52 public class LengthFieldPrepender extends MessageToByteEncoder<ByteBuf> {
53
54 private final ByteOrder byteOrder;
55 private final int lengthFieldLength;
56 private final boolean lengthIncludesLengthFieldLength;
57 private final int lengthAdjustment;
58
59
60
61
62
63
64
65
66
67
68 public LengthFieldPrepender(int lengthFieldLength) {
69 this(lengthFieldLength, false);
70 }
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 public LengthFieldPrepender(int lengthFieldLength, boolean lengthIncludesLengthFieldLength) {
86 this(lengthFieldLength, 0, lengthIncludesLengthFieldLength);
87 }
88
89
90
91
92
93
94
95
96
97
98
99
100 public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment) {
101 this(lengthFieldLength, lengthAdjustment, false);
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
120 this(ByteOrder.BIG_ENDIAN, lengthFieldLength, lengthAdjustment, lengthIncludesLengthFieldLength);
121 }
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139 public LengthFieldPrepender(
140 ByteOrder byteOrder, int lengthFieldLength,
141 int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
142 if (lengthFieldLength != 1 && lengthFieldLength != 2 &&
143 lengthFieldLength != 3 && lengthFieldLength != 4 &&
144 lengthFieldLength != 8) {
145 throw new IllegalArgumentException(
146 "lengthFieldLength must be either 1, 2, 3, 4, or 8: " +
147 lengthFieldLength);
148 }
149 ObjectUtil.checkNotNull(byteOrder, "byteOrder");
150
151 this.byteOrder = byteOrder;
152 this.lengthFieldLength = lengthFieldLength;
153 this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength;
154 this.lengthAdjustment = lengthAdjustment;
155 }
156
157 @Override
158 protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
159 int length = msg.readableBytes() + lengthAdjustment;
160 if (lengthIncludesLengthFieldLength) {
161 length += lengthFieldLength;
162 }
163
164 if (length < 0) {
165 throw new IllegalArgumentException(
166 "Adjusted frame length (" + length + ") is less than zero");
167 }
168
169 switch (lengthFieldLength) {
170 case 1:
171 if (length >= 256) {
172 throw new IllegalArgumentException(
173 "length does not fit into a byte: " + length);
174 }
175 out.writeByte((byte) length);
176 break;
177 case 2:
178 if (length >= 65536) {
179 throw new IllegalArgumentException(
180 "length does not fit into a short integer: " + length);
181 }
182 out.writeShort((short) length);
183 break;
184 case 3:
185 if (length >= 16777216) {
186 throw new IllegalArgumentException(
187 "length does not fit into a medium integer: " + length);
188 }
189 out.writeMedium(length);
190 break;
191 case 4:
192 out.writeInt(length);
193 break;
194 case 8:
195 out.writeLong(length);
196 break;
197 default:
198 throw new Error("should not reach here");
199 }
200
201 out.writeBytes(msg, msg.readerIndex(), msg.readableBytes());
202 }
203
204 @Override
205 protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, ByteBuf msg, boolean preferDirect) throws Exception {
206 return super.allocateBuffer(ctx, msg, preferDirect).order(byteOrder);
207 }
208 }