1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.handler.codec;
17
18 import io.netty5.buffer.BufferUtil;
19 import io.netty5.buffer.api.Buffer;
20 import io.netty5.channel.ChannelHandlerContext;
21
22 import java.nio.ByteOrder;
23 import java.util.List;
24
25 import static io.netty5.util.internal.ObjectUtil.checkPositiveOrZero;
26 import static java.util.Objects.requireNonNull;
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
52
53
54 public class LengthFieldPrepender extends MessageToMessageEncoder<Buffer> {
55
56 private final ByteOrder byteOrder;
57 private final int lengthFieldLength;
58 private final boolean lengthIncludesLengthFieldLength;
59 private final int lengthAdjustment;
60
61
62
63
64
65
66
67 public LengthFieldPrepender(int lengthFieldLength) {
68 this(lengthFieldLength, false);
69 }
70
71
72
73
74
75
76
77
78
79
80 public LengthFieldPrepender(int lengthFieldLength, boolean lengthIncludesLengthFieldLength) {
81 this(lengthFieldLength, 0, lengthIncludesLengthFieldLength);
82 }
83
84
85
86
87
88
89
90
91
92 public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment) {
93 this(lengthFieldLength, lengthAdjustment, false);
94 }
95
96
97
98
99
100
101
102
103
104
105
106
107 public LengthFieldPrepender(int lengthFieldLength, int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
108 this(ByteOrder.BIG_ENDIAN, lengthFieldLength, lengthAdjustment, lengthIncludesLengthFieldLength);
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123 public LengthFieldPrepender(
124 ByteOrder byteOrder, int lengthFieldLength,
125 int lengthAdjustment, boolean lengthIncludesLengthFieldLength) {
126 requireNonNull(byteOrder, "byteOrder");
127
128 this.byteOrder = byteOrder;
129 this.lengthFieldLength = lengthFieldLength;
130 this.lengthIncludesLengthFieldLength = lengthIncludesLengthFieldLength;
131 this.lengthAdjustment = lengthAdjustment;
132 }
133
134 @Override
135 public boolean isSharable() {
136 return true;
137 }
138
139 @Override
140 protected void encode(ChannelHandlerContext ctx, Buffer buffer, List<Object> out) throws Exception {
141 int length = buffer.readableBytes() + lengthAdjustment;
142 if (lengthIncludesLengthFieldLength) {
143 length += lengthFieldLength;
144 }
145
146 checkPositiveOrZero(length, "length");
147
148 out.add(getLengthFieldBuffer(ctx, length, lengthFieldLength, byteOrder));
149 out.add(buffer.split());
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164 protected Buffer getLengthFieldBuffer(
165 ChannelHandlerContext ctx, int length, int lengthFieldLength, ByteOrder byteOrder) {
166 final boolean reverseBytes = byteOrder == ByteOrder.LITTLE_ENDIAN;
167
168 switch (lengthFieldLength) {
169 case 1:
170 if (length >= 256) {
171 throw new IllegalArgumentException("length does not fit into a byte: " + length);
172 }
173 return ctx.bufferAllocator().allocate(lengthFieldLength).writeByte((byte) length);
174 case 2:
175 if (length >= 65536) {
176 throw new IllegalArgumentException("length does not fit into a short integer: " + length);
177 }
178 return ctx.bufferAllocator().allocate(lengthFieldLength)
179 .writeShort(reverseBytes ? Short.reverseBytes((short) length) : (short) length);
180 case 3:
181 if (length >= 16777216) {
182 throw new IllegalArgumentException("length does not fit into a medium integer: " + length);
183 }
184 return ctx.bufferAllocator().allocate(lengthFieldLength)
185 .writeMedium(reverseBytes ? BufferUtil.reverseMedium(length) : length);
186 case 4:
187 return ctx.bufferAllocator().allocate(lengthFieldLength)
188 .writeInt(reverseBytes ? Integer.reverseBytes(length) : length);
189 case 8:
190 return ctx.bufferAllocator().allocate(lengthFieldLength)
191 .writeLong(reverseBytes ? Long.reverseBytes(length) : length);
192 default:
193 throw new EncoderException(
194 "unsupported lengthFieldLength: " + lengthFieldLength + " (expected: 1, 2, 3, 4, or 8)");
195 }
196 }
197
198 }