1 /*
2 * Copyright (C) 2009, Google Inc. and others
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Distribution License v. 1.0 which is available at
6 * https://www.eclipse.org/org/documents/edl-v10.php.
7 *
8 * SPDX-License-Identifier: BSD-3-Clause
9 */
10
11 package org.eclipse.jgit.revwalk;
12
13 import java.nio.charset.Charset;
14
15 import org.eclipse.jgit.util.RawParseUtils;
16
17 /**
18 * Single line at the end of a message, such as a "Signed-off-by: someone".
19 * <p>
20 * These footer lines tend to be used to represent additional information about
21 * a commit, like the path it followed through reviewers before finally being
22 * accepted into the project's main repository as an immutable commit.
23 *
24 * @see RevCommit#getFooterLines()
25 */
26 public final class FooterLine {
27 private final byte[] buffer;
28
29 private final Charset enc;
30
31 private final int keyStart;
32
33 private final int keyEnd;
34
35 private final int valStart;
36
37 private final int valEnd;
38
39 FooterLine(final byte[] b, final Charset e, final int ks, final int ke,
40 final int vs, final int ve) {
41 buffer = b;
42 enc = e;
43 keyStart = ks;
44 keyEnd = ke;
45 valStart = vs;
46 valEnd = ve;
47 }
48
49 /**
50 * Whether keys match
51 *
52 * @param key
53 * key to test this line's key name against.
54 * @return true if {@code key.getName().equalsIgnorecase(getKey())}.
55 */
56 public boolean matches(FooterKey key) {
57 final byte[] kRaw = key.raw;
58 final int len = kRaw.length;
59 int bPtr = keyStart;
60 if (keyEnd - bPtr != len)
61 return false;
62 for (int kPtr = 0; kPtr < len;) {
63 byte b = buffer[bPtr++];
64 if ('A' <= b && b <= 'Z')
65 b += (byte) ('a' - 'A');
66 if (b != kRaw[kPtr++])
67 return false;
68 }
69 return true;
70 }
71
72 /**
73 * Get key name of this footer.
74 *
75 * @return key name of this footer; that is the text before the ":" on the
76 * line footer's line. The text is decoded according to the commit's
77 * specified (or assumed) character encoding.
78 */
79 public String getKey() {
80 return RawParseUtils.decode(enc, buffer, keyStart, keyEnd);
81 }
82
83 /**
84 * Get value of this footer.
85 *
86 * @return value of this footer; that is the text after the ":" and any
87 * leading whitespace has been skipped. May be the empty string if
88 * the footer has no value (line ended with ":"). The text is
89 * decoded according to the commit's specified (or assumed)
90 * character encoding.
91 */
92 public String getValue() {
93 return RawParseUtils.decode(enc, buffer, valStart, valEnd);
94 }
95
96 /**
97 * Extract the email address (if present) from the footer.
98 * <p>
99 * If there is an email address looking string inside of angle brackets
100 * (e.g. "<a@b>"), the return value is the part extracted from inside the
101 * brackets. If no brackets are found, then {@link #getValue()} is returned
102 * if the value contains an '@' sign. Otherwise, null.
103 *
104 * @return email address appearing in the value of this footer, or null.
105 */
106 public String getEmailAddress() {
107 final int lt = RawParseUtils.nextLF(buffer, valStart, '<');
108 if (valEnd <= lt) {
109 final int at = RawParseUtils.nextLF(buffer, valStart, '@');
110 if (valStart < at && at < valEnd)
111 return getValue();
112 return null;
113 }
114 final int gt = RawParseUtils.nextLF(buffer, lt, '>');
115 if (valEnd < gt)
116 return null;
117 return RawParseUtils.decode(enc, buffer, lt, gt - 1);
118 }
119
120 /** {@inheritDoc} */
121 @Override
122 public String toString() {
123 return getKey() + ": " + getValue(); //$NON-NLS-1$
124 }
125 }