~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit/ObjectChecker.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit's IP log.
 
4
 
 
5
This program and the accompanying materials are made available
 
6
under the terms of the Eclipse Distribution License v1.0 which
 
7
accompanies this distribution, is reproduced below, and is
 
8
available at http://www.eclipse.org/org/documents/edl-v10.php
 
9
 
 
10
All rights reserved.
 
11
 
 
12
Redistribution and use in source and binary forms, with or
 
13
without modification, are permitted provided that the following
 
14
conditions are met:
 
15
 
 
16
- Redistributions of source code must retain the above copyright
 
17
  notice, this list of conditions and the following disclaimer.
 
18
 
 
19
- Redistributions in binary form must reproduce the above
 
20
  copyright notice, this list of conditions and the following
 
21
  disclaimer in the documentation and/or other materials provided
 
22
  with the distribution.
 
23
 
 
24
- Neither the name of the Eclipse Foundation, Inc. nor the
 
25
  names of its contributors may be used to endorse or promote
 
26
  products derived from this software without specific prior
 
27
  written permission.
 
28
 
 
29
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 
30
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 
31
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
32
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
33
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 
34
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
35
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
36
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
37
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 
38
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
39
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
40
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
41
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
42
*/
 
43
 
 
44
using System;
 
45
using NGit;
 
46
using NGit.Errors;
 
47
using NGit.Util;
 
48
using Sharpen;
 
49
 
 
50
namespace NGit
 
51
{
 
52
        /// <summary>Verifies that an object is formatted correctly.</summary>
 
53
        /// <remarks>
 
54
        /// Verifies that an object is formatted correctly.
 
55
        /// <p>
 
56
        /// Verifications made by this class only check that the fields of an object are
 
57
        /// formatted correctly. The ObjectId checksum of the object is not verified, and
 
58
        /// connectivity links between objects are also not verified. Its assumed that
 
59
        /// the caller can provide both of these validations on its own.
 
60
        /// <p>
 
61
        /// Instances of this class are not thread safe, but they may be reused to
 
62
        /// perform multiple object validations.
 
63
        /// </remarks>
 
64
        public class ObjectChecker
 
65
        {
 
66
                /// <summary>Header "tree "</summary>
 
67
                public static readonly byte[] tree = Constants.EncodeASCII("tree ");
 
68
 
 
69
                /// <summary>Header "parent "</summary>
 
70
                public static readonly byte[] parent = Constants.EncodeASCII("parent ");
 
71
 
 
72
                /// <summary>Header "author "</summary>
 
73
                public static readonly byte[] author = Constants.EncodeASCII("author ");
 
74
 
 
75
                /// <summary>Header "committer "</summary>
 
76
                public static readonly byte[] committer = Constants.EncodeASCII("committer ");
 
77
 
 
78
                /// <summary>Header "encoding "</summary>
 
79
                public static readonly byte[] encoding = Constants.EncodeASCII("encoding ");
 
80
 
 
81
                /// <summary>Header "object "</summary>
 
82
                public static readonly byte[] @object = Constants.EncodeASCII("object ");
 
83
 
 
84
                /// <summary>Header "type "</summary>
 
85
                public static readonly byte[] type = Constants.EncodeASCII("type ");
 
86
 
 
87
                /// <summary>Header "tag "</summary>
 
88
                public static readonly byte[] tag = Constants.EncodeASCII("tag ");
 
89
 
 
90
                /// <summary>Header "tagger "</summary>
 
91
                public static readonly byte[] tagger = Constants.EncodeASCII("tagger ");
 
92
 
 
93
                private readonly MutableObjectId tempId = new MutableObjectId();
 
94
 
 
95
                private readonly MutableInteger ptrout = new MutableInteger();
 
96
 
 
97
                /// <summary>Check an object for parsing errors.</summary>
 
98
                /// <remarks>Check an object for parsing errors.</remarks>
 
99
                /// <param name="objType">
 
100
                /// type of the object. Must be a valid object type code in
 
101
                /// <see cref="Constants">Constants</see>
 
102
                /// .
 
103
                /// </param>
 
104
                /// <param name="raw">
 
105
                /// the raw data which comprises the object. This should be in the
 
106
                /// canonical format (that is the format used to generate the
 
107
                /// ObjectId of the object). The array is never modified.
 
108
                /// </param>
 
109
                /// <exception cref="NGit.Errors.CorruptObjectException">if an error is identified.</exception>
 
110
                public virtual void Check(int objType, byte[] raw)
 
111
                {
 
112
                        switch (objType)
 
113
                        {
 
114
                                case Constants.OBJ_COMMIT:
 
115
                                {
 
116
                                        CheckCommit(raw);
 
117
                                        break;
 
118
                                }
 
119
 
 
120
                                case Constants.OBJ_TAG:
 
121
                                {
 
122
                                        CheckTag(raw);
 
123
                                        break;
 
124
                                }
 
125
 
 
126
                                case Constants.OBJ_TREE:
 
127
                                {
 
128
                                        CheckTree(raw);
 
129
                                        break;
 
130
                                }
 
131
 
 
132
                                case Constants.OBJ_BLOB:
 
133
                                {
 
134
                                        CheckBlob(raw);
 
135
                                        break;
 
136
                                }
 
137
 
 
138
                                default:
 
139
                                {
 
140
                                        throw new CorruptObjectException(MessageFormat.Format(JGitText.Get().corruptObjectInvalidType2
 
141
                                                , objType));
 
142
                                }
 
143
                        }
 
144
                }
 
145
 
 
146
                private int Id(byte[] raw, int ptr)
 
147
                {
 
148
                        try
 
149
                        {
 
150
                                tempId.FromString(raw, ptr);
 
151
                                return ptr + Constants.OBJECT_ID_STRING_LENGTH;
 
152
                        }
 
153
                        catch (ArgumentException)
 
154
                        {
 
155
                                return -1;
 
156
                        }
 
157
                }
 
158
 
 
159
                private int PersonIdent(byte[] raw, int ptr)
 
160
                {
 
161
                        int emailB = RawParseUtils.NextLF(raw, ptr, '<');
 
162
                        if (emailB == ptr || raw[emailB - 1] != '<')
 
163
                        {
 
164
                                return -1;
 
165
                        }
 
166
                        int emailE = RawParseUtils.NextLF(raw, emailB, '>');
 
167
                        if (emailE == emailB || raw[emailE - 1] != '>')
 
168
                        {
 
169
                                return -1;
 
170
                        }
 
171
                        if (emailE == raw.Length || raw[emailE] != ' ')
 
172
                        {
 
173
                                return -1;
 
174
                        }
 
175
                        RawParseUtils.ParseBase10(raw, emailE + 1, ptrout);
 
176
                        // when
 
177
                        ptr = ptrout.value;
 
178
                        if (emailE + 1 == ptr)
 
179
                        {
 
180
                                return -1;
 
181
                        }
 
182
                        if (ptr == raw.Length || raw[ptr] != ' ')
 
183
                        {
 
184
                                return -1;
 
185
                        }
 
186
                        RawParseUtils.ParseBase10(raw, ptr + 1, ptrout);
 
187
                        // tz offset
 
188
                        if (ptr + 1 == ptrout.value)
 
189
                        {
 
190
                                return -1;
 
191
                        }
 
192
                        return ptrout.value;
 
193
                }
 
194
 
 
195
                /// <summary>Check a commit for errors.</summary>
 
196
                /// <remarks>Check a commit for errors.</remarks>
 
197
                /// <param name="raw">the commit data. The array is never modified.</param>
 
198
                /// <exception cref="NGit.Errors.CorruptObjectException">if any error was detected.</exception>
 
199
                public virtual void CheckCommit(byte[] raw)
 
200
                {
 
201
                        int ptr = 0;
 
202
                        if ((ptr = RawParseUtils.Match(raw, ptr, tree)) < 0)
 
203
                        {
 
204
                                throw new CorruptObjectException("no tree header");
 
205
                        }
 
206
                        if ((ptr = Id(raw, ptr)) < 0 || raw[ptr++] != '\n')
 
207
                        {
 
208
                                throw new CorruptObjectException("invalid tree");
 
209
                        }
 
210
                        while (RawParseUtils.Match(raw, ptr, parent) >= 0)
 
211
                        {
 
212
                                ptr += parent.Length;
 
213
                                if ((ptr = Id(raw, ptr)) < 0 || raw[ptr++] != '\n')
 
214
                                {
 
215
                                        throw new CorruptObjectException("invalid parent");
 
216
                                }
 
217
                        }
 
218
                        if ((ptr = RawParseUtils.Match(raw, ptr, author)) < 0)
 
219
                        {
 
220
                                throw new CorruptObjectException("no author");
 
221
                        }
 
222
                        if ((ptr = PersonIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
 
223
                        {
 
224
                                throw new CorruptObjectException("invalid author");
 
225
                        }
 
226
                        if ((ptr = RawParseUtils.Match(raw, ptr, committer)) < 0)
 
227
                        {
 
228
                                throw new CorruptObjectException("no committer");
 
229
                        }
 
230
                        if ((ptr = PersonIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
 
231
                        {
 
232
                                throw new CorruptObjectException("invalid committer");
 
233
                        }
 
234
                }
 
235
 
 
236
                /// <summary>Check an annotated tag for errors.</summary>
 
237
                /// <remarks>Check an annotated tag for errors.</remarks>
 
238
                /// <param name="raw">the tag data. The array is never modified.</param>
 
239
                /// <exception cref="NGit.Errors.CorruptObjectException">if any error was detected.</exception>
 
240
                public virtual void CheckTag(byte[] raw)
 
241
                {
 
242
                        int ptr = 0;
 
243
                        if ((ptr = RawParseUtils.Match(raw, ptr, @object)) < 0)
 
244
                        {
 
245
                                throw new CorruptObjectException("no object header");
 
246
                        }
 
247
                        if ((ptr = Id(raw, ptr)) < 0 || raw[ptr++] != '\n')
 
248
                        {
 
249
                                throw new CorruptObjectException("invalid object");
 
250
                        }
 
251
                        if ((ptr = RawParseUtils.Match(raw, ptr, type)) < 0)
 
252
                        {
 
253
                                throw new CorruptObjectException("no type header");
 
254
                        }
 
255
                        ptr = RawParseUtils.NextLF(raw, ptr);
 
256
                        if ((ptr = RawParseUtils.Match(raw, ptr, tag)) < 0)
 
257
                        {
 
258
                                throw new CorruptObjectException("no tag header");
 
259
                        }
 
260
                        ptr = RawParseUtils.NextLF(raw, ptr);
 
261
                        if ((ptr = RawParseUtils.Match(raw, ptr, tagger)) > 0)
 
262
                        {
 
263
                                if ((ptr = PersonIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
 
264
                                {
 
265
                                        throw new CorruptObjectException("invalid tagger");
 
266
                                }
 
267
                        }
 
268
                }
 
269
 
 
270
                private static int LastPathChar(int mode)
 
271
                {
 
272
                        return FileMode.TREE.Equals(mode) ? '/' : '\0';
 
273
                }
 
274
 
 
275
                private static int PathCompare(byte[] raw, int aPos, int aEnd, int aMode, int bPos
 
276
                        , int bEnd, int bMode)
 
277
                {
 
278
                        while (aPos < aEnd && bPos < bEnd)
 
279
                        {
 
280
                                int cmp = (raw[aPos++] & unchecked((int)(0xff))) - (raw[bPos++] & unchecked((int)
 
281
                                        (0xff)));
 
282
                                if (cmp != 0)
 
283
                                {
 
284
                                        return cmp;
 
285
                                }
 
286
                        }
 
287
                        if (aPos < aEnd)
 
288
                        {
 
289
                                return (raw[aPos] & unchecked((int)(0xff))) - LastPathChar(bMode);
 
290
                        }
 
291
                        if (bPos < bEnd)
 
292
                        {
 
293
                                return LastPathChar(aMode) - (raw[bPos] & unchecked((int)(0xff)));
 
294
                        }
 
295
                        return 0;
 
296
                }
 
297
 
 
298
                private static bool DuplicateName(byte[] raw, int thisNamePos, int thisNameEnd)
 
299
                {
 
300
                        int sz = raw.Length;
 
301
                        int nextPtr = thisNameEnd + 1 + Constants.OBJECT_ID_LENGTH;
 
302
                        for (; ; )
 
303
                        {
 
304
                                int nextMode = 0;
 
305
                                for (; ; )
 
306
                                {
 
307
                                        if (nextPtr >= sz)
 
308
                                        {
 
309
                                                return false;
 
310
                                        }
 
311
                                        byte c = raw[nextPtr++];
 
312
                                        if (' ' == c)
 
313
                                        {
 
314
                                                break;
 
315
                                        }
 
316
                                        nextMode <<= 3;
 
317
                                        nextMode += c - '0';
 
318
                                }
 
319
                                int nextNamePos = nextPtr;
 
320
                                for (; ; )
 
321
                                {
 
322
                                        if (nextPtr == sz)
 
323
                                        {
 
324
                                                return false;
 
325
                                        }
 
326
                                        byte c = raw[nextPtr++];
 
327
                                        if (c == 0)
 
328
                                        {
 
329
                                                break;
 
330
                                        }
 
331
                                }
 
332
                                if (nextNamePos + 1 == nextPtr)
 
333
                                {
 
334
                                        return false;
 
335
                                }
 
336
                                int cmp = PathCompare(raw, thisNamePos, thisNameEnd, FileMode.TREE.GetBits(), nextNamePos
 
337
                                        , nextPtr - 1, nextMode);
 
338
                                if (cmp < 0)
 
339
                                {
 
340
                                        return false;
 
341
                                }
 
342
                                else
 
343
                                {
 
344
                                        if (cmp == 0)
 
345
                                        {
 
346
                                                return true;
 
347
                                        }
 
348
                                }
 
349
                                nextPtr += Constants.OBJECT_ID_LENGTH;
 
350
                        }
 
351
                }
 
352
 
 
353
                /// <summary>Check a canonical formatted tree for errors.</summary>
 
354
                /// <remarks>Check a canonical formatted tree for errors.</remarks>
 
355
                /// <param name="raw">the raw tree data. The array is never modified.</param>
 
356
                /// <exception cref="NGit.Errors.CorruptObjectException">if any error was detected.</exception>
 
357
                public virtual void CheckTree(byte[] raw)
 
358
                {
 
359
                        int sz = raw.Length;
 
360
                        int ptr = 0;
 
361
                        int lastNameB = 0;
 
362
                        int lastNameE = 0;
 
363
                        int lastMode = 0;
 
364
                        while (ptr < sz)
 
365
                        {
 
366
                                int thisMode = 0;
 
367
                                for (; ; )
 
368
                                {
 
369
                                        if (ptr == sz)
 
370
                                        {
 
371
                                                throw new CorruptObjectException("truncated in mode");
 
372
                                        }
 
373
                                        byte c = raw[ptr++];
 
374
                                        if (' ' == c)
 
375
                                        {
 
376
                                                break;
 
377
                                        }
 
378
                                        if (((sbyte)c) < '0' || c > '7')
 
379
                                        {
 
380
                                                throw new CorruptObjectException("invalid mode character");
 
381
                                        }
 
382
                                        if (thisMode == 0 && c == '0')
 
383
                                        {
 
384
                                                throw new CorruptObjectException("mode starts with '0'");
 
385
                                        }
 
386
                                        thisMode <<= 3;
 
387
                                        thisMode += c - '0';
 
388
                                }
 
389
                                if (FileMode.FromBits(thisMode).GetObjectType() == Constants.OBJ_BAD)
 
390
                                {
 
391
                                        throw new CorruptObjectException("invalid mode " + thisMode);
 
392
                                }
 
393
                                int thisNameB = ptr;
 
394
                                for (; ; )
 
395
                                {
 
396
                                        if (ptr == sz)
 
397
                                        {
 
398
                                                throw new CorruptObjectException("truncated in name");
 
399
                                        }
 
400
                                        byte c = raw[ptr++];
 
401
                                        if (c == 0)
 
402
                                        {
 
403
                                                break;
 
404
                                        }
 
405
                                        if (c == '/')
 
406
                                        {
 
407
                                                throw new CorruptObjectException("name contains '/'");
 
408
                                        }
 
409
                                }
 
410
                                if (thisNameB + 1 == ptr)
 
411
                                {
 
412
                                        throw new CorruptObjectException("zero length name");
 
413
                                }
 
414
                                if (raw[thisNameB] == '.')
 
415
                                {
 
416
                                        int nameLen = (ptr - 1) - thisNameB;
 
417
                                        if (nameLen == 1)
 
418
                                        {
 
419
                                                throw new CorruptObjectException("invalid name '.'");
 
420
                                        }
 
421
                                        if (nameLen == 2 && raw[thisNameB + 1] == '.')
 
422
                                        {
 
423
                                                throw new CorruptObjectException("invalid name '..'");
 
424
                                        }
 
425
                                }
 
426
                                if (DuplicateName(raw, thisNameB, ptr - 1))
 
427
                                {
 
428
                                        throw new CorruptObjectException("duplicate entry names");
 
429
                                }
 
430
                                if (lastNameB != 0)
 
431
                                {
 
432
                                        int cmp = PathCompare(raw, lastNameB, lastNameE, lastMode, thisNameB, ptr - 1, thisMode
 
433
                                                );
 
434
                                        if (cmp > 0)
 
435
                                        {
 
436
                                                throw new CorruptObjectException("incorrectly sorted");
 
437
                                        }
 
438
                                }
 
439
                                lastNameB = thisNameB;
 
440
                                lastNameE = ptr - 1;
 
441
                                lastMode = thisMode;
 
442
                                ptr += Constants.OBJECT_ID_LENGTH;
 
443
                                if (ptr > sz)
 
444
                                {
 
445
                                        throw new CorruptObjectException("truncated in object id");
 
446
                                }
 
447
                        }
 
448
                }
 
449
 
 
450
                /// <summary>Check a blob for errors.</summary>
 
451
                /// <remarks>Check a blob for errors.</remarks>
 
452
                /// <param name="raw">the blob data. The array is never modified.</param>
 
453
                /// <exception cref="NGit.Errors.CorruptObjectException">if any error was detected.</exception>
 
454
                public virtual void CheckBlob(byte[] raw)
 
455
                {
 
456
                }
 
457
                // We can always assume the blob is valid.
 
458
        }
 
459
}