1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.velocity.tools

File CSSIdentifierSerializer.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

18
29
5
1
137
59
18
0.62
5.8
5
3.6

Classes

Class Line # Actions
CSSIdentifierSerializer 35 29 0% 18 0
1.0100%
 

Contributing tests

This file is covered by 2 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.velocity.tools;
21   
22    import org.apache.commons.lang3.StringUtils;
23   
24    /**
25    * Implements the specification regarding CSS identifier serialization.
26    * <p>
27    * See https://drafts.csswg.org/cssom/#serialize-an-identifier
28    * </p>
29    *
30    * @version $Id: 6976ae319d22d88f97daac9e8216c5567f7e1f6c $
31    * @since 6.4.7
32    * @since 7.1.4
33    * @since 7.4M1
34    */
 
35    public class CSSIdentifierSerializer
36    {
37    private static final int[][] NO_ESCAPE_RANGES = new int[][] {new int[] {0x0030, 0x0039},
38    new int[] {0x0041, 0x005A}, new int[] {0x0061, 0x007A}};
39   
40    /**
41    * Serialize a CSS identifier.
42    * <p>
43    * NOTE: This code was adapted from Mathias Bynens' CSS.escape polyfill, available under the MIT license.
44    * </p>
45    * <p>
46    * See https://drafts.csswg.org/cssom/#serialize-an-identifier and https://github.com/mathiasbynens/CSS.escape.
47    * </p>
48    *
49    * @param identifier the identifier to serialize
50    * @return the serialized identifier
51    * @throws IllegalArgumentException if the input contains U+0000
52    */
 
53  54 toggle public String serialize(String identifier)
54    {
55  54 if (StringUtils.isEmpty(identifier)) {
56  2 return identifier;
57    }
58   
59  52 int length = identifier.length();
60  52 int index = -1;
61  52 StringBuilder result = new StringBuilder();
62  52 int firstCodeUnit = identifier.charAt(0);
63   
64  301 while (++index < length) {
65  254 int codeUnit = identifier.charAt(index);
66    // Note: there's no need to special-case astral symbols, surrogate pairs, or lone surrogates.
67   
68    // If the character is NULL (U+0000), throw an IllegalArgumentException exception and terminate these steps.
69  254 if (codeUnit == 0x0000) {
70  5 throw new IllegalArgumentException("Invalid character: the input contains U+0000.");
71   
72  249 } else if (shouldEscapeAsCodePoint(codeUnit, index, firstCodeUnit)) {
73    // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point
74  25 result.append('\\').append(Integer.toHexString(codeUnit)).append(' ');
75   
76  224 } else if (index == 0 && length == 1 && codeUnit == 0x002D) {
77    // If the character is the first character and is a '-' (U+002D), and there is no second character
78    // https://drafts.csswg.org/cssom/#escape-a-character
79  1 result.append('\\').append(identifier.charAt(index));
80   
81  223 } else if (shouldNotEscape(codeUnit)) {
82    // the character itself
83  201 result.append(identifier.charAt(index));
84   
85    } else {
86    // Otherwise, the escaped character.
87    // https://drafts.csswg.org/cssom/#escape-a-character
88  22 result.append('\\').append(identifier.charAt(index));
89    }
90    }
91   
92  47 return result.toString();
93    }
94   
95    /**
96    * See https://drafts.csswg.org/cssom/#escape-a-character-as-code-point.
97    */
 
98  249 toggle private boolean shouldEscapeAsCodePoint(int codeUnit, int index, int firstCodeUnit)
99    {
100    // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is U+007F, [...]
101  249 if (isInRange(codeUnit, 0x0001, 0x001F) || codeUnit == 0x007F) {
102  5 return true;
103   
104  244 } else if (index == 0 && isInRange(codeUnit, 0x0030, 0x0039)) {
105    // If the character is the first character and is in the range [0-9] (U+0030 to U+0039), [...]
106  10 return true;
107   
108    } else {
109    // If the character is the second character and is in the range [0-9] (U+0030 to U+0039) and the first
110    // character is a '-' (U+002D), [...]
111  234 return index == 1 && isInRange(codeUnit, 0x0030, 0x0039) && firstCodeUnit == 0x002D;
112    }
113    }
114   
 
115  223 toggle private boolean shouldNotEscape(int codeUnit)
116    {
117    // If the character is not handled by one of the above rules and is greater than or equal to U+0080, is '-'
118    // (U+002D) or '_' (U+005F), or is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to U+005A),
119    // or [a-z] (U+0061 to U+007A), [...]
120  223 return codeUnit >= 0x0080 || codeUnit == 0x002D || codeUnit == 0x005F || isInRanges(codeUnit, NO_ESCAPE_RANGES);
121    }
122   
 
123  769 toggle private boolean isInRange(int codeUnit, int start, int end)
124    {
125  769 return codeUnit >= start && codeUnit <= end;
126    }
127   
 
128  165 toggle private boolean isInRanges(int codeUnit, int[][] ranges)
129    {
130  165 for (int[] range : ranges) {
131  429 if (isInRange(codeUnit, range[0], range[1])) {
132  143 return true;
133    }
134    }
135  22 return false;
136    }
137    }