OLD | NEW |
| (Empty) |
1 /* | |
2 * Simplified by Andrey Novikov for AdBlock Plus | |
3 */ | |
4 | |
5 /* | |
6 * Licensed to the Apache Software Foundation (ASF) under one or more | |
7 * contributor license agreements. See the NOTICE file distributed with | |
8 * this work for additional information regarding copyright ownership. | |
9 * The ASF licenses this file to You under the Apache License, Version 2.0 | |
10 * (the "License"); you may not use this file except in compliance with | |
11 * the License. You may obtain a copy of the License at | |
12 * | |
13 * http://www.apache.org/licenses/LICENSE-2.0 | |
14 * | |
15 * Unless required by applicable law or agreed to in writing, software | |
16 * distributed under the License is distributed on an "AS IS" BASIS, | |
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 * See the License for the specific language governing permissions and | |
19 * limitations under the License. | |
20 */ | |
21 package org.apache.commons.lang; | |
22 | |
23 import java.io.IOException; | |
24 import java.io.StringWriter; | |
25 import java.io.Writer; | |
26 | |
27 /** | |
28 * <p>Escapes and unescapes <code>String</code>s for | |
29 * Java, Java Script, HTML, XML, and SQL.</p> | |
30 * | |
31 * @author Apache Jakarta Turbine | |
32 * @author Purple Technology | |
33 * @author <a href="mailto:alex@purpletech.com">Alexander Day Chaffee</a> | |
34 * @author Antony Riley | |
35 * @author Helge Tesgaard | |
36 * @author <a href="sean@boohai.com">Sean Brown</a> | |
37 * @author <a href="mailto:ggregory@seagullsw.com">Gary Gregory</a> | |
38 * @author Phil Steitz | |
39 * @author Pete Gieser | |
40 * @since 2.0 | |
41 * @version $Id: StringEscapeUtils.java 612880 2008-01-17 17:34:43Z ggregory $ | |
42 */ | |
43 public class StringEscapeUtils | |
44 { | |
45 private static final char CSV_DELIMITER = ','; | |
46 private static final char CSV_QUOTE = '"'; | |
47 private static final String CSV_QUOTE_STR = String.valueOf(CSV_QUOTE); | |
48 private static final char[] CSV_SEARCH_CHARS = new char[]{CSV_DELIMITER, CSV_Q
UOTE, CharUtils.CR, CharUtils.LF}; | |
49 | |
50 /** | |
51 * <p><code>StringEscapeUtils</code> instances should NOT be constructed in | |
52 * standard programming.</p> | |
53 * | |
54 * <p>Instead, the class should be used as: | |
55 * <pre>StringEscapeUtils.escapeJava("foo");</pre></p> | |
56 * | |
57 * <p>This constructor is public to permit tools that require a JavaBean | |
58 * instance to operate.</p> | |
59 */ | |
60 public StringEscapeUtils() | |
61 { | |
62 super(); | |
63 } | |
64 | |
65 // Java and JavaScript | |
66 //-------------------------------------------------------------------------- | |
67 | |
68 /** | |
69 * <p>Escapes the characters in a <code>String</code> using Java String rules.
</p> | |
70 * | |
71 * <p>Deals correctly with quotes and control-chars (tab, backslash, cr, ff, e
tc.) </p> | |
72 * | |
73 * <p>So a tab becomes the characters <code>'\\'</code> and | |
74 * <code>'t'</code>.</p> | |
75 * | |
76 * <p>The only difference between Java strings and JavaScript strings | |
77 * is that in JavaScript, a single quote must be escaped.</p> | |
78 * | |
79 * <p>Example: | |
80 * <pre> | |
81 * input string: He didn't say, "Stop!" | |
82 * output string: He didn't say, \"Stop!\" | |
83 * </pre> | |
84 * </p> | |
85 * | |
86 * @param str String to escape values in, may be null | |
87 * @return String with escaped values, <code>null</code> if null string input | |
88 */ | |
89 public static String escapeJava(String str) | |
90 { | |
91 return escapeJavaStyleString(str, false); | |
92 } | |
93 | |
94 /** | |
95 * <p>Escapes the characters in a <code>String</code> using Java String rules
to | |
96 * a <code>Writer</code>.</p> | |
97 * | |
98 * <p>A <code>null</code> string input has no effect.</p> | |
99 * | |
100 * @see #escapeJava(java.lang.String) | |
101 * @param out Writer to write escaped string into | |
102 * @param str String to escape values in, may be null | |
103 * @throws IllegalArgumentException if the Writer is <code>null</code> | |
104 * @throws IOException if error occurs on underlying Writer | |
105 */ | |
106 public static void escapeJava(Writer out, String str) throws IOException | |
107 { | |
108 escapeJavaStyleString(out, str, false); | |
109 } | |
110 | |
111 /** | |
112 * <p>Escapes the characters in a <code>String</code> using JavaScript String
rules.</p> | |
113 * <p>Escapes any values it finds into their JavaScript String form. | |
114 * Deals correctly with quotes and control-chars (tab, backslash, cr, ff, etc.
) </p> | |
115 * | |
116 * <p>So a tab becomes the characters <code>'\\'</code> and | |
117 * <code>'t'</code>.</p> | |
118 * | |
119 * <p>The only difference between Java strings and JavaScript strings | |
120 * is that in JavaScript, a single quote must be escaped.</p> | |
121 * | |
122 * <p>Example: | |
123 * <pre> | |
124 * input string: He didn't say, "Stop!" | |
125 * output string: He didn\'t say, \"Stop!\" | |
126 * </pre> | |
127 * </p> | |
128 * | |
129 * @param str String to escape values in, may be null | |
130 * @return String with escaped values, <code>null</code> if null string input | |
131 */ | |
132 public static String escapeJavaScript(String str) | |
133 { | |
134 return escapeJavaStyleString(str, true); | |
135 } | |
136 | |
137 /** | |
138 * <p>Escapes the characters in a <code>String</code> using JavaScript String
rules | |
139 * to a <code>Writer</code>.</p> | |
140 * | |
141 * <p>A <code>null</code> string input has no effect.</p> | |
142 * | |
143 * @see #escapeJavaScript(java.lang.String) | |
144 * @param out Writer to write escaped string into | |
145 * @param str String to escape values in, may be null | |
146 * @throws IllegalArgumentException if the Writer is <code>null</code> | |
147 * @throws IOException if error occurs on underlying Writer | |
148 */ | |
149 public static void escapeJavaScript(Writer out, String str) throws IOException | |
150 { | |
151 escapeJavaStyleString(out, str, true); | |
152 } | |
153 | |
154 /** | |
155 * <p>Worker method for the {@link #escapeJavaScript(String)} method.</p> | |
156 * | |
157 * @param str String to escape values in, may be null | |
158 * @param escapeSingleQuotes escapes single quotes if <code>true</code> | |
159 * @return the escaped string | |
160 */ | |
161 private static String escapeJavaStyleString(String str, boolean escapeSingleQu
otes) | |
162 { | |
163 if (str == null) | |
164 { | |
165 return null; | |
166 } | |
167 try | |
168 { | |
169 StringWriter writer = new StringWriter(str.length() * 2); | |
170 escapeJavaStyleString(writer, str, escapeSingleQuotes); | |
171 return writer.toString(); | |
172 } | |
173 catch (IOException ioe) | |
174 { | |
175 // this should never ever happen while writing to a StringWriter | |
176 ioe.printStackTrace(); | |
177 return null; | |
178 } | |
179 } | |
180 | |
181 /** | |
182 * <p>Worker method for the {@link #escapeJavaScript(String)} method.</p> | |
183 * | |
184 * @param out write to receieve the escaped string | |
185 * @param str String to escape values in, may be null | |
186 * @param escapeSingleQuote escapes single quotes if <code>true</code> | |
187 * @throws IOException if an IOException occurs | |
188 */ | |
189 private static void escapeJavaStyleString(Writer out, String str, boolean esca
peSingleQuote) throws IOException | |
190 { | |
191 if (out == null) | |
192 { | |
193 throw new IllegalArgumentException("The Writer must not be null"); | |
194 } | |
195 if (str == null) | |
196 { | |
197 return; | |
198 } | |
199 int sz; | |
200 sz = str.length(); | |
201 for (int i = 0; i < sz; i++) | |
202 { | |
203 char ch = str.charAt(i); | |
204 | |
205 // handle unicode | |
206 if (ch > 0xfff) | |
207 { | |
208 out.write("\\u" + hex(ch)); | |
209 } else if (ch > 0xff) | |
210 { | |
211 out.write("\\u0" + hex(ch)); | |
212 } else if (ch > 0x7f) | |
213 { | |
214 out.write("\\u00" + hex(ch)); | |
215 } else if (ch < 32) | |
216 { | |
217 switch (ch) | |
218 { | |
219 case '\b': | |
220 out.write('\\'); | |
221 out.write('b'); | |
222 break; | |
223 case '\n': | |
224 out.write('\\'); | |
225 out.write('n'); | |
226 break; | |
227 case '\t': | |
228 out.write('\\'); | |
229 out.write('t'); | |
230 break; | |
231 case '\f': | |
232 out.write('\\'); | |
233 out.write('f'); | |
234 break; | |
235 case '\r': | |
236 out.write('\\'); | |
237 out.write('r'); | |
238 break; | |
239 default: | |
240 if (ch > 0xf) | |
241 { | |
242 out.write("\\u00" + hex(ch)); | |
243 } else | |
244 { | |
245 out.write("\\u000" + hex(ch)); | |
246 } | |
247 break; | |
248 } | |
249 } else | |
250 { | |
251 switch (ch) | |
252 { | |
253 case '\'': | |
254 if (escapeSingleQuote) | |
255 { | |
256 out.write('\\'); | |
257 } | |
258 out.write('\''); | |
259 break; | |
260 case '"': | |
261 out.write('\\'); | |
262 out.write('"'); | |
263 break; | |
264 case '\\': | |
265 out.write('\\'); | |
266 out.write('\\'); | |
267 break; | |
268 case '/': | |
269 out.write('\\'); | |
270 out.write('/'); | |
271 break; | |
272 default: | |
273 out.write(ch); | |
274 break; | |
275 } | |
276 } | |
277 } | |
278 } | |
279 | |
280 /** | |
281 * <p>Returns an upper case hexadecimal <code>String</code> for the given | |
282 * character.</p> | |
283 * | |
284 * @param ch The character to convert. | |
285 * @return An upper case hexadecimal <code>String</code> | |
286 */ | |
287 private static String hex(char ch) | |
288 { | |
289 return Integer.toHexString(ch).toUpperCase(); | |
290 } | |
291 | |
292 /** | |
293 * <p>Unescapes any Java literals found in the <code>String</code>. | |
294 * For example, it will turn a sequence of <code>'\'</code> and | |
295 * <code>'n'</code> into a newline character, unless the <code>'\'</code> | |
296 * is preceded by another <code>'\'</code>.</p> | |
297 * | |
298 * @param str the <code>String</code> to unescape, may be null | |
299 * @return a new unescaped <code>String</code>, <code>null</code> if null stri
ng input | |
300 */ | |
301 public static String unescapeJava(String str) | |
302 { | |
303 if (str == null) | |
304 { | |
305 return null; | |
306 } | |
307 try | |
308 { | |
309 StringWriter writer = new StringWriter(str.length()); | |
310 unescapeJava(writer, str); | |
311 return writer.toString(); | |
312 } catch (IOException ioe) | |
313 { | |
314 // this should never ever happen while writing to a StringWriter | |
315 ioe.printStackTrace(); | |
316 return null; | |
317 } | |
318 } | |
319 | |
320 /** | |
321 * <p>Unescapes any Java literals found in the <code>String</code> to a | |
322 * <code>Writer</code>.</p> | |
323 * | |
324 * <p>For example, it will turn a sequence of <code>'\'</code> and | |
325 * <code>'n'</code> into a newline character, unless the <code>'\'</code> | |
326 * is preceded by another <code>'\'</code>.</p> | |
327 * | |
328 * <p>A <code>null</code> string input has no effect.</p> | |
329 * | |
330 * @param out the <code>Writer</code> used to output unescaped characters | |
331 * @param str the <code>String</code> to unescape, may be null | |
332 * @throws IllegalArgumentException if the Writer is <code>null</code> | |
333 * @throws IOException if error occurs on underlying Writer | |
334 */ | |
335 public static void unescapeJava(Writer out, String str) throws IOException | |
336 { | |
337 if (out == null) | |
338 { | |
339 throw new IllegalArgumentException("The Writer must not be null"); | |
340 } | |
341 if (str == null) | |
342 { | |
343 return; | |
344 } | |
345 int sz = str.length(); | |
346 StringBuffer unicode = new StringBuffer(4); | |
347 boolean hadSlash = false; | |
348 boolean inUnicode = false; | |
349 for (int i = 0; i < sz; i++) | |
350 { | |
351 char ch = str.charAt(i); | |
352 if (inUnicode) | |
353 { | |
354 // if in unicode, then we're reading unicode | |
355 // values in somehow | |
356 unicode.append(ch); | |
357 if (unicode.length() == 4) | |
358 { | |
359 // unicode now contains the four hex digits | |
360 // which represents our unicode character | |
361 try | |
362 { | |
363 int value = Integer.parseInt(unicode.toString(), 16); | |
364 out.write((char) value); | |
365 unicode.setLength(0); | |
366 inUnicode = false; | |
367 hadSlash = false; | |
368 } catch (NumberFormatException nfe) | |
369 { | |
370 throw (IOException) new IOException("Unable to parse unicode value:
" + unicode).initCause(nfe); | |
371 } | |
372 } | |
373 continue; | |
374 } | |
375 if (hadSlash) | |
376 { | |
377 // handle an escaped value | |
378 hadSlash = false; | |
379 switch (ch) | |
380 { | |
381 case '\\': | |
382 out.write('\\'); | |
383 break; | |
384 case '\'': | |
385 out.write('\''); | |
386 break; | |
387 case '\"': | |
388 out.write('"'); | |
389 break; | |
390 case 'r': | |
391 out.write('\r'); | |
392 break; | |
393 case 'f': | |
394 out.write('\f'); | |
395 break; | |
396 case 't': | |
397 out.write('\t'); | |
398 break; | |
399 case 'n': | |
400 out.write('\n'); | |
401 break; | |
402 case 'b': | |
403 out.write('\b'); | |
404 break; | |
405 case 'u': | |
406 { | |
407 // uh-oh, we're in unicode country.... | |
408 inUnicode = true; | |
409 break; | |
410 } | |
411 default: | |
412 out.write(ch); | |
413 break; | |
414 } | |
415 continue; | |
416 } else if (ch == '\\') | |
417 { | |
418 hadSlash = true; | |
419 continue; | |
420 } | |
421 out.write(ch); | |
422 } | |
423 if (hadSlash) | |
424 { | |
425 // then we're in the weird case of a \ at the end of the | |
426 // string, let's output it anyway. | |
427 out.write('\\'); | |
428 } | |
429 } | |
430 | |
431 /** | |
432 * <p>Unescapes any JavaScript literals found in the <code>String</code>.</p> | |
433 * | |
434 * <p>For example, it will turn a sequence of <code>'\'</code> and <code>'n'</
code> | |
435 * into a newline character, unless the <code>'\'</code> is preceded by anothe
r | |
436 * <code>'\'</code>.</p> | |
437 * | |
438 * @see #unescapeJava(String) | |
439 * @param str the <code>String</code> to unescape, may be null | |
440 * @return A new unescaped <code>String</code>, <code>null</code> if null stri
ng input | |
441 */ | |
442 public static String unescapeJavaScript(String str) | |
443 { | |
444 return unescapeJava(str); | |
445 } | |
446 | |
447 /** | |
448 * <p>Unescapes any JavaScript literals found in the <code>String</code> to a | |
449 * <code>Writer</code>.</p> | |
450 * | |
451 * <p>For example, it will turn a sequence of <code>'\'</code> and <code>'n'</
code> | |
452 * into a newline character, unless the <code>'\'</code> is preceded by anothe
r | |
453 * <code>'\'</code>.</p> | |
454 * | |
455 * <p>A <code>null</code> string input has no effect.</p> | |
456 * | |
457 * @see #unescapeJava(Writer, String) | |
458 * @param out the <code>Writer</code> used to output unescaped characters | |
459 * @param str the <code>String</code> to unescape, may be null | |
460 * @throws IllegalArgumentException if the Writer is <code>null</code> | |
461 * @throws IOException if error occurs on underlying Writer | |
462 */ | |
463 public static void unescapeJavaScript(Writer out, String str) throws IOExcepti
on | |
464 { | |
465 unescapeJava(out, str); | |
466 } | |
467 | |
468 //----------------------------------------------------------------------- | |
469 | |
470 /** | |
471 * <p>Escapes the characters in a <code>String</code> to be suitable to pass t
o | |
472 * an SQL query.</p> | |
473 * | |
474 * <p>For example, | |
475 * <pre>statement.executeQuery("SELECT * FROM MOVIES WHERE TITLE='" + | |
476 * StringEscapeUtils.escapeSql("McHale's Navy") + | |
477 * "'");</pre> | |
478 * </p> | |
479 * | |
480 * <p>At present, this method only turns single-quotes into doubled single-quo
tes | |
481 * (<code>"McHale's Navy"</code> => <code>"McHale''s Navy"</code>). It does no
t | |
482 * handle the cases of percent (%) or underscore (_) for use in LIKE clauses.<
/p> | |
483 * | |
484 * see http://www.jguru.com/faq/view.jsp?EID=8881 | |
485 * | |
486 * @param str the string to escape, may be null | |
487 * @return a new String, escaped for SQL, <code>null</code> if null string inp
ut | |
488 */ | |
489 public static String escapeSql(String str) | |
490 { | |
491 if (str == null) | |
492 { | |
493 return null; | |
494 } | |
495 return StringUtils.replace(str, "'", "''"); | |
496 } | |
497 | |
498 //----------------------------------------------------------------------- | |
499 | |
500 /** | |
501 * <p>Returns a <code>String</code> value for a CSV column enclosed in double
quotes, | |
502 * if required.</p> | |
503 * | |
504 * <p>If the value contains a comma, newline or double quote, then the | |
505 * String value is returned enclosed in double quotes.</p> | |
506 * </p> | |
507 * | |
508 * <p>Any double quote characters in the value are escaped with another double
quote.</p> | |
509 * | |
510 * <p>If the value does not contain a comma, newline or double quote, then the | |
511 * String value is returned unchanged.</p> | |
512 * </p> | |
513 * | |
514 * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia
</a> and | |
515 * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>. | |
516 * | |
517 * @param str the input CSV column String, may be null | |
518 * @return the input String, enclosed in double quotes if the value contains a
comma, | |
519 * newline or double quote, <code>null</code> if null string input | |
520 * @since 2.4 | |
521 */ | |
522 public static String escapeCsv(String str) | |
523 { | |
524 if (StringUtils.containsNone(str, CSV_SEARCH_CHARS)) | |
525 { | |
526 return str; | |
527 } | |
528 try | |
529 { | |
530 StringWriter writer = new StringWriter(); | |
531 escapeCsv(writer, str); | |
532 return writer.toString(); | |
533 } catch (IOException ioe) | |
534 { | |
535 // this should never ever happen while writing to a StringWriter | |
536 ioe.printStackTrace(); | |
537 return null; | |
538 } | |
539 } | |
540 | |
541 /** | |
542 * <p>Writes a <code>String</code> value for a CSV column enclosed in double q
uotes, | |
543 * if required.</p> | |
544 * | |
545 * <p>If the value contains a comma, newline or double quote, then the | |
546 * String value is written enclosed in double quotes.</p> | |
547 * </p> | |
548 * | |
549 * <p>Any double quote characters in the value are escaped with another double
quote.</p> | |
550 * | |
551 * <p>If the value does not contain a comma, newline or double quote, then the | |
552 * String value is written unchanged (null values are ignored).</p> | |
553 * </p> | |
554 * | |
555 * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia
</a> and | |
556 * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>. | |
557 * | |
558 * @param str the input CSV column String, may be null | |
559 * @param out Writer to write input string to, enclosed in double quotes if it
contains | |
560 * a comma, newline or double quote | |
561 * @throws IOException if error occurs on underlying Writer | |
562 * @since 2.4 | |
563 */ | |
564 public static void escapeCsv(Writer out, String str) throws IOException | |
565 { | |
566 if (StringUtils.containsNone(str, CSV_SEARCH_CHARS)) | |
567 { | |
568 if (str != null) | |
569 { | |
570 out.write(str); | |
571 } | |
572 return; | |
573 } | |
574 out.write(CSV_QUOTE); | |
575 for (int i = 0; i < str.length(); i++) | |
576 { | |
577 char c = str.charAt(i); | |
578 if (c == CSV_QUOTE) | |
579 { | |
580 out.write(CSV_QUOTE); // escape double quote | |
581 } | |
582 out.write(c); | |
583 } | |
584 out.write(CSV_QUOTE); | |
585 } | |
586 | |
587 /** | |
588 * <p>Returns a <code>String</code> value for an unescaped CSV column. </p> | |
589 * | |
590 * <p>If the value is enclosed in double quotes, and contains a comma, newline | |
591 * or double quote, then quotes are removed. | |
592 * </p> | |
593 * | |
594 * <p>Any double quote escaped characters (a pair of double quotes) are unesca
ped | |
595 * to just one double quote. </p> | |
596 * | |
597 * <p>If the value is not enclosed in double quotes, or is and does not contai
n a | |
598 * comma, newline or double quote, then the String value is returned unchanged
.</p> | |
599 * </p> | |
600 * | |
601 * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia
</a> and | |
602 * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>. | |
603 * | |
604 * @param str the input CSV column String, may be null | |
605 * @return the input String, with enclosing double quotes removed and embedded
double | |
606 * quotes unescaped, <code>null</code> if null string input | |
607 * @since 2.4 | |
608 */ | |
609 public static String unescapeCsv(String str) | |
610 { | |
611 if (str == null) | |
612 { | |
613 return null; | |
614 } | |
615 try | |
616 { | |
617 StringWriter writer = new StringWriter(); | |
618 unescapeCsv(writer, str); | |
619 return writer.toString(); | |
620 } catch (IOException ioe) | |
621 { | |
622 // this should never ever happen while writing to a StringWriter | |
623 ioe.printStackTrace(); | |
624 return null; | |
625 } | |
626 } | |
627 | |
628 /** | |
629 * <p>Returns a <code>String</code> value for an unescaped CSV column. </p> | |
630 * | |
631 * <p>If the value is enclosed in double quotes, and contains a comma, newline | |
632 * or double quote, then quotes are removed. | |
633 * </p> | |
634 * | |
635 * <p>Any double quote escaped characters (a pair of double quotes) are unesca
ped | |
636 * to just one double quote. </p> | |
637 * | |
638 * <p>If the value is not enclosed in double quotes, or is and does not contai
n a | |
639 * comma, newline or double quote, then the String value is returned unchanged
.</p> | |
640 * </p> | |
641 * | |
642 * see <a href="http://en.wikipedia.org/wiki/Comma-separated_values">Wikipedia
</a> and | |
643 * <a href="http://tools.ietf.org/html/rfc4180">RFC 4180</a>. | |
644 * | |
645 * @param str the input CSV column String, may be null | |
646 * @param out Writer to write the input String to, with enclosing double quote
s | |
647 * removed and embedded double quotes unescaped, <code>null</code> if null str
ing input | |
648 * @throws IOException if error occurs on underlying Writer | |
649 * @since 2.4 | |
650 */ | |
651 public static void unescapeCsv(Writer out, String str) throws IOException | |
652 { | |
653 if (str == null) | |
654 { | |
655 return; | |
656 } | |
657 if (str.length() < 2) | |
658 { | |
659 out.write(str); | |
660 return; | |
661 } | |
662 if (str.charAt(0) != CSV_QUOTE || str.charAt(str.length() - 1) != CSV_QUOTE) | |
663 { | |
664 out.write(str); | |
665 return; | |
666 } | |
667 | |
668 // strip quotes | |
669 String quoteless = str.substring(1, str.length() - 1); | |
670 | |
671 if (StringUtils.containsAny(quoteless, CSV_SEARCH_CHARS)) | |
672 { | |
673 // deal with escaped quotes; ie) "" | |
674 str = StringUtils.replace(quoteless, CSV_QUOTE_STR + CSV_QUOTE_STR, CSV_QU
OTE_STR); | |
675 } | |
676 | |
677 out.write(str); | |
678 } | |
679 | |
680 } | |
OLD | NEW |