1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.eclipse.jgit.transport;
47
48 import java.io.IOException;
49 import java.io.InputStream;
50 import java.text.MessageFormat;
51
52 import org.eclipse.jgit.errors.PackProtocolException;
53 import org.eclipse.jgit.internal.JGitText;
54 import org.eclipse.jgit.lib.Constants;
55 import org.eclipse.jgit.lib.MutableObjectId;
56 import org.eclipse.jgit.util.IO;
57 import org.eclipse.jgit.util.RawParseUtils;
58 import org.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
60
61
62
63
64
65
66
67
68
69
70
71 public class PacketLineIn {
72 private static final Logger log = LoggerFactory.getLogger(PacketLineIn.class);
73
74
75 public static final String END = new StringBuilder(0).toString();
76
77 static enum AckNackResult {
78
79 NAK,
80
81 ACK,
82
83 ACK_CONTINUE,
84
85 ACK_COMMON,
86
87 ACK_READY;
88 }
89
90 private final byte[] lineBuffer = new byte[SideBandOutputStream.SMALL_BUF];
91 private final InputStream in;
92 private long limit;
93
94
95
96
97
98
99
100 public PacketLineIn(InputStream in) {
101 this(in, 0);
102 }
103
104
105
106
107
108
109
110
111
112
113 public PacketLineIn(InputStream in, long limit) {
114 this.in = in;
115 this.limit = limit;
116 }
117
118 AckNackResult readACK(final MutableObjectId returnedId) throws IOException {
119 final String line = readString();
120 if (line.length() == 0)
121 throw new PackProtocolException(JGitText.get().expectedACKNAKFoundEOF);
122 if ("NAK".equals(line))
123 return AckNackResult.NAK;
124 if (line.startsWith("ACK ")) {
125 returnedId.fromString(line.substring(4, 44));
126 if (line.length() == 44)
127 return AckNackResult.ACK;
128
129 final String arg = line.substring(44);
130 if (arg.equals(" continue"))
131 return AckNackResult.ACK_CONTINUE;
132 else if (arg.equals(" common"))
133 return AckNackResult.ACK_COMMON;
134 else if (arg.equals(" ready"))
135 return AckNackResult.ACK_READY;
136 }
137 if (line.startsWith("ERR "))
138 throw new PackProtocolException(line.substring(4));
139 throw new PackProtocolException(MessageFormat.format(JGitText.get().expectedACKNAKGot, line));
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154 public String readString() throws IOException {
155 int len = readLength();
156 if (len == 0) {
157 log.debug("git< 0000");
158 return END;
159 }
160
161 len -= 4;
162 if (len == 0) {
163 log.debug("git< ");
164 return "";
165 }
166
167 byte[] raw;
168 if (len <= lineBuffer.length)
169 raw = lineBuffer;
170 else
171 raw = new byte[len];
172
173 IO.readFully(in, raw, 0, len);
174 if (raw[len - 1] == '\n')
175 len--;
176
177 String s = RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
178 log.debug("git< " + s);
179 return s;
180 }
181
182
183
184
185
186
187
188
189
190
191
192 public String readStringRaw() throws IOException {
193 int len = readLength();
194 if (len == 0) {
195 log.debug("git< 0000");
196 return END;
197 }
198
199 len -= 4;
200
201 byte[] raw;
202 if (len <= lineBuffer.length)
203 raw = lineBuffer;
204 else
205 raw = new byte[len];
206
207 IO.readFully(in, raw, 0, len);
208
209 String s = RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
210 log.debug("git< " + s);
211 return s;
212 }
213
214 void discardUntilEnd() throws IOException {
215 for (;;) {
216 int n = readLength();
217 if (n == 0) {
218 break;
219 }
220 IO.skipFully(in, n - 4);
221 }
222 }
223
224 int readLength() throws IOException {
225 IO.readFully(in, lineBuffer, 0, 4);
226 int len;
227 try {
228 len = RawParseUtils.parseHexInt16(lineBuffer, 0);
229 } catch (ArrayIndexOutOfBoundsException err) {
230 throw invalidHeader();
231 }
232
233 if (len == 0) {
234 return 0;
235 } else if (len < 4) {
236 throw invalidHeader();
237 }
238
239 if (limit != 0) {
240 int n = len - 4;
241 if (limit < n) {
242 limit = -1;
243 try {
244 IO.skipFully(in, n);
245 } catch (IOException e) {
246
247 }
248 throw new InputOverLimitIOException();
249 }
250
251 limit = n < limit ? limit - n : -1;
252 }
253 return len;
254 }
255
256 private IOException invalidHeader() {
257 return new IOException(MessageFormat.format(JGitText.get().invalidPacketLineHeader,
258 "" + (char) lineBuffer[0] + (char) lineBuffer[1]
259 + (char) lineBuffer[2] + (char) lineBuffer[3]));
260 }
261
262
263
264
265
266
267 public static class InputOverLimitIOException extends IOException {
268 private static final long serialVersionUID = 1L;
269 }
270 }