Esempio n. 1
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);
        }
Esempio n. 2
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);
        }
Esempio n. 3
0
        /// <summary>
        /// Parse a "diff --git" or "diff --cc" line.
        /// </summary>
        /// <param name="ptr">
        /// first character After the "diff --git " or "diff --cc " part.
        /// </param>
        /// <param name="end">
        /// one past the last position to parse.
        /// </param>
        /// <returns>
        /// first character After the LF at the end of the line; -1 on error.
        /// </returns>
        public int parseGitFileName(int ptr, int end)
        {
            int eol = RawParseUtils.nextLF(Buffer, ptr);
            int bol = ptr;

            if (eol >= end)
            {
                return(-1);
            }

            // buffer[ptr..eol] looks like "a/foo b/foo\n". After the first
            // A regex to match this is "^[^/]+/(.*?) [^/+]+/\1\n$". There
            // is only one way to split the line such that text to the left
            // of the space matches the text to the right, excluding the part
            // before the first slash.
            //
            int aStart = RawParseUtils.nextLF(Buffer, ptr, (byte)'/');

            if (aStart >= eol)
            {
                return(eol);
            }

            while (ptr < eol)
            {
                int sp = RawParseUtils.nextLF(Buffer, ptr, (byte)' ');
                if (sp >= eol)
                {
                    // We can't split the header, it isn't valid.
                    // This may be OK if this is a rename patch.
                    //
                    return(eol);
                }
                int bStart = RawParseUtils.nextLF(Buffer, sp, (byte)'/');
                if (bStart >= eol)
                {
                    return(eol);
                }

                // If buffer[aStart..sp - 1] = buffer[bStart..eol - 1]
                // we have a valid split.
                //
                if (Eq(aStart, sp - 1, bStart, eol - 1))
                {
                    if (Buffer[bol] == '"')
                    {
                        // We're a double quoted name. The region better end
                        // in a double quote too, and we need to decode the
                        // characters before reading the name.
                        //
                        if (Buffer[sp - 2] != '"')
                        {
                            return(eol);
                        }
                        oldName = QuotedString.GitPathStyle.GIT_PATH.dequote(Buffer, bol, sp - 1);
                        oldName = P1(oldName);
                    }
                    else
                    {
                        oldName = RawParseUtils.decode(Constants.CHARSET, Buffer, aStart, sp - 1);
                    }
                    newName = oldName;
                    return(eol);
                }

                // This split wasn't correct. Move past the space and try
                // another split as the space must be part of the file name.
                //
                ptr = sp;
            }

            return(eol);
        }
Esempio n. 4
0
        public void parseCanonical(RevWalk walk, byte[] raw)
        {
            MutableObjectId idBuffer = walk.IdBuffer;

            idBuffer.FromString(raw, 5);
            _tree = walk.lookupTree(idBuffer);

            int ptr = 46;

            if (Parents == null)
            {
                var pList    = new RevCommit[1];
                int nParents = 0;

                while (true)
                {
                    if (raw[ptr] != (byte)'p')
                    {
                        break;
                    }
                    idBuffer.FromString(raw, ptr + 7);
                    RevCommit p = walk.lookupCommit(idBuffer);
                    if (nParents == 0)
                    {
                        pList[nParents++] = p;
                    }
                    else if (nParents == 1)
                    {
                        pList    = new[] { pList[0], p };
                        nParents = 2;
                    }
                    else
                    {
                        if (pList.Length <= nParents)
                        {
                            RevCommit[] old = pList;
                            pList = new RevCommit[pList.Length + 32];
                            Array.Copy(old, 0, pList, 0, nParents);
                        }
                        pList[nParents++] = p;
                    }
                    ptr += 48;
                }
                if (nParents != pList.Length)
                {
                    RevCommit[] old = pList;
                    pList = new RevCommit[nParents];
                    Array.Copy(old, 0, pList, 0, nParents);
                }
                Parents = pList;
            }

            // extract time from "committer "
            ptr = RawParseUtils.committer(raw, ptr);
            if (ptr > 0)
            {
                ptr = RawParseUtils.nextLF(raw, ptr, (byte)'>');

                // In 2038 commitTime will overflow unless it is changed to long.
                CommitTime = RawParseUtils.parseBase10(raw, ptr, null);
            }

            if (walk.isRetainBody())
            {
                _buffer = raw;
            }
            Flags |= PARSED;
        }
Esempio n. 5
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);
        }
Esempio n. 6
0
        /// <summary>
        /// Line of the patch script the error appears on.
        /// </summary>
        /// <returns></returns>
        public string getLineText()
        {
            int eol = RawParseUtils.nextLF(_buf, _offset);

            return(RawParseUtils.decode(Constants.CHARSET, _buf, _offset, eol));
        }
Esempio n. 7
0
        public override void extractFileLines(StringBuilder sb, string[] text, int[] offsets)
        {
            byte[] buf = File.Buffer;
            int    ptr = StartOffset;
            int    eol = RawParseUtils.nextLF(buf, ptr);

            if (EndOffset <= eol)
            {
                return;
            }

            copyLine(sb, text, offsets, 0);

            for (ptr = eol; ptr < EndOffset; ptr = eol)
            {
                eol = RawParseUtils.nextLF(buf, ptr);

                if (eol - ptr < _old.Count + 1)
                {
                    // Line isn't long enough to mention the state of each
                    // ancestor. It must be the end of the hunk.
                    break;
                }

                bool breakScan = false;
                switch (buf[ptr])
                {
                case (byte)' ':
                case (byte)'-':
                case (byte)'+':
                    break;

                default:
                    // Line can't possibly be part of this hunk; the first
                    // ancestor information isn't recognizable.
                    //
                    breakScan = true;
                    break;
                }
                if (breakScan)
                {
                    break;
                }

                bool copied = false;
                for (int ancestor = 0; ancestor < _old.Count; ancestor++)
                {
                    switch (buf[ptr + ancestor])
                    {
                    case (byte)' ':
                    case (byte)'-':
                        if (copied)
                        {
                            skipLine(text, offsets, ancestor);
                        }
                        else
                        {
                            copyLine(sb, text, offsets, ancestor);
                            copied = true;
                        }
                        continue;

                    case (byte)'+':
                        continue;

                    default:
                        breakScan = true;
                        break;
                    }

                    if (breakScan)
                    {
                        break;
                    }
                }

                if (breakScan)
                {
                    break;
                }

                if (!copied)
                {
                    // If none of the ancestors caused the copy then this line
                    // must be new across the board, so it only appears in the
                    // text of the new file.
                    //
                    copyLine(sb, text, offsets, _old.Count);
                }
            }
        }
Esempio n. 8
0
        public void extractFileLines(Stream[] outStream)
        {
            byte[] buf = File.Buffer;
            int    ptr = StartOffset;
            int    eol = RawParseUtils.nextLF(buf, ptr);

            if (EndOffset <= eol)
            {
                return;
            }

            // Treat the hunk header as though it were from the ancestor,
            // as it may have a function header appearing After it which
            // was copied out of the ancestor file.
            //
            outStream[0].Write(buf, ptr, eol - ptr);

            //SCAN:
            for (ptr = eol; ptr < EndOffset; ptr = eol)
            {
                eol = RawParseUtils.nextLF(buf, ptr);

                if (eol - ptr < _old.Count + 1)
                {
                    // Line isn't long enough to mention the state of each
                    // ancestor. It must be the end of the hunk.
                    break;
                }

                bool breakScan = false;
                switch (buf[ptr])
                {
                case (byte)' ':
                case (byte)'-':
                case (byte)'+':
                    break;

                default:
                    // Line can't possibly be part of this hunk; the first
                    // ancestor information isn't recognizable.
                    //
                    breakScan = true;
                    break;
                }
                if (breakScan)
                {
                    break;
                }

                int delcnt = 0;
                for (int ancestor = 0; ancestor < _old.Count; ancestor++)
                {
                    switch (buf[ptr + ancestor])
                    {
                    case (byte)'-':
                        delcnt++;
                        outStream[ancestor].Write(buf, ptr, eol - ptr);
                        continue;

                    case (byte)' ':
                        outStream[ancestor].Write(buf, ptr, eol - ptr);
                        continue;

                    case (byte)'+':
                        continue;

                    default:
                        breakScan = true;
                        break;
                    }

                    if (breakScan)
                    {
                        break;
                    }
                }

                if (breakScan)
                {
                    break;
                }

                if (delcnt < _old.Count)
                {
                    // This line appears in the new file if it wasn't deleted
                    // relative to all ancestors.
                    //
                    outStream[_old.Count].Write(buf, ptr, eol - ptr);
                }
            }
        }
Esempio n. 9
0
        public override int parseBody(Patch script, int end)
        {
            byte[] buf = File.Buffer;
            int    c   = RawParseUtils.nextLF(buf, StartOffset);

            _old.ForEach(coi =>
            {
                coi.LinesAdded   = 0;
                coi.LinesDeleted = 0;
                coi.LinesContext = 0;
            });

            LinesContext = 0;
            int nAdded = 0;

            for (int eol; c < end; c = eol)
            {
                eol = RawParseUtils.nextLF(buf, c);

                if (eol - c < _old.Count + 1)
                {
                    // Line isn't long enough to mention the state of each
                    // ancestor. It must be the end of the hunk.
                    break;
                }

                bool break_scan = false;
                switch (buf[c])
                {
                case (byte)' ':
                case (byte)'-':
                case (byte)'+':
                    break;

                default:
                    // Line can't possibly be part of this hunk; the first
                    // ancestor information isn't recognizable.
                    //
                    break_scan = true;
                    break;
                }
                if (break_scan)
                {
                    break;
                }

                int localcontext = 0;
                for (int ancestor = 0; ancestor < _old.Count; ancestor++)
                {
                    switch (buf[c + ancestor])
                    {
                    case (byte)' ':
                        localcontext++;
                        _old[ancestor].LinesContext++;
                        continue;

                    case (byte)'-':
                        _old[ancestor].LinesDeleted++;
                        continue;

                    case (byte)'+':
                        _old[ancestor].LinesAdded++;
                        nAdded++;
                        continue;

                    default:
                        break_scan = true;
                        break;
                    }
                    if (break_scan)
                    {
                        break;
                    }
                }
                if (break_scan)
                {
                    break;
                }

                if (localcontext == _old.Count)
                {
                    LinesContext++;
                }
            }

            for (int ancestor = 0; ancestor < _old.Count; ancestor++)
            {
                CombinedOldImage o = _old[ancestor];
                int cmp            = o.LinesContext + o.LinesDeleted;
                if (cmp < o.LineCount)
                {
                    int missingCnt = o.LineCount - cmp;
                    script.error(buf, StartOffset, "Truncated hunk, at least "
                                 + missingCnt + " lines is missing for ancestor "
                                 + (ancestor + 1));
                }
            }

            if (LinesContext + nAdded < NewLineCount)
            {
                int missingCount = NewLineCount - (LinesContext + nAdded);
                script.error(buf, StartOffset, "Truncated hunk, at least "
                             + missingCount + " new lines is missing");
            }

            return(c);
        }
Esempio n. 10
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);
        }