|
20 | 20 | package org.sonar.cxx.preprocessor; |
21 | 21 |
|
22 | 22 | import java.math.BigInteger; |
| 23 | +import java.util.Collections; |
23 | 24 | import java.util.HashMap; |
| 25 | +import java.util.Map; |
| 26 | +import org.sonar.api.internal.apachecommons.lang.StringUtils; |
24 | 27 |
|
25 | 28 | /** |
26 | 29 | * Helper class to evaluate preprocessor numbers. |
27 | 30 | */ |
28 | 31 | final class PPNumber { |
29 | 32 |
|
30 | 33 | private static final HashMap<String, BigInteger> numberCache = new HashMap<>(); |
| 34 | + private static final Map<String, Integer> namedUniversalCharacter = createNamedUniversalCharacter(); |
31 | 35 |
|
32 | 36 | private PPNumber() { |
33 | 37 |
|
@@ -127,27 +131,79 @@ static BigInteger decodeCharacter(String charValue) { |
127 | 131 | } |
128 | 132 |
|
129 | 133 | switch (charValue.charAt(1)) { |
130 | | - case 't': |
131 | | - return BigInteger.valueOf('\t'); |
132 | | - case 'b': |
133 | | - return BigInteger.valueOf('\b'); |
134 | | - case 'n': |
135 | | - return BigInteger.valueOf('\n'); |
136 | | - case 'r': |
137 | | - return BigInteger.valueOf('\r'); |
138 | | - case 'f': |
139 | | - return BigInteger.valueOf('\f'); |
140 | 134 | case '\'': |
141 | 135 | return BigInteger.valueOf('\''); |
142 | 136 | case '"': |
143 | 137 | return BigInteger.valueOf('\"'); |
| 138 | + case '?': |
| 139 | + return BigInteger.valueOf(0x3f); |
144 | 140 | case '\\': |
145 | 141 | return BigInteger.valueOf('\\'); |
| 142 | + case 'a': |
| 143 | + return BigInteger.valueOf(0x07); |
| 144 | + case 'b': |
| 145 | + return BigInteger.valueOf('\b'); |
| 146 | + case 'f': |
| 147 | + return BigInteger.valueOf('\f'); |
| 148 | + case 'n': |
| 149 | + return BigInteger.valueOf('\n'); |
| 150 | + case 'r': |
| 151 | + return BigInteger.valueOf('\r'); |
| 152 | + case 't': |
| 153 | + return BigInteger.valueOf('\t'); |
| 154 | + case 'v': |
| 155 | + return BigInteger.valueOf(0x0b); |
| 156 | + |
| 157 | + case 'u': |
| 158 | + if (charValue.length() > 2 && charValue.charAt(2) == '{') { |
| 159 | + return delimitedEscapeSequences(charValue, 16); |
| 160 | + } |
| 161 | + return new BigInteger(StringUtils.substring(charValue, 2, 2 + 4), 16); // 4 hexadecimal digits |
| 162 | + |
| 163 | + case 'U': |
| 164 | + return new BigInteger(StringUtils.substring(charValue, 2, 2 + 8), 16); // 8 hexadecimal digits |
| 165 | + |
146 | 166 | case 'x': |
147 | | - case 'X': |
| 167 | + if (charValue.length() > 2 && charValue.charAt(2) == '{') { |
| 168 | + return delimitedEscapeSequences(charValue, 16); |
| 169 | + } |
148 | 170 | return new BigInteger(charValue.substring(2), 16); |
| 171 | + |
| 172 | + case 'o': |
| 173 | + if (charValue.length() > 2 && charValue.charAt(2) == '{') { |
| 174 | + return delimitedEscapeSequences(charValue, 8); |
| 175 | + } |
| 176 | + return BigInteger.ZERO; |
| 177 | + |
| 178 | + case 'N': |
| 179 | + if (charValue.length() > 2 && charValue.charAt(2) == '{') { |
| 180 | + return delimitedEscapeSequences(charValue, -1); |
| 181 | + } |
| 182 | + return BigInteger.ZERO; |
| 183 | + |
149 | 184 | default: |
150 | | - return new BigInteger(charValue.substring(1), 10); |
| 185 | + return new BigInteger(charValue.substring(1), 8); |
151 | 186 | } |
152 | 187 | } |
| 188 | + |
| 189 | + static BigInteger delimitedEscapeSequences(String charValue, int radix) { |
| 190 | + int end = charValue.indexOf('}', 3); |
| 191 | + if (end != -1) { |
| 192 | + String value = charValue.substring(3, end); |
| 193 | + if (radix != -1) { |
| 194 | + return new BigInteger(value, radix); |
| 195 | + } else { // character named by NAME |
| 196 | + return BigInteger.valueOf(namedUniversalCharacter.getOrDefault(value, 1)); |
| 197 | + } |
| 198 | + } |
| 199 | + return BigInteger.ZERO; |
| 200 | + } |
| 201 | + |
| 202 | + // currently only NULL and NUL is supported, rest is mapped to 1 |
| 203 | + private static Map<String, Integer> createNamedUniversalCharacter() { |
| 204 | + Map<String, Integer> result = new HashMap<>(); |
| 205 | + result.put("NULL", 0); |
| 206 | + result.put("NUL", 0); |
| 207 | + return Collections.unmodifiableMap(result); |
| 208 | + } |
153 | 209 | } |
0 commit comments