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 InputStream in;
91
92 private final byte[] lineBuffer;
93
94
95
96
97
98
99
100 public PacketLineIn(final InputStream i) {
101 in = i;
102 lineBuffer = new byte[SideBandOutputStream.SMALL_BUF];
103 }
104
105 AckNackResult readACK(final MutableObjectId returnedId) throws IOException {
106 final String line = readString();
107 if (line.length() == 0)
108 throw new PackProtocolException(JGitText.get().expectedACKNAKFoundEOF);
109 if ("NAK".equals(line))
110 return AckNackResult.NAK;
111 if (line.startsWith("ACK ")) {
112 returnedId.fromString(line.substring(4, 44));
113 if (line.length() == 44)
114 return AckNackResult.ACK;
115
116 final String arg = line.substring(44);
117 if (arg.equals(" continue"))
118 return AckNackResult.ACK_CONTINUE;
119 else if (arg.equals(" common"))
120 return AckNackResult.ACK_COMMON;
121 else if (arg.equals(" ready"))
122 return AckNackResult.ACK_READY;
123 }
124 if (line.startsWith("ERR "))
125 throw new PackProtocolException(line.substring(4));
126 throw new PackProtocolException(MessageFormat.format(JGitText.get().expectedACKNAKGot, line));
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141 public String readString() throws IOException {
142 int len = readLength();
143 if (len == 0) {
144 log.debug("git< 0000");
145 return END;
146 }
147
148 len -= 4;
149 if (len == 0) {
150 log.debug("git< ");
151 return "";
152 }
153
154 byte[] raw;
155 if (len <= lineBuffer.length)
156 raw = lineBuffer;
157 else
158 raw = new byte[len];
159
160 IO.readFully(in, raw, 0, len);
161 if (raw[len - 1] == '\n')
162 len--;
163
164 String s = RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
165 log.debug("git< " + s);
166 return s;
167 }
168
169
170
171
172
173
174
175
176
177
178
179 public String readStringRaw() throws IOException {
180 int len = readLength();
181 if (len == 0) {
182 log.debug("git< 0000");
183 return END;
184 }
185
186 len -= 4;
187
188 byte[] raw;
189 if (len <= lineBuffer.length)
190 raw = lineBuffer;
191 else
192 raw = new byte[len];
193
194 IO.readFully(in, raw, 0, len);
195
196 String s = RawParseUtils.decode(Constants.CHARSET, raw, 0, len);
197 log.debug("git< " + s);
198 return s;
199 }
200
201 void discardUntilEnd() throws IOException {
202 for (;;) {
203 int n = readLength();
204 if (n == 0) {
205 break;
206 }
207 IO.skipFully(in, n - 4);
208 }
209 }
210
211 int readLength() throws IOException {
212 IO.readFully(in, lineBuffer, 0, 4);
213 try {
214 final int len = RawParseUtils.parseHexInt16(lineBuffer, 0);
215 if (len != 0 && len < 4)
216 throw new ArrayIndexOutOfBoundsException();
217 return len;
218 } catch (ArrayIndexOutOfBoundsException err) {
219 throw new IOException(MessageFormat.format(JGitText.get().invalidPacketLineHeader,
220 "" + (char) lineBuffer[0] + (char) lineBuffer[1]
221 + (char) lineBuffer[2] + (char) lineBuffer[3]));
222 }
223 }
224 }