/** * Parse a base 10 numeric from a sequence of ASCII digits into an int. * <para /> * Digit sequences can begin with an optional run of spaces before the * sequence, and may start with a '+' or a '-' to indicate sign position. * Any other characters will cause the method to stop and return the current * result to the caller. * * @param b * buffer to scan. * @param ptr * position within buffer to start parsing digits at. * @param ptrResult * optional location to return the new ptr value through. If null * the ptr value will be discarded. * @return the value at this location; 0 if the location is not a valid * numeric. */ public static int parseBase10(byte[] b, int ptr, MutableInteger ptrResult) { int r = 0; int sign = 0; try { int sz = b.Length; while (ptr < sz && b[ptr] == ' ') { ptr++; } if (ptr >= sz) { return(0); } switch (b[ptr]) { case ((byte)'-'): sign = -1; ptr++; break; case ((byte)'+'): ptr++; break; } while (ptr < sz) { byte d = b[ptr]; if ((d < (byte)'0') || (d > (byte)'9')) { break; } r = r * 10 + (d - (byte)'0'); ptr++; } } catch (IndexOutOfRangeException) { // Not a valid digit. } if (ptrResult != null) { ptrResult.value = ptr; } return(sign < 0 ? -r : r); }
/// <summary> /// Parse a base 10 numeric from a sequence of ASCII digits into a long. /// <para /> /// Digit sequences can begin with an optional run of spaces before the /// sequence, and may start with a '+' or a '-' to indicate sign position. /// Any other characters will cause the method to stop and return the current /// result to the caller. /// </summary> /// <param name="b">Buffer to scan.</param> /// <param name="ptr"> /// Position within buffer to start parsing digits at. /// </param> /// <param name="ptrResult"> /// Optional location to return the new ptr value through. If null /// the ptr value will be discarded. /// </param> /// <returns> /// The value at this location; 0 if the location is not a valid /// numeric. /// </returns> public static long parseLongBase10(byte[] b, int ptr, MutableInteger ptrResult) { long r = 0; int sign = 0; try { int sz = b.Length; while (ptr < sz && b[ptr] == ' ') { ptr++; } if (ptr >= sz) { return(0); } switch (b[ptr]) { case (byte)'-': sign = -1; ptr++; break; case (byte)'+': ptr++; break; } while (ptr < sz) { int v = b[ptr] - (byte)'0'; if (v < 0) { break; } r = (r * 10) + v; ptr++; } } catch (IndexOutOfRangeException) { // Not a valid digit. } if (ptrResult != null) { ptrResult.value = ptr; } return(sign < 0 ? -r : r); }
/** * Parse a name line (e.g. author, committer, tagger) into a PersonIdent. * <para /> * When passing in a value for <code>nameB</code> callers should use the * return value of {@link #author(byte[], int)} or * {@link #committer(byte[], int)}, as these methods provide the proper * position within the buffer. * * @param raw * the buffer to parse character data from. * @param nameB * first position of the identity information. This should be the * first position After the space which delimits the header field * name (e.g. "author" or "committer") from the rest of the * identity line. * @return the parsed identity. Never null. */ public static PersonIdent parsePersonIdent(byte[] raw, int nameB) { Encoding cs = parseEncoding(raw); int emailB = nextLF(raw, nameB, (byte)'<'); int emailE = nextLF(raw, emailB, (byte)'>'); string name = decode(cs, raw, nameB, emailB - 2); string email = decode(cs, raw, emailB, emailE - 1); var ptrout = new MutableInteger(); long when = parseLongBase10(raw, emailE + 1, ptrout); int tz = parseTimeZoneOffset(raw, ptrout.value); return(new PersonIdent(name, email, when * 1000, tz)); }
public void parseCanonical(RevWalk walk, byte[] rawTag) { var pos = new MutableInteger { value = 53 }; int oType = Constants.decodeTypeString(this, rawTag, (byte)'\n', pos); walk.IdBuffer.FromString(rawTag, 7); _object = walk.lookupAny(walk.IdBuffer, oType); int p = pos.value += 4; // "tag " int nameEnd = RawParseUtils.nextLF(rawTag, p) - 1; _tagName = RawParseUtils.decode(Constants.CHARSET, rawTag, p, nameEnd); if (walk.isRetainBody()) _buffer = rawTag; Flags |= PARSED; }
/** * Parse a name data (e.g. as within a reflog) into a PersonIdent. * <para /> * When passing in a value for <code>nameB</code> callers should use the * return value of {@link #author(byte[], int)} or * {@link #committer(byte[], int)}, as these methods provide the proper * position within the buffer. * * @param raw * the buffer to parse character data from. * @param nameB * first position of the identity information. This should be the * first position After the space which delimits the header field * name (e.g. "author" or "committer") from the rest of the * identity line. * @return the parsed identity. Never null. */ public static PersonIdent parsePersonIdentOnly(byte[] raw, int nameB) { int stop = nextLF(raw, nameB); int emailB = nextLF(raw, nameB, (byte)'<'); int emailE = nextLF(raw, emailB, (byte)'>'); string name; string email; if (emailE < stop) { email = decode(raw, emailB, emailE - 1); } else { email = "invalid"; } if (emailB < stop) { name = decode(raw, nameB, emailB - 2); } else { name = decode(raw, nameB, stop); } MutableInteger ptrout = new MutableInteger(); long when; int tz; if (emailE < stop) { when = parseLongBase10(raw, emailE + 1, ptrout); tz = parseTimeZoneOffset(raw, ptrout.value); } else { when = 0; tz = 0; } return(new PersonIdent(name, email, when * 1000, tz)); }
/// <summary> /// Parse an encoded type string into a type constant. /// </summary> /// <param name="id"> /// <see cref="ObjectId" /> this type string came from; may be null if /// that is not known at the time the parse is occurring. /// </param> /// <param name="typeString">string version of the type code.</param> /// <param name="endMark"> /// Character immediately following the type string. Usually ' ' /// (space) or '\n' (line feed). /// </param> /// <param name="offset"> /// Position within <paramref name="typeString"/> where the parse /// should start. Updated with the new position (just past /// <paramref name="endMark"/> when the parse is successful). /// </param> /// <returns> /// A type code constant (one of <see cref="OBJ_BLOB"/>, /// <see cref="OBJ_COMMIT"/>, <see cref="OBJ_TAG"/>, <see cref="OBJ_TREE"/> /// </returns> /// <exception cref="CorruptObjectException"></exception> public static int decodeTypeString(AnyObjectId id, byte[] typeString, byte endMark, MutableInteger offset) { try { int position = offset.value; switch (typeString[position]) { case (byte)'b': if (typeString[position + 1] != (byte)'l' || typeString[position + 2] != (byte)'o' || typeString[position + 3] != (byte)'b' || typeString[position + 4] != endMark) { throw new CorruptObjectException(id, "invalid type"); } offset.value = position + 5; return OBJ_BLOB; case (byte)'c': if (typeString[position + 1] != (byte)'o' || typeString[position + 2] != (byte)'m' || typeString[position + 3] != (byte)'m' || typeString[position + 4] != (byte)'i' || typeString[position + 5] != (byte)'t' || typeString[position + 6] != endMark) { throw new CorruptObjectException(id, "invalid type"); } offset.value = position + 7; return OBJ_COMMIT; case (byte)'t': switch (typeString[position + 1]) { case (byte)'a': if (typeString[position + 2] != (byte)'g' || typeString[position + 3] != endMark) throw new CorruptObjectException(id, "invalid type"); offset.value = position + 4; return OBJ_TAG; case (byte)'r': if (typeString[position + 2] != (byte)'e' || typeString[position + 3] != (byte)'e' || typeString[position + 4] != endMark) throw new CorruptObjectException(id, "invalid type"); offset.value = position + 5; return OBJ_TREE; default: throw new CorruptObjectException(id, "invalid type"); } default: throw new CorruptObjectException(id, "invalid type"); } } catch (IndexOutOfRangeException) { throw new CorruptObjectException(id, "invalid type"); } }
private UnpackedObjectLoader(byte[] compressed, AnyObjectId id) { // Try to determine if this is a legacy format loose object or // a new style loose object. The legacy format was completely // compressed with zlib so the first byte must be 0x78 (15-bit // window size, deflated) and the first 16 bit word must be // evenly divisible by 31. Otherwise its a new style loose // object. // Inflater inflater = InflaterCache.Instance.get(); try { int fb = compressed[0] & 0xff; if (fb == 0x78 && (((fb << 8) | compressed[1] & 0xff) % 31) == 0) { inflater.SetInput(compressed); var hdr = new byte[64]; int avail = 0; while (!inflater.IsFinished && avail < hdr.Length) { try { avail += inflater.Inflate(hdr, avail, hdr.Length - avail); } catch (IOException dfe) { var coe = new CorruptObjectException(id, "bad stream", dfe); //inflater.end(); throw coe; } } if (avail < 5) { throw new CorruptObjectException(id, "no header"); } var p = new MutableInteger(); _objectType = Constants.decodeTypeString(id, hdr, (byte)' ', p); _objectSize = RawParseUtils.parseBase10(hdr, p.value, p); if (_objectSize < 0) { throw new CorruptObjectException(id, "negative size"); } if (hdr[p.value++] != 0) { throw new CorruptObjectException(id, "garbage after size"); } _bytes = new byte[_objectSize]; if (p.value < avail) { Array.Copy(hdr, p.value, _bytes, 0, avail - p.value); } Decompress(id, inflater, avail - p.value); } else { int p = 0; int c = compressed[p++] & 0xff; int typeCode = (c >> 4) & 7; int size = c & 15; int shift = 4; while ((c & 0x80) != 0) { c = compressed[p++] & 0xff; size += (c & 0x7f) << shift; shift += 7; } switch (typeCode) { case Constants.OBJ_COMMIT: case Constants.OBJ_TREE: case Constants.OBJ_BLOB: case Constants.OBJ_TAG: _objectType = typeCode; break; default: throw new CorruptObjectException(id, "invalid type"); } _objectSize = size; _bytes = new byte[_objectSize]; inflater.SetInput(compressed, p, compressed.Length - p); Decompress(id, inflater, 0); } } finally { InflaterCache.Instance.release(inflater); } }
/** * Parse a name data (e.g. as within a reflog) into a PersonIdent. * <para /> * When passing in a value for <code>nameB</code> callers should use the * return value of {@link #author(byte[], int)} or * {@link #committer(byte[], int)}, as these methods provide the proper * position within the buffer. * * @param raw * the buffer to parse character data from. * @param nameB * first position of the identity information. This should be the * first position After the space which delimits the header field * name (e.g. "author" or "committer") from the rest of the * identity line. * @return the parsed identity. Never null. */ public static PersonIdent parsePersonIdentOnly(byte[] raw, int nameB) { int stop = nextLF(raw, nameB); int emailB = nextLF(raw, nameB, (byte)'<'); int emailE = nextLF(raw, emailB, (byte)'>'); string name; string email; if (emailE < stop) { email = decode(raw, emailB, emailE - 1); } else { email = "invalid"; } if (emailB < stop) name = decode(raw, nameB, emailB - 2); else name = decode(raw, nameB, stop); MutableInteger ptrout = new MutableInteger(); long when; int tz; if (emailE < stop) { when = parseLongBase10(raw, emailE + 1, ptrout); tz = parseTimeZoneOffset(raw, ptrout.value); } else { when = 0; tz = 0; } return new PersonIdent(name, email, when * 1000, tz); }
/** * Parse a name line (e.g. author, committer, tagger) into a PersonIdent. * <para /> * When passing in a value for <code>nameB</code> callers should use the * return value of {@link #author(byte[], int)} or * {@link #committer(byte[], int)}, as these methods provide the proper * position within the buffer. * * @param raw * the buffer to parse character data from. * @param nameB * first position of the identity information. This should be the * first position After the space which delimits the header field * name (e.g. "author" or "committer") from the rest of the * identity line. * @return the parsed identity. Never null. */ public static PersonIdent parsePersonIdent(byte[] raw, int nameB) { Encoding cs = parseEncoding(raw); int emailB = nextLF(raw, nameB, (byte)'<'); int emailE = nextLF(raw, emailB, (byte)'>'); string name = decode(cs, raw, nameB, emailB - 2); string email = decode(cs, raw, emailB, emailE - 1); var ptrout = new MutableInteger(); long when = parseLongBase10(raw, emailE + 1, ptrout); int tz = parseTimeZoneOffset(raw, ptrout.value); return new PersonIdent(name, email, when * 1000, tz); }
/// <summary> /// Parse a base 10 numeric from a sequence of ASCII digits into a long. /// <para /> /// Digit sequences can begin with an optional run of spaces before the /// sequence, and may start with a '+' or a '-' to indicate sign position. /// Any other characters will cause the method to stop and return the current /// result to the caller. /// </summary> /// <param name="b">Buffer to scan.</param> /// <param name="ptr"> /// Position within buffer to start parsing digits at. /// </param> /// <param name="ptrResult"> /// Optional location to return the new ptr value through. If null /// the ptr value will be discarded. /// </param> /// <returns> /// The value at this location; 0 if the location is not a valid /// numeric. /// </returns> public static long parseLongBase10(byte[] b, int ptr, MutableInteger ptrResult) { long r = 0; int sign = 0; try { int sz = b.Length; while (ptr < sz && b[ptr] == ' ') ptr++; if (ptr >= sz) return 0; switch (b[ptr]) { case (byte)'-': sign = -1; ptr++; break; case (byte)'+': ptr++; break; } while (ptr < sz) { int v = b[ptr] - (byte)'0'; if (v < 0) break; r = (r * 10) + v; ptr++; } } catch (IndexOutOfRangeException) { // Not a valid digit. } if (ptrResult != null) ptrResult.value = ptr; return sign < 0 ? -r : r; }
/** * Parse a base 10 numeric from a sequence of ASCII digits into an int. * <para /> * Digit sequences can begin with an optional run of spaces before the * sequence, and may start with a '+' or a '-' to indicate sign position. * Any other characters will cause the method to stop and return the current * result to the caller. * * @param b * buffer to scan. * @param ptr * position within buffer to start parsing digits at. * @param ptrResult * optional location to return the new ptr value through. If null * the ptr value will be discarded. * @return the value at this location; 0 if the location is not a valid * numeric. */ public static int parseBase10(byte[] b, int ptr, MutableInteger ptrResult) { int r = 0; int sign = 0; try { int sz = b.Length; while (ptr < sz && b[ptr] == ' ') ptr++; if (ptr >= sz) return 0; switch (b[ptr]) { case ((byte)'-'): sign = -1; ptr++; break; case ((byte)'+'): ptr++; break; } while (ptr < sz) { byte d = b[ptr]; if ((d < (byte)'0') || (d > (byte)'9')) break; r = r * 10 + (d - (byte)'0'); ptr++; } } catch (IndexOutOfRangeException) { // Not a valid digit. } if (ptrResult != null) ptrResult.value = ptr; return sign < 0 ? -r : r; }
public DirCacheTree(byte[] @in, MutableInteger off, DirCacheTree myParent) { _parent = myParent; int ptr = RawParseUtils.next(@in, off.value, (byte)'\0'); int nameLen = ptr - off.value - 1; if (nameLen > 0) { _encodedName = new byte[nameLen]; Array.Copy(@in, off.value, _encodedName, 0, nameLen); } else { _encodedName = NoName; } _entrySpan = RawParseUtils.parseBase10(@in, ptr, off); int subcnt = RawParseUtils.parseBase10(@in, off.value, off); off.value = RawParseUtils.next(@in, off.value, (byte)'\n'); if (_entrySpan >= 0) { // Valid trees have a positive entry count and an id of a // tree object that should exist in the object database. // _id = ObjectId.FromRaw(@in, off.value); off.value += Constants.OBJECT_ID_LENGTH; } if (subcnt > 0) { bool alreadySorted = true; _children = new DirCacheTree[subcnt]; for (int i = 0; i < subcnt; i++) { _children[i] = new DirCacheTree(@in, off, this); // C Git's ordering differs from our own; it prefers to // sort by Length first. This sometimes produces a sort // we do not desire. On the other hand it may have been // created by us, and be sorted the way we want. // if (alreadySorted && i > 0 && TreeComparison(_children[i - 1], _children[i]) > 0) { alreadySorted = false; } } if (!alreadySorted) { Array.Sort(_children, TreeComparison); } } else { // Leaf level trees have no children, only (file) entries. // _children = NoChildren; } _childCount = subcnt; }
public virtual void parseHeader() { // Parse "@@ -236,9 +236,9 @@ protected boolean" // byte[] buf = _file.Buffer; var ptr = new MutableInteger { value = RawParseUtils.nextLF(buf, _startOffset, (byte)' ') }; _oldImage.StartLine = -1 * RawParseUtils.parseBase10(buf, ptr.value, ptr); _oldImage.LineCount = buf[ptr.value] == ',' ? RawParseUtils.parseBase10(buf, ptr.value + 1, ptr) : 1; NewStartLine = RawParseUtils.parseBase10(buf, ptr.value + 1, ptr); NewLineCount = buf[ptr.value] == ',' ? RawParseUtils.parseBase10(buf, ptr.value + 1, ptr) : 1; }
public override void parseHeader() { // Parse "@@@ -55,12 -163,13 +163,15 @@@ protected boolean" // byte[] buf = File.Buffer; var ptr = new MutableInteger { value = RawParseUtils.nextLF(buf, StartOffset, (byte)' ') }; _old.ForEach(coi => { coi.StartLine = -1 * RawParseUtils.parseBase10(Buffer, ptr.value, ptr); coi.LineCount = buf[ptr.value] == ',' ? RawParseUtils.parseBase10(buf, ptr.value + 1, ptr) : 1; }); NewStartLine = RawParseUtils.parseBase10(buf, ptr.value + 1, ptr); NewLineCount = buf[ptr.value] == ',' ? RawParseUtils.parseBase10(buf, ptr.value + 1, ptr) : 1; }