/// <summary>
        /// Check an annotated tag for errors.
        /// </summary>
        /// <param name="raw">The tag data. The array is never modified.</param>
        /// <exception cref="CorruptObjectException">If any error was detected.</exception>
        public void checkTag(byte[] raw)
        {
            int ptr = 0;

            if ((ptr = RawParseUtils.match(raw, ptr, @object)) < 0)
            {
                throw new CorruptObjectException("no object header");
            }
            if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
            {
                throw new CorruptObjectException("invalid object");
            }

            if ((ptr = RawParseUtils.match(raw, ptr, type)) < 0)
            {
                throw new CorruptObjectException("no type header");
            }
            ptr = RawParseUtils.nextLF(raw, ptr);

            if ((ptr = RawParseUtils.match(raw, ptr, tag)) < 0)
            {
                throw new CorruptObjectException("no tag header");
            }
            ptr = RawParseUtils.nextLF(raw, ptr);

            if ((ptr = RawParseUtils.match(raw, ptr, tagger)) > 0)
            {
                if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
                {
                    throw new CorruptObjectException("invalid tagger");
                }
            }
        }
Beispiel #2
0
        public int parseTraditionalHeaders(int ptr, int end)
        {
            while (ptr < end)
            {
                int eol = RawParseUtils.nextLF(Buffer, ptr);
                if (isHunkHdr(Buffer, ptr, eol) >= 1)
                {
                    // First hunk header; break out and parse them later.
                    break;
                }

                if (RawParseUtils.match(Buffer, ptr, OLD_NAME) >= 0)
                {
                    ParseOldName(ptr, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, NEW_NAME) >= 0)
                {
                    ParseNewName(ptr, eol);
                }
                else
                {
                    // Possibly an empty patch.
                    break;
                }

                ptr = eol;
            }

            return(ptr);
        }
 public void testMatch_Prefix()
 {
     byte[] src = Constants.encodeASCII("author ");
     byte[] dst = Constants.encodeASCII("author A. U. Thor");
     Assert.IsTrue(RawParseUtils.match(dst, 0, src) == src.Length);
     Assert.IsTrue(RawParseUtils.match(dst, 1, src) < 0);
 }
Beispiel #4
0
 private static int SkipFile(byte[] buf, int ptr)
 {
     ptr = RawParseUtils.nextLF(buf, ptr);
     if (RawParseUtils.match(buf, ptr, FileHeader.OLD_NAME) >= 0)
     {
         ptr = RawParseUtils.nextLF(buf, ptr);
     }
     return(ptr);
 }
Beispiel #5
0
 private static bool MatchAny(byte[] buf, int c, IEnumerable <byte[]> srcs)
 {
     foreach (byte[] s in srcs)
     {
         if (RawParseUtils.match(buf, c, s) >= 0)
         {
             return(true);
         }
     }
     return(false);
 }
Beispiel #6
0
        public override int parseGitHeaders(int ptr, int end)
        {
            while (ptr < end)
            {
                int eol = RawParseUtils.nextLF(Buffer, ptr);
                if (isHunkHdr(Buffer, ptr, end) >= 1)
                {
                    // First hunk header; break out and parse them later.
                    break;
                }

                if (RawParseUtils.match(Buffer, ptr, OLD_NAME) >= 0)
                {
                    ParseOldName(ptr, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, NEW_NAME) >= 0)
                {
                    ParseNewName(ptr, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, Index) >= 0)
                {
                    ParseIndexLine(ptr + Index.Length, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, Mode) >= 0)
                {
                    parseModeLine(ptr + Mode.Length, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, NewFileMode) >= 0)
                {
                    ParseNewFileMode(ptr, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, DeletedFileMode) >= 0)
                {
                    parseDeletedFileMode(ptr + DeletedFileMode.Length, eol);
                }
                else
                {
                    // Probably an empty patch (stat dirty).
                    break;
                }

                ptr = eol;
            }
            return(ptr);
        }
        /// <summary>
        /// Check a commit for errors.
        /// </summary>
        /// <param name="raw">The commit data. The array is never modified.</param>
        /// <exception cref="CorruptObjectException">If any error was detected.</exception>
        public void checkCommit(byte[] raw)
        {
            int ptr = 0;

            if ((ptr = RawParseUtils.match(raw, ptr, tree)) < 0)
            {
                throw new CorruptObjectException("no tree header");
            }
            if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
            {
                throw new CorruptObjectException("invalid tree");
            }

            while (RawParseUtils.match(raw, ptr, parent) >= 0)
            {
                ptr += parent.Length;
                if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
                {
                    throw new CorruptObjectException("invalid parent");
                }
            }

            if ((ptr = RawParseUtils.match(raw, ptr, author)) < 0)
            {
                throw new CorruptObjectException("no author");
            }
            if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
            {
                throw new CorruptObjectException("invalid author");
            }

            if ((ptr = RawParseUtils.match(raw, ptr, committer)) < 0)
            {
                throw new CorruptObjectException("no committer");
            }
            if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
            {
                throw new CorruptObjectException("invalid committer");
            }
        }
Beispiel #8
0
        public int parseHunk(int ptr, int end)
        {
            byte[] buf = file.Buffer;

            if (RawParseUtils.match(buf, ptr, LITERAL) >= 0)
            {
                type   = Type.LITERAL_DEFLATED;
                length = RawParseUtils.parseBase10(buf, ptr + LITERAL.Length, null);
            }
            else if (RawParseUtils.match(buf, ptr, DELTA) >= 0)
            {
                type   = Type.DELTA_DEFLATED;
                length = RawParseUtils.parseBase10(buf, ptr + DELTA.Length, null);
            }
            else
            {
                // Not a valid binary hunk. Signal to the caller that
                // we cannot parse any further and that this line should
                // be treated otherwise.
                //
                return(-1);
            }
            ptr = RawParseUtils.nextLF(buf, ptr);

            // Skip until the first blank line; that is the end of the binary
            // encoded information in this hunk. To save time we don't do a
            // validation of the binary data at this point.
            //
            while (ptr < end)
            {
                bool empty = buf[ptr] == '\n';
                ptr = RawParseUtils.nextLF(buf, ptr);
                if (empty)
                {
                    break;
                }
            }

            return(ptr);
        }
Beispiel #9
0
        private void OnOpenPack()
        {
            PackIndex idx = LoadPackIndex();
            var       buf = new byte[20];

            IO.ReadFully(_fd, 0, buf, 0, 12);
            if (RawParseUtils.match(buf, 0, Constants.PACK_SIGNATURE) != 4)
            {
                throw new IOException("Not a PACK file.");
            }

            long vers    = NB.decodeUInt32(buf, 4);
            long packCnt = NB.decodeUInt32(buf, 8);

            if (vers != 2 && vers != 3)
            {
                throw new IOException("Unsupported pack version " + vers + ".");
            }

            if (packCnt != idx.ObjectCount)
            {
                throw new PackMismatchException("Pack object count mismatch:"
                                                + " pack " + packCnt
                                                + " index " + idx.ObjectCount
                                                + ": " + File.FullName);
            }

            IO.ReadFully(_fd, Length - 20, buf, 0, 20);

            if (!buf.SequenceEqual(_packChecksum))
            {
                throw new PackMismatchException("Pack checksum mismatch:"
                                                + " pack " + ObjectId.FromRaw(buf)
                                                + " index " + ObjectId.FromRaw(idx.PackChecksum)
                                                + ": " + File.FullName);
            }
        }
Beispiel #10
0
        private int ParseHunks(FileHeader fh, int c, int end)
        {
            byte[] buf = fh.Buffer;
            while (c < end)
            {
                // If we see a file header at this point, we have all of the
                // hunks for our current file. We should stop and report back
                // with this position so it can be parsed again later.
                //
                if (RawParseUtils.match(buf, c, DiffGit) >= 0)
                {
                    break;
                }
                if (RawParseUtils.match(buf, c, DiffCc) >= 0)
                {
                    break;
                }
                if (RawParseUtils.match(buf, c, DiffCombined) >= 0)
                {
                    break;
                }
                if (RawParseUtils.match(buf, c, FileHeader.OLD_NAME) >= 0)
                {
                    break;
                }
                if (RawParseUtils.match(buf, c, FileHeader.NEW_NAME) >= 0)
                {
                    break;
                }

                if (FileHeader.isHunkHdr(buf, c, end) == fh.ParentCount)
                {
                    HunkHeader h = fh.newHunkHeader(c);
                    h.parseHeader();
                    c           = h.parseBody(this, end);
                    h.EndOffset = c;
                    fh.addHunk(h);
                    if (c < end)
                    {
                        switch (buf[c])
                        {
                        case (byte)'@':
                        case (byte)'d':
                        case (byte)'\n':
                            break;

                        default:
                            if (RawParseUtils.match(buf, c, SigFooter) < 0)
                            {
                                warn(buf, c, "Unexpected hunk trailer");
                            }
                            break;
                        }
                    }
                    continue;
                }

                int eol = RawParseUtils.nextLF(buf, c);
                if (fh.Hunks.isEmpty() && RawParseUtils.match(buf, c, GitBinary) >= 0)
                {
                    fh.PatchType = FileHeader.PatchTypeEnum.GIT_BINARY;
                    return(ParseGitBinary(fh, eol, end));
                }

                if (fh.Hunks.isEmpty() && BinTrailer.Length < eol - c &&
                    RawParseUtils.match(buf, eol - BinTrailer.Length, BinTrailer) >= 0 &&
                    MatchAny(buf, c, BinHeaders))
                {
                    // The patch is a binary file diff, with no deltas.
                    //
                    fh.PatchType = FileHeader.PatchTypeEnum.BINARY;
                    return(eol);
                }

                // Skip this line and move to the next. Its probably garbage
                // After the last hunk of a file.
                //
                c = eol;
            }

            if (fh.Hunks.isEmpty() &&
                fh.getPatchType() == FileHeader.PatchTypeEnum.UNIFIED &&
                !fh.hasMetaDataChanges())
            {
                // Hmm, an empty patch? If there is no metadata here we
                // really have a binary patch that we didn't notice above.
                //
                fh.PatchType = FileHeader.PatchTypeEnum.BINARY;
            }

            return(c);
        }
Beispiel #11
0
        private int ParseFile(byte[] buf, int c, int end)
        {
            while (c < end)
            {
                if (FileHeader.isHunkHdr(buf, c, end) >= 1)
                {
                    // If we find a disconnected hunk header we might
                    // have missed a file header previously. The hunk
                    // isn't valid without knowing where it comes from.
                    //
                    error(buf, c, "Hunk disconnected from file");
                    c = RawParseUtils.nextLF(buf, c);
                    continue;
                }

                // Valid git style patch?
                //
                if (RawParseUtils.match(buf, c, DiffGit) >= 0)
                {
                    return(ParseDiffGit(buf, c, end));
                }
                if (RawParseUtils.match(buf, c, DiffCc) >= 0)
                {
                    return(ParseDiffCombined(DiffCc, buf, c, end));
                }
                if (RawParseUtils.match(buf, c, DiffCombined) >= 0)
                {
                    return(ParseDiffCombined(DiffCombined, buf, c, end));
                }

                // Junk between files? Leading junk? Traditional
                // (non-git generated) patch?
                //
                int n = RawParseUtils.nextLF(buf, c);
                if (n >= end)
                {
                    // Patches cannot be only one line long. This must be
                    // trailing junk that we should ignore.
                    //
                    return(end);
                }

                if (n - c < 6)
                {
                    // A valid header must be at least 6 bytes on the
                    // first line, e.g. "--- a/b\n".
                    //
                    c = n;
                    continue;
                }

                if (RawParseUtils.match(buf, c, FileHeader.OLD_NAME) >= 0 &&
                    RawParseUtils.match(buf, n, FileHeader.NEW_NAME) >= 0)
                {
                    // Probably a traditional patch. Ensure we have at least
                    // a "@@ -0,0" smelling line next. We only check the "@@ -".
                    //
                    int f = RawParseUtils.nextLF(buf, n);
                    if (f >= end)
                    {
                        return(end);
                    }
                    if (FileHeader.isHunkHdr(buf, f, end) == 1)
                    {
                        return(ParseTraditionalPatch(buf, c, end));
                    }
                }

                c = n;
            }
            return(c);
        }
Beispiel #12
0
        public virtual int parseGitHeaders(int ptr, int end)
        {
            while (ptr < end)
            {
                int eol = RawParseUtils.nextLF(Buffer, ptr);
                if (isHunkHdr(Buffer, ptr, eol) >= 1)
                {
                    // First hunk header; break out and parse them later.
                    break;
                }

                if (RawParseUtils.match(Buffer, ptr, OLD_NAME) >= 0)
                {
                    ParseOldName(ptr, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, NEW_NAME) >= 0)
                {
                    ParseNewName(ptr, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, OldModeString) >= 0)
                {
                    _oldMode = ParseFileMode(ptr + OldModeString.Length, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, NewModeString) >= 0)
                {
                    _newMode = ParseFileMode(ptr + NewModeString.Length, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, DeletedFileMode) >= 0)
                {
                    _oldMode   = ParseFileMode(ptr + DeletedFileMode.Length, eol);
                    _newMode   = FileMode.Missing;
                    ChangeType = ChangeTypeEnum.DELETE;
                }
                else if (RawParseUtils.match(Buffer, ptr, NewFileMode) >= 0)
                {
                    ParseNewFileMode(ptr, eol);
                }
                else if (RawParseUtils.match(Buffer, ptr, CopyFrom) >= 0)
                {
                    oldName    = ParseName(oldName, ptr + CopyFrom.Length, eol);
                    ChangeType = ChangeTypeEnum.COPY;
                }
                else if (RawParseUtils.match(Buffer, ptr, CopyTo) >= 0)
                {
                    newName    = ParseName(newName, ptr + CopyTo.Length, eol);
                    ChangeType = ChangeTypeEnum.COPY;
                }
                else if (RawParseUtils.match(Buffer, ptr, RenameOld) >= 0)
                {
                    oldName    = ParseName(oldName, ptr + RenameOld.Length, eol);
                    ChangeType = ChangeTypeEnum.RENAME;
                }
                else if (RawParseUtils.match(Buffer, ptr, RenameNew) >= 0)
                {
                    newName    = ParseName(newName, ptr + RenameNew.Length, eol);
                    ChangeType = ChangeTypeEnum.RENAME;
                }
                else if (RawParseUtils.match(Buffer, ptr, RenameFrom) >= 0)
                {
                    oldName    = ParseName(oldName, ptr + RenameFrom.Length, eol);
                    ChangeType = ChangeTypeEnum.RENAME;
                }
                else if (RawParseUtils.match(Buffer, ptr, RenameTo) >= 0)
                {
                    newName    = ParseName(newName, ptr + RenameTo.Length, eol);
                    ChangeType = ChangeTypeEnum.RENAME;
                }
                else if (RawParseUtils.match(Buffer, ptr, SimilarityIndex) >= 0)
                {
                    _score = RawParseUtils.parseBase10(Buffer, ptr + SimilarityIndex.Length, null);
                }
                else if (RawParseUtils.match(Buffer, ptr, DissimilarityIndex) >= 0)
                {
                    _score = RawParseUtils.parseBase10(Buffer, ptr + DissimilarityIndex.Length, null);
                }
                else if (RawParseUtils.match(Buffer, ptr, Index) >= 0)
                {
                    ParseIndexLine(ptr + Index.Length, eol);
                }
                else
                {
                    // Probably an empty patch (stat dirty).
                    break;
                }

                ptr = eol;
            }

            return(ptr);
        }
 public void testMatch_TooSmall()
 {
     byte[] src = Constants.encodeASCII("author ");
     byte[] dst = Constants.encodeASCII("author autho");
     Assert.IsTrue(RawParseUtils.match(dst, src.Length + 1, src) < 0);
 }
 public void testMatch_NotEqual()
 {
     byte[] src = Constants.encodeASCII(" differ\n");
     byte[] dst = Constants.encodeASCII("a differ\n");
     Assert.IsTrue(RawParseUtils.match(dst, 2, src) < 0);
 }
 public void testMatch_Equal()
 {
     byte[] src = Constants.encodeASCII(" differ\n");
     byte[] dst = Constants.encodeASCII("foo differ\n");
     Assert.IsTrue(RawParseUtils.match(dst, 3, src) == 3 + src.Length);
 }
Beispiel #16
0
        public virtual int parseBody(Patch script, int end)
        {
            byte[] buf = _file.Buffer;
            int    c = RawParseUtils.nextLF(buf, _startOffset), last = c;

            _oldImage.LinesDeleted = 0;
            _oldImage.LinesAdded   = 0;

            for (; c < end; last = c, c = RawParseUtils.nextLF(buf, c))
            {
                bool breakScan;
                switch (buf[c])
                {
                case (byte)' ':
                case (byte)'\n':
                    LinesContext++;
                    continue;

                case (byte)'-':
                    _oldImage.LinesDeleted++;
                    continue;

                case (byte)'+':
                    _oldImage.LinesAdded++;
                    continue;

                case (byte)'\\':                         // Matches "\ No newline at end of file"
                    continue;

                default:
                    breakScan = true;
                    break;
                }

                if (breakScan)
                {
                    break;
                }
            }

            if (last < end && LinesContext + _oldImage.LinesDeleted - 1 == _oldImage.LineCount &&
                LinesContext + _oldImage.LinesAdded == NewLineCount &&
                RawParseUtils.match(buf, last, Patch.SigFooter) >= 0)
            {
                // This is an extremely common occurrence of "corruption".
                // Users add footers with their signatures After this mark,
                // and git diff adds the git executable version number.
                // Let it slide; the hunk otherwise looked sound.
                //
                _oldImage.LinesDeleted--;
                return(last);
            }

            if (LinesContext + _oldImage.LinesDeleted < _oldImage.LineCount)
            {
                int missingCount = _oldImage.LineCount - (LinesContext + _oldImage.LinesDeleted);
                script.error(buf, _startOffset, "Truncated hunk, at least "
                             + missingCount + " old lines is missing");
            }
            else if (LinesContext + _oldImage.LinesAdded < NewLineCount)
            {
                int missingCount = NewLineCount - (LinesContext + _oldImage.LinesAdded);
                script.error(buf, _startOffset, "Truncated hunk, at least "
                             + missingCount + " new lines is missing");
            }
            else if (LinesContext + _oldImage.LinesDeleted > _oldImage.LineCount ||
                     LinesContext + _oldImage.LinesAdded > NewLineCount)
            {
                string oldcnt = _oldImage.LineCount + ":" + NewLineCount;
                string newcnt = (LinesContext + _oldImage.LinesDeleted) + ":"
                                + (LinesContext + _oldImage.LinesAdded);
                script.warn(buf, _startOffset, "Hunk header " + oldcnt
                            + " does not match body line count of " + newcnt);
            }

            return(c);
        }