EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.server.web]

COVERAGE SUMMARY FOR SOURCE FILE [PageParser.java]

nameclass, %method, %block, %line, %
PageParser.java100% (1/1)94%  (15/16)82%  (590/721)80%  (151/188)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class PageParser100% (1/1)94%  (15/16)82%  (590/721)80%  (151/188)
setError (int): void 0%   (0/1)0%   (0/32)0%   (0/5)
read (String): void 100% (1/1)42%  (5/12)67%  (2/3)
escapeJavaScript (String): String 100% (1/1)56%  (37/66)45%  (10/22)
replaceTags (): String 100% (1/1)57%  (12/21)57%  (4/7)
parseBlockUntil (String): String 100% (1/1)75%  (24/32)83%  (5/6)
get (String): Object 100% (1/1)76%  (34/45)89%  (8/9)
parseAll (): void 100% (1/1)89%  (218/246)83%  (53/64)
escapeHtml (String, boolean): String 100% (1/1)95%  (125/132)92%  (36/39)
PageParser (String, Map, int): void 100% (1/1)100% (23/23)100% (7/7)
escapeHtml (String): String 100% (1/1)100% (4/4)100% (1/1)
escapeHtmlData (String): String 100% (1/1)100% (4/4)100% (1/1)
parse (String, Map): String 100% (1/1)100% (10/10)100% (2/2)
readIf (String): boolean 100% (1/1)100% (25/25)100% (6/6)
readParam (String): String 100% (1/1)100% (43/43)100% (10/10)
replaceTags (String): void 100% (1/1)100% (11/11)100% (3/3)
skipSpaces (): void 100% (1/1)100% (15/15)100% (3/3)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.server.web;
7 
8import java.text.ParseException;
9import java.util.HashMap;
10import java.util.List;
11import java.util.Map;
12import org.h2.util.New;
13 
14/**
15 * A page parser can parse an HTML page and replace the tags there.
16 * This class is used by the H2 Console.
17 */
18public class PageParser {
19    private static final int TAB_WIDTH = 4;
20 
21    private final String page;
22    private int pos;
23    private final Map<String, Object> settings;
24    private final int len;
25    private StringBuilder result;
26 
27    private PageParser(String page, Map<String, Object> settings, int pos) {
28        this.page = page;
29        this.pos = pos;
30        this.len = page.length();
31        this.settings = settings;
32        result = new StringBuilder(len);
33    }
34 
35    /**
36     * Replace the tags in the HTML page with the given settings.
37     *
38     * @param page the HTML page
39     * @param settings the settings
40     * @return the converted page
41     */
42    public static String parse(String page, Map<String, Object> settings) {
43        PageParser block = new PageParser(page, settings, 0);
44        return block.replaceTags();
45    }
46 
47    private void setError(int i) {
48        String s = page.substring(0, i) + "####BUG####" + page.substring(i);
49        s = PageParser.escapeHtml(s);
50        result = new StringBuilder();
51        result.append(s);
52    }
53 
54    private String parseBlockUntil(String end) throws ParseException {
55        PageParser block = new PageParser(page, settings, pos);
56        block.parseAll();
57        if (!block.readIf(end)) {
58            throw new ParseException(page, block.pos);
59        }
60        pos = block.pos;
61        return block.result.toString();
62    }
63 
64    private String replaceTags() {
65        try {
66            parseAll();
67            if (pos != len) {
68                setError(pos);
69            }
70        } catch (ParseException e) {
71            setError(pos);
72        }
73        return result.toString();
74    }
75 
76    @SuppressWarnings("unchecked")
77    private void parseAll() throws ParseException {
78        StringBuilder buff = result;
79        String p = page;
80        int i = pos;
81        for (; i < len; i++) {
82            char c = p.charAt(i);
83            switch (c) {
84            case '<': {
85                if (p.charAt(i + 3) == ':' && p.charAt(i + 1) == '/') {
86                    // end tag
87                    pos = i;
88                    return;
89                } else if (p.charAt(i + 2) == ':') {
90                    pos = i;
91                    if (readIf("<c:forEach")) {
92                        String var = readParam("var");
93                        String items = readParam("items");
94                        read(">");
95                        int start = pos;
96                        List<Object> list = (List<Object>) get(items);
97                        if (list == null) {
98                            result.append("?items?");
99                            list = New.arrayList();
100                        }
101                        if (list.size() == 0) {
102                            parseBlockUntil("</c:forEach>");
103                        }
104                        for (Object o : list) {
105                            settings.put(var, o);
106                            pos = start;
107                            String block = parseBlockUntil("</c:forEach>");
108                            result.append(block);
109                        }
110                    } else if (readIf("<c:if")) {
111                        String test = readParam("test");
112                        int eq = test.indexOf("=='");
113                        if (eq < 0) {
114                            setError(i);
115                            return;
116                        }
117                        String val = test.substring(eq + 3, test.length() - 1);
118                        test = test.substring(0, eq);
119                        String value = (String) get(test);
120                        read(">");
121                        String block = parseBlockUntil("</c:if>");
122                        pos--;
123                        if (value.equals(val)) {
124                            result.append(block);
125                        }
126                    } else {
127                        setError(i);
128                        return;
129                    }
130                    i = pos;
131                } else {
132                    buff.append(c);
133                }
134                break;
135            }
136            case '$':
137                if (p.length() > i + 1 && p.charAt(i + 1) == '{') {
138                    i += 2;
139                    int j = p.indexOf('}', i);
140                    if (j < 0) {
141                        setError(i);
142                        return;
143                    }
144                    String item = p.substring(i, j).trim();
145                    i = j;
146                    String s = (String) get(item);
147                    replaceTags(s);
148                } else {
149                    buff.append(c);
150                }
151                break;
152            default:
153                buff.append(c);
154                break;
155            }
156        }
157        pos = i;
158    }
159 
160    @SuppressWarnings("unchecked")
161    private Object get(String item) {
162        int dot = item.indexOf('.');
163        if (dot >= 0) {
164            String sub = item.substring(dot + 1);
165            item = item.substring(0, dot);
166            HashMap<String, Object> map = (HashMap<String, Object>) settings.get(item);
167            if (map == null) {
168                return "?" + item + "?";
169            }
170            return map.get(sub);
171        }
172        return settings.get(item);
173    }
174 
175    private void replaceTags(String s) {
176        if (s != null) {
177            result.append(PageParser.parse(s, settings));
178        }
179    }
180 
181    private String readParam(String name) throws ParseException {
182        read(name);
183        read("=");
184        read("\"");
185        int start = pos;
186        while (page.charAt(pos) != '"') {
187            pos++;
188        }
189        int end = pos;
190        read("\"");
191        String s = page.substring(start, end);
192        return PageParser.parse(s, settings);
193    }
194 
195    private void skipSpaces() {
196        while (page.charAt(pos) == ' ') {
197            pos++;
198        }
199    }
200 
201    private void read(String s) throws ParseException {
202        if (!readIf(s)) {
203            throw new ParseException(s, pos);
204        }
205    }
206 
207    private boolean readIf(String s) {
208        skipSpaces();
209        if (page.regionMatches(pos, s, 0, s.length())) {
210            pos += s.length();
211            skipSpaces();
212            return true;
213        }
214        return false;
215    }
216 
217    /**
218     * Convert data to HTML, but don't convert newlines and multiple spaces.
219     *
220     * @param s the data
221     * @return the escaped html text
222     */
223    static String escapeHtmlData(String s) {
224        return escapeHtml(s, false);
225    }
226 
227    /**
228     * Convert data to HTML, including newlines and multiple spaces.
229     *
230     * @param s the data
231     * @return the escaped html text
232     */
233    public static String escapeHtml(String s) {
234        return escapeHtml(s, true);
235    }
236 
237    private static String escapeHtml(String s, boolean convertBreakAndSpace) {
238        if (s == null) {
239            return null;
240        }
241        if (convertBreakAndSpace) {
242            if (s.length() == 0) {
243                return "&nbsp;";
244            }
245        }
246        StringBuilder buff = new StringBuilder(s.length());
247        boolean convertSpace = true;
248        for (int i = 0; i < s.length(); i++) {
249            char c = s.charAt(i);
250            if (c == ' ' || c == '\t') {
251                // convert tabs into spaces
252                for (int j = 0; j < (c == ' ' ? 1 : TAB_WIDTH); j++) {
253                    if (convertSpace && convertBreakAndSpace) {
254                        buff.append("&nbsp;");
255                    } else {
256                        buff.append(' ');
257                        convertSpace = true;
258                    }
259                }
260                continue;
261            }
262            convertSpace = false;
263            switch (c) {
264            case '$':
265                // so that ${ } in the text is interpreted correctly
266                buff.append("&#36;");
267                break;
268            case '<':
269                buff.append("&lt;");
270                break;
271            case '>':
272                buff.append("&gt;");
273                break;
274            case '&':
275                buff.append("&amp;");
276                break;
277            case '"':
278                buff.append("&quot;");
279                break;
280            case '\'':
281                buff.append("&#39;");
282                break;
283            case '\n':
284                if (convertBreakAndSpace) {
285                    buff.append("<br />");
286                    convertSpace = true;
287                } else {
288                    buff.append(c);
289                }
290                break;
291            default:
292                if (c >= 128) {
293                    buff.append("&#").append((int) c).append(';');
294                } else {
295                    buff.append(c);
296                }
297                break;
298            }
299        }
300        return buff.toString();
301    }
302 
303    /**
304     * Escape text as a the javascript string.
305     *
306     * @param s the text
307     * @return the javascript string
308     */
309    static String escapeJavaScript(String s) {
310        if (s == null) {
311            return null;
312        }
313        if (s.length() == 0) {
314            return "";
315        }
316        StringBuilder buff = new StringBuilder(s.length());
317        for (int i = 0; i < s.length(); i++) {
318            char c = s.charAt(i);
319            switch (c) {
320            case '"':
321                buff.append("\\\"");
322                break;
323            case '\'':
324                buff.append("\\'");
325                break;
326            case '\\':
327                buff.append("\\\\");
328                break;
329            case '\n':
330                buff.append("\\n");
331                break;
332            case '\r':
333                buff.append("\\r");
334                break;
335            case '\t':
336                buff.append("\\t");
337                break;
338            default:
339                buff.append(c);
340                break;
341            }
342        }
343        return buff.toString();
344    }
345}

[all classes][org.h2.server.web]
EMMA 2.0.5312 (C) Vladimir Roubtsov