unbescape-unbescape-1.1.5.RELEASE/000077500000000000000000000000001311410233600164775ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/.gitattributes000066400000000000000000000015171311410233600213760ustar00rootroot00000000000000# Auto detect text files and perform LF normalization * text=auto *.java text diff=java *.properties text *.js text *.css text *.less text *.html text diff=html *.jsp text diff=html *.jspx text diff=html *.tag text diff=html *.tagx text diff=html *.tld text *.xml text *.gradle text *.sql text *.xsd text *.dtd text *.mod text *.ent text *.txt text *.md text *.markdown text *.thtest text *.thindex text *.common text *.odt binary *.pdf binary *.sh text eol=lf *.bat text eol=crlf *.ico binary *.png binary *.svg binary *.woff binary *.rar binary *.zargo binary *.zip binary CNAME text *.MF text unbescape-unbescape-1.1.5.RELEASE/.gitignore000066400000000000000000000000721311410233600204660ustar00rootroot00000000000000.classpath .project target/ bin/ .settings/ .idea/ *.iml unbescape-unbescape-1.1.5.RELEASE/BUILD.txt000066400000000000000000000013651311410233600201040ustar00rootroot00000000000000 Building unbescape ------------------ To build unbescape you will need Maven 2. You can get it at: http://maven.apache.org Build and install the project executing, from the unbescape project root folder: mvn clean:clean install And you will get a fresh target/unbescape-{version}.jar file. You will also get it installed in your local repository at: $M2_REPO/org/unbescape/unbescape/{version}/unbescape-{version}.jar Generating Javadoc for unbescape -------------------------------- If you wish to generate the javadoc for unbescape, execute this from the unbescape root folder: mvn javadoc:javadoc This will generate the javadoc documentation in HTML format in: target/site/apidocs unbescape-unbescape-1.1.5.RELEASE/CONTRIBUTING.markdown000066400000000000000000000342331311410233600221570ustar00rootroot00000000000000Contributing to Unbescape: Terms and Conditions =============================================== ------------------------------------------------------------------------------ Do you want to contribute your work to Unbescape? Well, then first and most important: **THANK YOU!** Now, in order to accept your contribution, there are some terms you must expressly agree with, so please read them carefully. They might look a bit cumbersome, but they are here just in order to protect you, your contribution, and especially the project's future. **Important**: submitting any contributions to the Unbescape project implies your **full acceptance of these terms**, including the *"Unbescape Individual Contributor License Agreement"* detailed at the end. Who can contribute? ------------------- Anyone, with the unique condition that he/she must be a **private individual**, acting in his/her own name, and not being endorsed in their contributed work by any company or government. Note that this condition will not only refer to the ownership of the effort invested in contributing to the project, but also to the fact that *no private or public company will be mentioned as a a part of your contribution on the project's website or code*, including but not limited to web/email addresses or package names. What is the first step to be taken? ----------------------------------- First of all, **talk to the [project members](http://www.unbescape.org/team.html)** (an email should do) about your ideas: new features, fixes, documentation... whatever you would like to contribute to the project. Let we discuss the possibilities with you so that we make sure your contribution goes in the right direction and aligns with the project's standards, intentions and roadmap. How will your relation with the Unbescape project be? ----------------------------------------------------- Your contributions will have the form of GitHub *pull requests*. Note that contributors do not have read+write (or *pull+push*) access to the project repositories, only project *members* do. Also, please understand that *not all pull requests will be accepted and merged into the project's repositories*. Talking about your planned contributions with the project members before creating pull requests will maximize the possibilities of your contributions being accepted. Once your contribution is approved, you will be listed as a *contributor* at the [Unbescape Team page](http://www.unbescape.org/team.html). You can opt-out of this if you want. Also, you will be `@author` for any new Java classes that you write and also co-`@author` to any existing classes to which you make significant changes. You can also opt-out of this if you want. About the code you contribute ----------------------------- ### General guidelines: - Obviously, **your code must both compile and work correctly**. Also, the addition of any new patches to the codebase should not render it unstable in any way. - All your code should be easy to read and understand by a human. - There should be no compilation warnings at all. ### Detailed Java code quality standards: - All your code should compile and run in **Java 5.0**. - All comments, names of classes and variables, log messages, etc. must be **in English**. - All `.java` files must include the standard Unbescape copyright header. - All your code should follow the Java Code Conventions regarding variable/method/class naming. - Maximum line size is 120 characters. - Indentation should be made with 4 spaces, not tabs. - All .java source files should be pure ASCII. All .properties files should be ISO-8859-1. - Number autoboxing and/or autounboxing is forbidden. - Every class should define a constructor, even if it is the default one, and include a call to `super()`. - Every non-nullable argument in a public method should be first validated with a `Validate.notNull(...)` call. - All method arguments should include the `final` modifier, so that their value is never changed. - Include `/* ... */` comments for every algorithm you develop with a minimum of complexity. *"Minimum of complexity"* usually means you had to take some design decisions in order to write it the way you did. Do not write obvious comments. - All public methods and classes directly available to users (i.e. public) should have comprehensive javadoc. ### Detailed HTML/XML code quality standards: - All tags, CSS styles, file names, etc. must be **in English**. - Lower case should be prefered for HTML/XML artifacts. The only exceptions are `DOCTYPE` and `CDATA` clauses. - All HTML code should be XML-valid (i.e. all tags should be closed, attributes surrounded by commas, etc.) - Maximum line size is 120 characters. - Indentation should be made with 4 spaces, not tabs. - Line feeds should be UNIX-like (`\n`). - All .html and .xml source files should be pure ASCII, even if _content-type_ is set to a different encoding. - All XHTML self-closing (minimized) tags should have a space before `/>` (the XHTML standards say so!). - All inline scripts must be enclosed inside a commented `` block. About the documentation/articles you contribute ----------------------------------------------- Note the following only applies to documentation/articles meant to be published at the Unbescape website. - All documentation artifacts, including articles, must be written **in correct English**. - Your name and email will be displayed as *"author"* of any documentation artifacts you create. - Topic and text structure must be first discussed and agreed upon with the project members. - Project members may edit and make small changes to your texts --of which you will be informed-- before publishing them. - Format and visual styles must adhere to the Unbescape website standards, of which you will be informed by the project members. Pay special attention to this ----------------------------- All Unbescape software is distributed under the **Apache License 2.0** open source license, and your contributions will be licensed in the same way. If you work for a company which, by the way or place in which your code was written, by your contract terms or by the laws in your country, could claim any rights (including but not limited to intellectual or industrial property) over your contributed code, you will have to send the project members (either by email from your authorised superiors or by signed fax), a statement indicating that your company agrees with the terms explained in this page, and that it both authorises your contribution to Unbescape and states that will never claim any kind of rights over it. Unbescape Individual Contributor License Agreement --------------------------------------------------- This contributor agreement ("Agreement") documents the rights granted by contributors to the Unbescape Project. This is a legally binding document, so please read it carefully before agreeing to it. The Agreement may cover more than one software project managed by Unbescape. ###1. Definitions * _"Unbescape"_ means the "Unbescape Project organization and members". * _"You"_ means the individual who submits a Contribution to Unbescape. * _"Contribution"_ means any work of authorship that is submitted by you to Unbescape in which you own or assert ownership of the Copyright. * _"Copyright"_ means all rights protecting works of authorship owned or controlled by you, including copyright, moral and neighboring rights, as appropriate, for the full term of their existence including any extensions by you. * _"Material"_ means the work of authorship which is made available by Unbescape to third parties. When this Agreement covers more than one software project, the Material means the work of authorship to which the Contribution was submitted. After you submit the Contribution, it may be included in the Material. * _"Submit"_ means any form of electronic, verbal, or written communication sent to Unbescape or its representatives, including but not limited to electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, Unbescape for the purpose of discussing and improving the Material, but excluding communication that is conspicuously marked or otherwise designated in writing by you as _"Not a Contribution." * _"Submission Date"_ means the date on which you submit a Contribution to Unbescape. * _"Effective Date"_ means the date you execute this agreement or the date You first submit a Contribution to Unbescape, whichever is earlier. ###2. Grant of Rights ####2.1. Copyright License * (a) You retain ownership of the copyright in your Contribution and have the same rights to use or license the Contribution which you would have had without entering into the agreement. * (b) To the maximum extent permitted by the relevant law, you grant to Unbescape a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable license under the copyright covering the Contribution, with the right to sublicense such rights through multiple tiers of sublicensees, to reproduce, modify, display, perform and distribute the Contribution as part of the Material; provided that this license is conditioned upon compliance with Section 2.3. ####2.2 Patent License For patent claims including, without limitation, method, process, and apparatus claims which you own, control or have the right to grant, now or in the future, you grant to Unbescape a perpetual, worldwide, non-exclusive, transferable, royalty-free, irrevocable patent license, with the right to sublicense these rights to multiple tiers of sublicensees, to make, have made, use, sell, offer for sale, import and otherwise transfer the Contribution and the Contribution in combination with the Material (and portions of such combination). This license is granted only to the extent that the exercise of the licensed rights infringes such patent claims; and provided that this license is conditioned upon compliance with Section 2.3. ####2.3 Outbound License As a condition on the grant of rights in Sections 2.1 and 2.2, Unbescape agrees to license the Contribution only under the terms of the Apache License 2.0 (including any right to adopt any future version of this license if permitted). ####2.4 Moral Rights If moral rights apply to the Contribution, to the maximum extent permitted by law, you waive and agree not to assert such moral rights against Unbescape or its successors in interest, or any of our licensees, either direct or indirect. ####2.5 Unbescape Rights You acknowledge that Unbescape is not obligated to use your Contribution as part of the Material and may decide to include any Contributions Unbescape considers appropriate. ####2.6 Reservation of Rights Any rights not expressly assigned or licensed under this section are expressly reserved by you. ###3. Agreement You confirm that: * (a) You have the legal authority to enter into this Agreement. * (b) You own the Copyright and patent claims covering the Contribution which are required to grant the rights under Section 2. * (c) The grant of rights under Section 2 does not violate any grant of rights which you have made to third parties, including your employer. If you are an employee, you have had your employer approve this Agreement. If you are less than eighteen years old, please have your parents or guardian sign the Agreement. ###4. Disclaimer EXCEPT FOR THE EXPRESS WARRANTIES IN SECTION 3, THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY DISCLAIMED BY YOU TO UNBESCAPE AND BY UNBESCAPE TO YOU. TO THE EXTENT THAT ANY SUCH WARRANTIES CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION TO THE MINIMUM PERIOD PERMITTED BY LAW. ###5. Consequential Damage Waiver TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU OR UNBESCAPE BE LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA, INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR OTHERWISE) UPON WHICH THE CLAIM IS BASED. ###6. Miscellaneous * 6.1 This Agreement will be governed by and construed in accordance with the laws of Spain excluding its conflicts of law provisions. Under certain circumstances, the governing law in this section might be superseded by the United Nations Convention on Contracts for the International Sale of Goods ("UN Convention") and the parties intend to avoid the application of the UN Convention to this Agreement and, thus, exclude the application of the UN Convention in its entirety to this Agreement. * 6.2 This Agreement sets out the entire agreement between you and Unbescape for your Contributions to Unbescape and overrides all other agreements or understandings. * 6.3 If You or Unbescape assign the rights or obligations received through this Agreement to a third party, as a condition of the assignment, that third party must agree in writing to abide by all the rights and obligations in the Agreement. * 6.4 The failure of either party to require performance by the other party of any provision of this Agreement in one situation shall not affect the right of a party to require such performance at any time in the future. A waiver of performance under a provision in one situation shall not be considered a waiver of the performance of the provision in the future or a waiver of the provision in its entirety. * 6.5 If any provision of this Agreement is found void and unenforceable, such provision will be replaced to the extent possible with a provision that comes closest to the meaning of the original provision and which is enforceable. The terms and conditions set forth in this Agreement shall apply notwithstanding any failure of essential purpose of this Agreement or any limited remedy to the maximum extent possible under law. unbescape-unbescape-1.1.5.RELEASE/ChangeLog.txt000066400000000000000000000034611311410233600210730ustar00rootroot000000000000001.1.5.RELEASE ============= - Fixed unescaping of some HTML5 NCRs (Named Character References) which are allowed to be specified without a semicolon-char suffix (e.g. " "). - Added to XmlEscape specific methods for performing escape operations on XML attribute values. These methods will always perform the escaping of the \t, \n and \r characters to avoid a possible loss of information when the XML document is read by a parser, as according to the XML spec at https://www.w3.org/TR/REC-xml/#AVNormalize all these three characters would be normalised to white-space. 1.1.4.RELEASE ============= - Added ampersand (&) to the list of characters to be escaped in LEVEL 1 for JSON, JavaScript and CSS literals in order to make escaped code safe against code injection attacks in XHTML scenarios (browsers using XHTML processing mode) performed by means of including XHTML escape codes in literals. 1.1.3.RELEASE ============= - Improved performance of String-based unescape methods for HTML, XML, JS, JSON and others when the text to be unescaped actually needs no unescaping. 1.1.2.RELEASE ============= - Added support for stream-based (String-to-Writer and Reader-to-Writer) escape and unescape operations. 1.1.1.RELEASE ============= - Fixed HTML unescape for codepoints > U+10FFFF (was throwing IllegalArgumentException). - Fixed HTML unescape for codepoints > Integer.MAX_VALUE (was throwing ArrayIndexOutOfBounds). - Simplified and improved performance of codepoint-computing code by using Character.codePointAt(...) instead of a complex conditional structure based on Character.isHighSurrogate(...) and Character.isLowSurrogate(...). - [doc] Fixed description of MSExcel-compatible CSV files. 1.1.0.RELEASE ============= - Added URI/URL escape and unescape operations. 1.0 === - First release of unbescape. unbescape-unbescape-1.1.5.RELEASE/LICENSE.txt000066400000000000000000000261361311410233600203320ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. unbescape-unbescape-1.1.5.RELEASE/NOTICE.txt000077500000000000000000000011621311410233600202240ustar00rootroot00000000000000 Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. unbescape-unbescape-1.1.5.RELEASE/README.markdown000066400000000000000000000366471311410233600212200ustar00rootroot00000000000000 Unbescape: escape and unescape operations in Java ================================================= ------------------------------------------------------------------------------ _Unbescape_ is a Java library aimed at performing fully-featured and high-performance escape and unescape operations for: * **HTML** (HTML5 and HTML 4) * **XML** (XML 1.0 and XML 1.1) * **JavaScript** * **JSON** * **URI**/**URL** * **CSS** * **CSV** (Comma-Separated Values) * **Java literals** * **Java `.properties` files** Status ------ This project is stable and production-ready. Current versions: * Version **1.1.4.RELEASE** (27 Sep 2016) License ------- This software is licensed under the [Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). Requirements ------------ * Java SE 5.0 or higher Maven info ---------- * groupId: `org.unbescape` * artifactId: `unbescape` * version: (see _Current Versions_ above) Features -------- * **High performance** * No unneeded `String` or `char[]` objects are created, and specific optimizations are applied in order to provide maximum performance and reduce Garbage Collector latency (e.g. if a `String` has the same content after escaping/unescaping, exactly the same `String` object is returned, no copy is made). * See (and execute) the [`benchmark.sh`](https://github.com/unbescape/unbescape-tests/blob/20140429/benchmark.sh) script in the [`unbescape-tests`](https://github.com/unbescape/unbescape-tests) repository for specific figures. * **Highly configurable** * Most escaped languages allow specifying the _type_ of escape to be performed: based on literals, on decimal numbers, hexadecimal, octal, etc. * Most escaped languages allow specifying the _level_ of escape to be performed: only escape the _basic set_, escape _all non-ASCII characters_, escape _all non-alphanumeric_, etc. * Provides sensible defaults and pre-configured, easy-to-use methods. * **Documented API** * Includes full JavaDoc API documentation for all public classes, explaining each escape and unescape operation in detail. * **Unicode** * All escape and unescape operations support the whole Unicode character set: `U+0000` to `U+10FFFF`, including characters not representable by only one char in Java (>`U+FFFF`). * **HTML Escape/Unescape** * Whole **HTML5** NCR (Named Character Reference) set supported, if required: `]`,` `, etc. (HTML 4 set available too). * Mixed named and numerical (decimal or hexa) character references supported. * Ability to default to numerical (decimal or hexa) references when an applicable NCR does not exist (depending on the selected operation level). * Support for unescape of double-char NCRs in HTML5: `fj` → `fj`. * Support for a set of HTML5 unescape tweaks included in the HTML5 specification: * Unescape of numerical character references not ending in semi-colon (e.g. `⎬`). * Unescape of specific NCRs not ending in semi-colon (e.g. `á`). * Unescape of specific numerical character references wrongly specified by their Windows-1252 codepage code instead of the Unicode one (e.g. `€` for `€` (`€`) instead of `€`). * **XML Escape/Unescape** * Support for both XML 1.0 and XML 1.1 escape/unescape operations. * No support for DTD-defined or user-defined entities. Only the five predefined XML character entities are supported: `<`, `>`, `&`, `"` and `'`. * Automatic escaping of allowed control characters. * **JavaScript Escape/Unescape** * Support for the JavaScript basic escape set: `\0`, `\b`, `\t`, `\n`, `\v`, `\f`, `\r`, `\"`, `\'`, `\\`. Note that `\v` (`U+000B`) will not be used in escape operations (only unescape) because it is not supported by Microsoft Internet Explorer versions < 9. * Automatic escape of `/` (as `\/` if possible) when it appears after `<`, as in ``. * Support for escaping non-displayable, control characters: `U+0001` to `U+001F` and `U+007F` to `U+009F`. * Support for X-based hexadecimal escapes (a.k.a. _hexadecimal escapes_) both in escape and unescape operations: `\xE1`. * Support for U-based hexadecimal escapes (a.k.a. _unicode escapes_) both in escape and unescape operations: `\u00E1`. * Support for Octal escapes, though only in unescape operations: `\071`. Not supported in escape operations (octal escapes were deprecated in version 5 of the ECMAScript specification). * **JSON Escape/Unescape** * Support for the JSON basic escape set: `\b`, `\t`, `\n`, `\f`, `\r`, `\"`, `\\`. * Automatic escape of `/` (as `\/` if possible) when it appears after `<`, as in ``. * Support for escaping non-displayable, control characters: `U+0000` to `U+001F` and `U+007F` to `U+009F`. * Support for U-based hexadecimal escapes (a.k.a. _unicode escapes_) both in escape and unescape operations: `\u00E1`. * **URI/URL Escape/Unescape** * Support for escape operations using percent-encoding (`%HH`). * Escape URI paths, path fragments, query parameters and fragment identifiers. * **CSS Escape/Unescape** * Complete set of CSS _Backslash Escapes_ supported (e.g. `\+`, `\;`, `\(`, `\)`, etc.). * Full set of escape syntax rules supported, both for **CSS identifiers** and **CSS Strings** (or _literals_). * Non-standard tweaks supported: `\:` not used because of lacking support in Internet Explorer < 8, `\_` escaped at the beginning of identifiers for better Internet Explorer 6 support, etc. * Hexadecimal escapes (a.k.a. _unicode escapes_) are supported both in escape and unescape operations, and both in _compact_ (`\E1 `) and six-digit forms (`\0000E1`). * Support for unescaping unicode characters >`\uFFFF` both when represented in standard form (one char, `\20000`) and non-standard (surrogate pair, `\D840\DC00`, used by older WebKit browsers). * **CSV (Comma-Separated Values) Escape/Unescape** * Works according to the rules specified in RFC4180 (there is no _CSV standard_ as such). * Encloses escaped values in double-quotes (`"value"`) if they contain any non-alphanumeric characters. * Escapes double-quote characters (`"`) by writing them twice: `""`. * Honors rules for maximum compatibility with Microsoft Excel. * **Java Literal Escape/Unescape** * Support for the Java basic escape set: `\b`, `\t`, `\n`, `\f`, `\r`, `\"`, `\'`, `\\`. Note `\'` will not be used in escaping levels < 3 (= _all but alphanumeric_) because escaping the apostrophe is not really required in Java String literals (only in Character literals). * Support for escaping non-displayable, control characters: `U+0001` to `U+001F` and `U+007F` to `U+009F`. * Support for U-based hexadecimal escapes (a.k.a. _unicode escapes_) both in escape and unescape operations: `\u00E1`. * Support for Octal escapes, though only in unescape operations: `\071`. Not supported in escape operations (use of octal escapes is not recommended by the Java Language Specification). * **Java `.properties` File Escape/Unescape** * Support for the Java Properties basic escape set: `\t`, `\n`, `\f`, `\r`, `\\`. When escaping `.properties` keys (not values) `\ `, `\:` and `\=` will be applied too. * Support for escaping non-displayable, control characters: `U+0001` to `U+001F` and `U+007F` to `U+009F`. * Support for U-based hexadecimal escapes (a.k.a. _unicode escapes_) both in escape and unescape operations: `\u00E1`. ------------------------------------------------------------------------------ HTML Escape/Unescape ------------------------- HTML escape and unescape operations are performed by means of the `org.unbescape.html.HtmlEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). There are simple, preconfigured methods: ```java final String escaped = HtmlEscape.escapeHtml5(text); final String unescaped = HtmlEscape.unescapeHtml(escaped); ``` And also those that allow a more fine-grained configuration of the escape operation: ```java final String result = HtmlEscape.escapeHtml( text, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); ``` XML Escape/Unescape ------------------------- XML escape and unescape operations are performed by means of the `org.unbescape.xml.XmlEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). There are simple, preconfigured methods: ```java final String escaped = XmlEscape.escapeXml11(text); final String unescaped = XmlEscape.unescapeXml(escaped); ``` And also those that allow a more fine-grained configuration of the escape operation: ```java final String result = XmlEscape.escapeXml11( text, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_DECIMAL, XmlEscapeLevel.LEVEL_3_ALL_NON_ALPHANUMERIC); ``` JavaScript Escape/Unescape -------------------------- JavaScript escape and unescape operations are performed by means of the `org.unbescape.javascript.JavaScriptEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). There are simple, preconfigured methods: ```java final String escaped = JavaScriptEscape.escapeJavaScript(text); final String unescaped = JavaScriptEscape.unescapeJavaScript(escaped); ``` And also those that allow a more fine-grained configuration of the escape operation: ```java final String result = JavaScriptEscape.escapeJavaScript( text, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); ``` JSON Escape/Unescape -------------------- JSON escape and unescape operations are performed by means of the `org.unbescape.json.JsonEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). There are simple, preconfigured methods: ```java final String escaped = JsonEscape.escapeJson(text); final String unescaped = JsonEscape.unescapeJson(escaped); ``` And also those that allow a more fine-grained configuration of the escape operation: ```java final String result = JsonEscape.escapeJson( text, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO__UHEXA, JsonEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); ``` URI/URL Escape/Unescape ----------------------- URI/URL escape and unescape operations are performed by means of the `org.unbescape.uri.UriEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). The methods for this type of escape/unescape operations are very simple: ```java final String escapedPath = UriEscape.escapeUriPath(text); final String escapedPathSegment = UriEscape.escapeUriPathSegment(text); final String escapedQueryParam = UriEscape.escapeUriQueryParam(text); final String escapedFragmentId = UriEscape.escapeUriFragmentId(text); ``` ```java final String unescapedPath = UriEscape.unescapeUriPath(text); final String unescapedPathSegment = UriEscape.unescapeUriPathSegment(text); final String unescapedQueryParam = UriEscape.unescapeUriQueryParam(text); final String unescapedFragmentId = UriEscape.unescapeUriFragmentId(text); ``` CSS Escape/Unescape -------------------- CSS escape and unescape operations are performed by means of the `org.unbescape.css.CssEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). Unbescape includes support for escaping both **CSS identifiers** and **CSS strings** (the former type apply more strict syntax rules). There are simple, preconfigured methods: ```java final String escapedIdentifier = CssEscape.escapeCssIdentifier(text); final String escapedString = CssEscape.escapeCssString(text); final String unescaped = CssEscape.unescapeCss(escapedIdentifierOrString); ``` And also those that allow a more fine-grained configuration of the escape operation: ```java final String identifierResult = CssEscape.escapeCssIdentifier( identifierText, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_SIX_DIGIT_HEXA, CssIdentifierEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); final String stringResult = CssEscape.escapeCssString( stringText, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); ``` CSV Escape/Unescape ------------------- CSV (Comma-Separated Values) escape and unescape operations are performed by means of the `org.unbescape.csv.CsvEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). The methods for this type of escape/unescape operations are very simple: ```java final String escaped = CsvEscape.escapeCsv(text); final String unescaped = CsvEscape.unescapeCsv(escaped); ``` Java Literal Escape/Unescape ---------------------------- Java escape and unescape operations are performed by means of the `org.unbescape.java.JavaEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). There are simple, preconfigured methods: ```java final String escaped = JavaEscape.escapeJava(text); final String unescaped = JavaEscape.unescapeJava(escaped); ``` And also those that allow a more fine-grained configuration of the escape operation: ```java final String result = JavaEscape.escapeJava( text, JavaEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); ``` Java `.properties` File Escape/Unescape --------------------------------------- Java `.properties` escape and unescape operations are performed by means of the `org.unbescape.properties.PropertiesEscape` class. This class defines a series of static methods that perform the desired operations (see the class _javadoc_ for more info). Unbescape includes support for escaping both **properties keys** and **properties values** (keys require additional escaping of ` `, `:` and `=`). There are simple, preconfigured methods: ```java final String escapedKey = PropertiesEscape.escapePropertiesKey(text); final String escapedString = PropertiesEscape.escapePropertiesValue(text); final String unescaped = PropertiesEscape.unescapeProperties(escapedKeyOrValue); ``` And also those that allow a more fine-grained configuration of the escape operation: ```java final String identifierResult = PropertiesEscape.escapePropertiesKey( keyText, PropertiesKeyEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); final String stringResult = PropertiesEscape.escapePropertiesValue( valueText, PropertiesValueEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); ``` unbescape-unbescape-1.1.5.RELEASE/RELEASING.txt000066400000000000000000000023061311410233600205520ustar00rootroot00000000000000In order to prepare a release, this steps have to be taken: 1. In settings.xml, these entries must exist: releases [KEYNAME (EMAIL)] [GPG PASSPHRASE] sonatype-nexus-snapshots [USER IN SONATYPE NEXUS] [PASSWORD IN SONATYPE NEXUS] 2. Ensure all SVN URLs in pom.xml are using "https". A "502 Bad Gateway" error will be received if not. 3. Deploy SNAPSHOT artifact to Sonatype NEXUS with "mvn deploy", and check in Nexus web interface. 4. Execute a test "no modification" run of the release:prepare goal: "mvn -Preleases release:prepare -DdryRun=true -Dusername=[SVNUSER] -Dpassword=[SVNPASS]" 5. Execute a real run of the release:prepare goal: "mvn -Preleases release:prepare -Dusername=[SVNUSER] -Dpassword=[SVNPASS]" 6. Upload the release: "mvn -Preleases release:perform -Dusername=[SVNUSER] -Dpassword=[SVNPASS]" 7. Follow instructions for Nexus at: http://nexus.sonatype.org/oss-repository-hosting.html unbescape-unbescape-1.1.5.RELEASE/USAGE.txt000066400000000000000000000011471311410233600201070ustar00rootroot00000000000000 Using unbescape from Maven 2 ---------------------------- To use it in your Maven 2 applications, you will need to add it as a dependency with: org.unbescape unbescape {version} compile In order for this to work correctly, you need to have previously installed thymeleaf in your local repository (as explained in BUILD.txt) or have a working internet connection to let maven automatically download thymeleaf binaries from Maven 2's central repositories. unbescape-unbescape-1.1.5.RELEASE/pom.xml000077500000000000000000000224401311410233600200210ustar00rootroot00000000000000 4.0.0 org.unbescape unbescape jar 1.1.5.RELEASE unbescape http://www.unbescape.org Advanced yet easy-to-use escape/unescape library for Java The Apache Software License, Version 2.0 http://www.apache.org/licenses/LICENSE-2.0.txt repo The UNBESCAPE team http://www.unbescape.org scm:git:git@github.com:unbescape/unbescape.git scm:git:git@github.com:unbescape/unbescape.git scm:git:git@github.com:unbescape/unbescape.git unbescape-1.1.5.RELEASE danielfernandez Daniel Fernandez daniel.fernandez AT 11thlabs DOT org Project Admin Lead Developer sonatype-nexus-snapshots Sonatype Nexus Snapshots https://oss.sonatype.org/content/repositories/snapshots sonatype-nexus-snapshots Sonatype Nexus Snapshots https://oss.sonatype.org/service/local/staging/deploy/maven2 sonatype-nexus-snapshots Sonatype Nexus Snapshots https://oss.sonatype.org/content/repositories/snapshots true 1.5 1.5 src/main/resources . META-INF LICENSE.txt NOTICE.txt src/test/resources org.apache.maven.plugins maven-compiler-plugin 3.3 ${maven.compile.source} ${maven.compile.target} US-ASCII org.apache.maven.plugins maven-resources-plugin 2.7 US-ASCII org.apache.maven.plugins maven-javadoc-plugin 2.10.3 protected java.lang ${basedir}/src/main/javadoc/overview.html ${basedir}/src/main/javadoc ${project.reporting.outputDirectory}/api/${project.artifactId}/apidocs package jar org.apache.maven.plugins maven-source-plugin 2.4 package jar org.apache.felix maven-bundle-plugin 2.4.0 bundle-manifest process-classes manifest org.apache.maven.plugins maven-jar-plugin 2.6 ${project.build.outputDirectory}/META-INF/MANIFEST.MF false true true ${maven.compile.source} ${maven.compile.target} org.apache.maven.plugins maven-gpg-plugin 1.6 sign-artifacts verify sign org.apache.maven.plugins maven-release-plugin 2.5.3 org.apache.maven.plugins maven-assembly-plugin 2.6 src/assembly/dist.xml make-assembly-deps package single org.apache.maven.plugins maven-site-plugin 3.4 org.apache.maven.plugins maven-project-info-reports-plugin 2.2 license unbescape-unbescape-1.1.5.RELEASE/src/000077500000000000000000000000001311410233600172665ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/artwork/000077500000000000000000000000001311410233600207575ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/artwork/unbescape.png000066400000000000000000003011571311410233600234410ustar00rootroot00000000000000PNG  IHDR fXsBIT|d pHYsvvY'tEXtSoftwarewww.inkscape.org< IDATx{uayf&$%@ (QTxzA]/v Emk][Vez9k]uT=gǻU)^@*V "X@2?䖐<37z3$?Ϸ4MO>ƽ_G'Ydb=|WV$\뺦i&,reYdsm;ژ$@m|/wZ&ro6]k@M'<,I./\\J)5Y$%9o^o ,DIivM5*,O$O 'iSszbg2g7%9iksfR̞ߏ4sq\\rhOEqDOmnaV)ey'4k)6O502I3c|po40 J)%eI4k \AuQx=A9/{(M"$Y_ `nL&9iOBJ)\dḻli\7_.$( 膵I޳YYI^Y^`>=mԌif$ `2əM|f&<025IC`{㛦E_( uJĬRʉILҟ dG6M6ĬRJIriDYOrvjZYI^Ԗ0N͞vjJ4RV%6ɚMI66Mst~͉YQ0ɞjZubV)$Hҟ.6䄦iuYE,li'fRMrmY7dc4{ΉYF,iUJ92nPەئiĬ "ik'fROr]0v&Y4͍:1eii'fRzI~djۓ4}a'fQ˞~f7w[:cUi(eY$Q$jf=΍( Z{o+Z4)eu(a;ڦin=1eHWt0jJ4wI"!wC4/O*l( `_m#Jrf1]aYt/4MJ)%O `ݜAM4w9,:{Zfm3%wY+芍0 a@K$'ّd+ɲ^eLh=: i(hgc/ѵWtѽ$+k萕$WtȄ0 ^WtJ'f3!hGDI;I,I+W{@Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K,Y- Zf$hIВ0 %a@K#wȚ^6om\Ī%˒ɍOGߟ~|vמ $M@~c?O{ȉ)Y4ɿ?|0 \7Y~dˏ8s7ߒy2?O"^e%Ƀ̧a̱Jzߎ{˗=a̡]U唑l8ν2a̡],>cSή{Hsy+՞~E0h,^X!h<2;á_{ɒ3$KK~plX(Y0`#ɋ/XV{ƽ_{";Kfpn0 `Rriho 1`NXoө֭V yi=a>db1.f,(9 fXYjOXPY0 3%Wh`f<yZ].sj`OU9dpPΆ[r3`zqO˯<[~Dۛ|;7/#ť0 fi ՞q@go]'JՋ/_Ï%&qG;3{XT#|DYt9GY'd⠒W~<~l"RrMaR¬]w&w^=^'wxQݟ9(ߟ0 `l9yì[yh)[Ճrsڣ{9nȜ ASG2i0 (%.򌯘SeD[?<,L𘳆$ɏYtҒ׿kE^U &a#O=aZnfc><'mçx-r jY0dx7Ӳb36eAG򲋗՞f l9e%?}gدcמ0-9zC70?Y0[f91 !vn<I^3"xE C'֞0m?VsgwGuA0 Z:a|X=cjaM՞ʫ8^ 0 Z|H ` ˍwc,=! 6ԝ7pvמ.^ *f@KuĬk.`}ӻ2խC<-=ʄYؒa't'׺i,.ɷ{cUKPf,f,haÉ#b,:sU{Bk'J^|3H-l֝Ӳf0>?H^3si֬b!f5eۯW?ӽSƖ$/ЩY0 Z|Ri֕,f,x`1ji%G۝0_]{Lݕ_ԞZ$ygP0 iI#'rWYtǝ;|<5I1N 0 iY&?d/ݙ]w^^eg0τY0M] rwjv~zT<5`Tw¬,ݗL^^ĩY0 #{Yuh=cڮ`Fv2Į3fQsjb!iش;e%7,'H䂥g0OY0 mΧtT0c\;W|3fWcI8ƣyW0 mΉY{e}u;2՞<f4lҝ0 &Q{ƌԞflҝ* g7OoQ{ƌ~p/xي< yХݵ'ҝ~T3ǍE/=9 pvx7Fk_fyG^{ƌ˲ԑ3nQjO`YڝO|(OLM^13ko=f8nkwN̺jO9v#ﺣ{䬧՞lҝX{?kjϘ|y;ܣ{ Ww-YoS3`gMwo=c:o=S%P:tZgw՞##rwOI=Yf~l8_{´]>m5M'-So^Cx˼.%`qkw֞1cRr%g0 ,ޝtof{ QKPNkW("RKԮvZ*ڢ4RTUb'>^K33s}?ǜL&~JV쭄J@vv.7oH &?1z˯m1mRq쀌C5n܍&1MHR:`Q+VVRdSq EcL 4Ej<VAmL;~!:y䄅YDDDD$KZ/}b3\_lZ+i&""r7'1x'fݒ /ADDDDDDDD$9a 4X,:F]9j'#'[t3?%GtO- &EWmXNv =Rt""""(( xU/9TG'_c.у|{(6ȷ) /~(Zl:nE"e@ %5`wV4:8!{`a΀qz*EVuPm $r5,""""""""?>);h/?*uلb]6zǽ&SJu:I:J)Q3B`VJ5~dHݶ#~RER`[1Hfk01nYQ)ODDDD$G?aBDDDDݵQrEg"""wRJt,""""""""hu6FkYCTv[Ʒ|lƨhλ\0dy'-▙l2 EDDDEV 6ӈR ߟh"""wQ7+:=-˲D(VuB&"</%8hX %X3|'NDDDD5T }#:9HPol,"""""""""*w'eK61DF6@!R$4,/͈%q'NDDDD`~n|nS,E """*O!?"3ݎC`gmE+:I"=S1ytr9|NK7Ftـ32E """\UY牎@DDDDDDDD$k%a,1ihXB!^a BkEG!""""rfP~XDG)[scUAaѯrEG """"""""Eq$Ͻ>@%zzArOzYXQU_Y0`J/ Hg뫱.0uJKckc VpvYEDDDDDDDD3MtyU/?}3KXۂRA|{. %/,%]8!Kwa S*(%~k^DDDrUiOc9-ȑޛK?拎Q$m\MWaL? bFqa%""""QX""""Uxk C9p .l"""*JҿG9q0Ot""8???lٲ(S |}}QX1l6CAB"??FJJ ~w\~׮]Å pddd'9UN60mh:V@pJ`ĴM$f~:uq,ak jFX1wtvm`cT""""/y܁Eux# &f/wnDG!"""'$βvxYDDՊZjf͚ Ehh(BBB`2v ݎā_{}""""""x6n/yRhuhPG$tbl F4/u(?9VmDA:Q{3L1I>%c<7sJ'v%"TUTAFP~}#88 rl8t6mڄk"==ݥ'"""""r&/-(Nr\>z> kZ<^:jgHR9=dYDDDD4+&<|:r=r0DDD$>~J-:#-fADD.RD j [FF/:ҿܻw/o{CDDp^^^GQB\o믿ܹsغu+n߾-::=j,cRjt| Z[Mz"""">fC@tz{/~NjS|DDDWF2Pi)v4)}ի5jL2~^z'NݻuVܻwItXf 5kĘ1ch">IFAXXC^nHHH2))!M}d홑fGɸ{ n*Zu+OLcLlZeDDDD$I,"""""h&x*DGqv Js Kਗ਼=epB>X%:۪Q"##ѰaC4l.7Ga˖-믑wSO!&&}j)nܸHgɐ?:t耎;A[={`ڵضm RHf͚a(Qӯo`ĉN'Z EaZeِԡd\xIII,&Rը[.7n """k''%%a˖-زe N:k}`ݺu.;*Q4h5jU\"۷O?رc8x :۷o;605^͛cǎh۶æa9BRRrJ8I,%݆Nt{Ö6tC`Li,""""*2ߒJa 48LN6jT2Wt"""rJ*l?-ݩ%Yv4<=)V\Z4V[OP %( -.~/sqpW.xիcРA֭K&#gΜquH 4im۶B Ν;Xh}]>*?lAMg95Mt ̧N[a[~qx,"""""Hks]GQgHE>LDD"i1gIt:u.^j*:KLbnFT Q9e:뵟gK,Ɲ6_$d2G8p E)<,ZSLArr8TELL |}}EjĈxwDǠh޼9&M /Vȑ#": yjժ!** 5BXXrݎ v؁<)&&®%]7nTRׯ  ˦ ɈC||<Q:/B2'{y1f6S3cDDDD$ PJ`8=MI)('""41t^tZF&:^ -ZtѢA+ tzuqnƺYH]Eҥ+`Ȑ!0͢<7obXf v.K/FÇdn+%''J*<,͛7G\\"""DGyk׮o߾8p(䦬V+(*U~w,YsAVV˯:v-[8mRA <˗/A|||зo_ <O?8Š+0g\zUtrիcر֭j8O~/}"; 33j7҈R(? SeϦTZP?6̊M/ODDDDb0 &DDkqrsqRqpj<Y+:C:ǿvXVݵlbـdcєLܽ Zr1cƠW^hvڅ}Ν;П|||0fd=Ĝ9s0vX1<ֳ> ~Hnn.UVBn mڴAϞ=Ѻukt:ё/^Đ!Cx0ޅJ*~ޢʕ+FNN(Pn] >:ubݺucĸqТE Qb;v,R@Y%6`~UXKJ)> U^ڵ1Ʀ%""""baH*YoF@97 'ˎ8)ȃm>aEUc~7= ᵅhpcFAey*<}D!^hW'|:VA$ŤiH%T)ɓ1h jq\&77111X|(GVc2e J*%:, 4+V#( 8f͂8Odӧl6Nj޽;bcc&:N:u -Z͛7EGq[=zEӧOf͚cѴiSL< 6剜9sC Abb(UVŬYЦMQ\ݻh߾=:$:l(]fj(ćxgb.$൅Ft( t\̊Ջ`a=F kD8lGlT=ƎDDDb Kw pBO|Oԣi-6+6땆Qj0~x=FU;ѣo10|"+}r!((WGYb $:I/bcc1d,YRt"IJJBqQ܎JBRRʗ//: µkDpH̘18fC\\f̘)27|/,:Bff&:t={"| /%-Ŏm~Vy:Ō(yUN+fgaLW+9 JRbFBk_l6?ew,WS* OP(QJ U*5pwop woqpNB99MT-XcFwOÁ9cY`EMУeWdSvcz^ޔHEfͰdTTItI:u*Dpk+Womۊ"KFV;;K1|X,Qn޼yxWE *VF#Fl6~DFFŋ.]`͢c<аaðd1.00o6t":޽{Ɲ;wDGkٳQX1qA=}vQd+^iP>ZE Xnjqss|>f OǙD6"""""`auԘߒ2>=_!]*&(˕SZX`Z_dgz 㡢[61 -_#*7&};[(0o~JgAwav`ۊlO@O[9 IDATZ ȱXEDDDD :_` ϛ]}Dp 5jSDx,e!^6m`TXQtJOOGǎw^Qj5&N'Bш#Ihܸ1 ZY(\?BKà1H"Xgg6j}5^""""rϺ&"""Ro0i{e}ASX"AUXӌw>6;( JQbr#%Xl}7ADDBU nWӉy#JnZl;eEߑYJ0u >>شi>Ce=Ʋeмys1dB صko΢,Vneȑ8pGeRć~ȟIV~}|xwݺ( zC6m*:#yyy!$$Dt ǎ;sN+ш;wK.ű( >S/_^tY8{,WfQ(S#.Q]fà)zѳWMŌex|wDDDDo_jFס^8ן ]*R9,Ci*,̂6tN?^%\uDYUXWP/7[Mt;E8{,v*:,h4lݺ*TEJ%FgϢUV㸝eˊf3lقyA%غu+Z$$Jºup!ԨQCtY`;@dd,:tΝCvDGJbƍ4h(|wEsNzQd!~rܐWS3 e4拜6 i+IU [k[+zxADDDDd$"""pRk?Z1=ӐŢ,W:I9L0RSg{gSk?%TPO -k|7\^e0)0v뾱fg 7YX ߒ~ɜF {n(ׯ'̛7At¬'tYtaj׮ٳgA.P(0d\pzt:O.:)J4h@tr¬ŋcذaO+(RK{x4ڵ /P̟?_t YHMc 1 d%^Ž5[0y*~8)hg0x-|mApu6""""S U"""")q5Xs3EG'1xfb~IWQuO-kPW/ %%NÙ<9'nDRSˍcCRDGfaÆHHHlٲXr%6m*:Pv>,N:%:,+W/_6l؀={Qd?<.]%K"I999hժ': öm u۶mC6˪ fvk&/_ք-^v$[>~QDf:|p<9 ݲ(+'x\/aEYo=9Rjm52cI+#eVϩgl0a%ogAZ(ȏ*Jtb$} &&h㋲ #T^]t2h $$$(/_Ο=226+325E -Z0DDDDDT8<=ADDDa`bf};K9xڍ4=Ẅ́w ojr[z/2b j7*zuԘ΄xc(F8}$Wt\S 6C?~T{INF/DTbѢEP|ӈc0h ;vd2")6m@ػw/{=fq$e˖[$ *PhժUÉ'зo_Qdb`׮](^(nOaժUXlt:]8Bb0{l1d|l\%:FEHZt [>0sx:Mɔd0WTbfl04QΑȃ m5NodԒN,,tzn0~S Vq唘a)Ɵr1͙cҹ d=VL_ir˦V|r̙3EDVzu 6Lt IX,غu+VXB{3f{l|QFf͚cDEEԩSh֬(4`dI.YEtB߿?=*U"+KƪUDpk>>>/Я_?QN߾}Y$\@KgfuPxiL띆 N'ŵ_""""z, """~XE"egBd\IţT]>f0)[=hAȳw#"""""""rUUXsJi׆l m{=cZhymt崂OeP $L]8@ޱ^: Q :=7e v# n%(Gfc?HyZ.FzšVU4Yb0ּ͛/!\~J* sŔ)SDǐƍ}cP`߾}8q"z?lfQqP`FQtG ѷo_QdoܹZn^zHLLDʕEGqk>,Eǐݛsp<1 e Dq1Coty$e#t/oWfta/V\e&kនV5٘#{''5jݻ/:Gs!ݎh;`Сx,^Xt IS(Xh^z%Qdŋ Ann(T@ 4m8%ۇM!+{ATTRlY\zUt޽;VX!19ILLDDDvyR:u‡~%p!4lPt YºcU䝉X Kt 01Ӏ1ҟl7a ۑ#: I XZL~Lct "ôތX#W/拎!;hH/TNDsl.z)CV!THg%Q CTU쭀ɢ٪[HK##͎;S /υ|~q}47IuBF ـ.&JA%""}EG(/2Ep)___lݺ7edd ɢH… +:, >- Xd ZMa2ݎcǎ!%%ﯻw~ٳgq9,~DԩSGt EB8L}! %UV+[gWEPNL^ɚ^锊yyt"3&)U@ͺj4֢ak *|l_7xt ߒҫ@JMI{.f0)Ԉ&95˞{Q:w?2zgp)1qرc,( 555kĥKDG8L2Et 0`VZ%:=bƍѪU+Q<Ʊc0a|W믿" @t Ecǎ͚5 &LCvO_]t %K"3M X=MыQ`|{x2.{ *50pB$}Y8sYDDDDJzOTj`Re}6CZ(KW 8]xaVӊ kxv# })15=>OƲ=rYQTk 75 2w ⭐dQ|<ϥEYUXs¢,RFЍ6mbQ`=z:vݻw(KBbccYƍcQ?J@9rEY./[nEPP8BXV L*5kıcX"(V`e f6-:l{' ׯgOS^Q!,~MR,\U_Y0iVqwMhu&l1R:rsD!ycA?C^ /1~kط 7S-;{u5#k\ꦅρWay ֭N5h l޼:=Ֆ-[f1$kРAx7Ep+WFEǠ Ç":ԩ=zJtR(0!:y|7 cF :Tt ٘;w.F!:+)'ˎw'/vZE 9w""tF+/7ڿ w‰܀N-f4v).gBI<>4HƱ\<6|K# Rb1bg7F]5ڿ(C@-P\SLXԓRLqX\~  PK>8W7d[X:tY(#1 x1n݊HRxx86mG'hٲ%Dxڵ_|bŊB֭[VKyV%l26RTRѣ6uTkc?+V0 ixyM Ԡv#w&绒xS*&勎#\:jKbl &%"""t\]#"""1UE;xm8/6Nm7*qBL[a6!hVeWdu,Ӯ|F3 z:SXQ7D ~dC=^hVhW^zjhlڴcIEGp޽{cٲe.!K.Eݑ#:$UT ~) (nIRo߾cxc\BCC1|p1\KtB51kΜ95kk 0@tɚ0a&O,:==W:ۙy#y=pj=ovKdL{)]~ 9 O[Y~{\DDDDTp{2H, ,̌juf'g`l4d9`2]9׺Nݻ J|iA&M\vM*]0O 6ݶ(ݻ8p~駿+ݻ%J 00M4Add$ji1rʢ#Ҋ73Ѧf<*в6z9$Ež\./E|J^Уhqzط?cDDDDd`R ~՟LaژJ&:a»8٢}ܹÁ^[~cpH IDAT89t&?y@bw%Re/8ޭ9xhCi+{,?hϡCM;h1s j^`HT|{'oO?-:C]r֭×_~#G ;;^cȐ!>}:L&R^V{n1d2ѣ ei&lܸΝsJ(aÆaذa{|2V^  5ճ&ŨQoQك-[F9s戎ApM,YRt ]6;&:F|ru vڅF9ZTx6 %JݻwEGz8x V(uIlܸ_}N:؆2e bbbTJ`xs/4Q`^3K[$ѬY[ bΫ|FDDDDr&'x""""Qݫ(+/;&(KF ܽ)  LQg?5֊P*5PL}K*lc=( :k1r|6IsjKY(K vS:;wtcǎX"^u8pEYS,XP9sI\r#ի=(+++ |ի`L4%EYp-L:e˖E֭1}t|Xv-ШQ#TXӧOgQVlo{ A{G*EV.nj:bm]UVD *8BH 9'>~o_Is]3u Ӽys888a)K@ =&%ҿqAjT*EÆ Y`Xb ,Zm۶qƨSΝW5e͛7^~m#}%K/KEl8kWEKKѱ8D,I:p|o:tVZ.P-~Q?;J!B,eVB!X{ PVc˹|{Ÿ*WB Tkl퀞pV R)ޔP$ yr7EBupFb|L9nkg]΅xTwe]ubNVȻ*->+WFFX0cǎaѸ~z^'::-[ıcPzu#3gggr%00]taäZ[nc2wrnœRppKsB!!Bcg]z,k,AdbVm MJv}jﴬ<7krʦ-pB&/,лeƬ#xRe7f?{f#Ϟ>>xQ^ϘD"兙3ga2ٳ'*U 0o"yP(g>:u >>>pqqAٲeѱcGt˗ǐ!C:b4h:ŋY yP`ALJ" )r9ۇ-[x,e CI$lڴ jb%._ bynz/<<]v|GGGǎt g4!)2 S#DTiqcr/ ŔNXwUXseB!KcOB!foqFCo)k*KDK&1jz7r2&N>JP7?Z[pp' 6c lbe,1kd̠)%K>ԩf̘:Fh4̚5 *UΝ;O>ŰaÌy%ZBƍ~sΡ}Q~wh4tc)֬YJ*+FƍѼysBRjj*tRL㫯j|1Zƍ7qF̞=ƍٳsN<us\pI̟?诛W"n X<)u Ge^WcH[%FuMz6p:8׶B!֌ !B8%fnPɗє!I8?uvy &fx7Z}>oxj2E?7xR&8C?a=Ww &,q.XdrX㔒CT~rDl56HKA;M_qŲvyU6m$tQvLL zӧO8۶mC@@W;b}_,XKfè1~x:tub֭ǠAk.Çc޼yM,wׯ:iѢo>3VRRvލ{?@RRR-vǣjժfNi\ #Hרh̲Þ={ЦM6k)))[K$$$@ӡJ*hٲQdIDEEb6{Yȓ/gϞ&ߦLͤ1hp<Od~ 1ց]%1Lsj(#bpM@r 7qA":GvX?/"= B!!B0{_tc("#4DIMYxYDpUjm~qvä"4f]ʀ+)+3ME^w129p*~1FbŊo߾ؽ{wMYϐԭ[˗/7cR,&f$ 6l؀muYj8}4&L:u@PnݺׯƎ3fয়~J*lcޕ)SuWV^:Ft:̝;^^^fiKJJ%}%OJN˹Xؾ"?HOc aڃB!ĪDB!J;Hvg42oMCfJDߧ&KP"{œH%hӍtVY[l' ^OO*ʘyB|DV߱4(FLFJ{1mh:VGo1K"MO-iGϴHV-XyZeS|:;zs[&a֭(V(V;"..lݽ{7&F/^:QT*;+WFHHt"Uyzzbc̙&MѣGoh"2Dŋaʕ+Çٙux%PB̟?SSS1l01D McѣG& QQQDkjKM-]Is4:,.qt81*.EZ6rAF5ŘB!DB! 8*$XGF*Lz3F$a$&S(Uς]?wK ߿??|͚5Ë/9SRf %xL׷r8C,ӱ=R; ~L2^X2c{ wYpsB!!B,[r2;5+6DF:0wL2VȖC"J 01KV-Pޝ츞fSx{'3)8߉rZ}|ёnV v΀K0nX @ߦJ o'2LrOxߝQ^صkE/_Fƍ(@~%z9*UYȕd 2ݺuHB@HHlmCj={͛,'fGO͛Ν;'СŋMuYĬ:u`׮]V1gTX6mΐc#=<>dɿ[%K͛l ܼy3|}}: ^z:¿xIK-,NeCo  hjGF:eQ*:~BmG\;/Gax8*%BO$ !B,Tպ6XsEK}YŠVJl[&΢1\RR!^>-ufӪM[Y0` FNsLA\)]∫Ojm+f=e5MD׉b6:^[7o<ԨQu ]z[۷oYGal>qDኋwêUXG!fo\rcmذaرc_7&&QQQFݼwS0rH1ۨ_>o\111f9V^YCc(^/^B0R"pԩqƙ9::W61Rd2BBB/_>Q uVaMJRMKT$ĉer!%ʷ:.ql8䨐`pC\nVG!bĮ&BX6X~95x%e~ aqT.FMIbRTK!FHK3n^1,DzT%к3 )ic߇U`N6)" )q~H*3rq;t#Fa0jՊ,(X Fc RH׏u QF`QϞ=ѷo_16w\_pd[5+ ,`#O: f;V5$:S:ptt޽{ԇZѨQ#[l1۱RNFa۷O>4eWFFF`quX?t>Y,§(-V %[z<$#=|.B!XAJ!B,K~NhN7Fr|51؞?FYޝ츞rM5rwfu-m1ie[oiaۘJWDУ1DyQ6-LE kw$Pc:A+kײa7nqqqGBXGn2Cz::66n2M6~1%Kbcm޽ 21Ο?o TlYl߾2π2l2tJ޸qُlX#Ĭu֡vFLcZQQQhܸ1f͚ ?_61s6:j޼9Ə:v???~+ݻ:Eڶ" /09\~^I[5[*RbRL^m\K?&B1%>+R!B,DpĤNUg3S0q isX >gTZv{Ή(SMH[8}DP j6#9!&*-Rn|9_PW,$6Mo#T͛7ݝuDDDe˖x ((\0.Ő!CX0ٳgѦM$$$BH"`pqqaE/W\ ]f Qy}!_|ڄ 0|pfEoݻwwaDi.Ĭ &[n cB۶mC͚5qE&j erlCՖ57oToٳ'WZTVgjB>?X^C)5Mm+rB;B!!BtF _$1AFE-MB}8uRsk.@eWUivȗ?oR@Aik^*._W.s*P* eEFhЯYKp% !!s͚51i$1 RЮ];DGG){{{4lؐu YGRϞ=YGۋ/_"..ubf+VĬYXKFF:ugϞx/^`^x4+3ѡC1rEVwXn(˗/۷o`"4fEEEϰyfHx~^| ooo̟?u|6gƒ~___1 "%ύ kժWWW1}_):X>`f$3fq:,5-:[̑De=]1|mH!b$TC!bbj`.T 6xZm'2}Tl֞Lד(Yo_f) =!"З2ޕgsl&fzl͘0ۖWobۅtu:2akk֖ǜڱW IDATj5vk׮ B.c "th۶-z۷/>|:13L7Aà OYxԥKL0u\@ݱuVQuEY0B0Q"q֭SNKi*Z(,X:A^~/_f%K-Z`fGaюHǽllT 4Y/BsKe{a>c*]Ƭ;a7fu*G|&%1H^Lw223aԨQu 6 Ga#[Zb3Z)u>$TgA-Pų4le ;Nn^R#u e/[EIKSEJJQ!-:<}9Y-Fqd(gwk{t2Ur>VfM?u ̜9Wf#[666߿?'N۳gϞaѬcW)SgϞ_~1%y-3;^b[عsw>jѷo_ٳuO(Je-Dh61+((mڴ1aXz5ڵkyS1rd Yztݻ7FKF˖-Y}%9oģ/kĺ?F =8@J5fݽVr2Y? %b.u2UBYX~=lmСC0qD1rԱcG)Ru vʓD"0'ӧOG||<d2֬Y#wVIQL/_˗>c`:֭[YG )qf!Ĭ{5i&NwSLV611u%%%'Ea23/oRNv-*,' z:!yOGd(LؤR`{v&B wB!S]STwk0b.%Wukw:l,:: 𵟔CZN)+P.ʻlXW)n_4RgW TōfGdLt6֨ Hx5QPF 1޽{3c#F?uLըQcիWذaueC/3fɓ'Y#piȐ!ӧ2f]u,rۘyu 1KYغu+d2ij6lO:JDhzz-yh"PL6ur 8u @LLL_j\<)κJ!pu&!l^Ua~*RhlRL[儕G\P$uB!&B!#)^V']P# ~^mFBU.?ws:Ì*׶'x4xtO((f?1^S@~h+?ڂIЛK^yrwXS*fnTdyTJ~蔈͋RYGSxUD L4u %''SNBL-S7o:눍e#SrdHTRBL*g2/BZ*=j׮E+ ϟ:Fxhk׮`67f)Jx"F"`ӦM(ZR.-- ݻwYGыJb!Gqqq#Z۶mѹsg1???hoҿxxx8rVg樐;9Mb'%÷j-Kb2c!]Ѻ+ B!ϧ„B!RkH)/.D|ߍYOjq";W[6NgWܰCj*VFsZ0^mi+7JW;akVfwwkѿ)Tqc[.\'''16d_u#dIim4-:X_ 14 ˜fxOi4 ;vi%3[lرcYȑ 5fqϸ>OAAAhӦNJJ ڷo;w7&fژ%˱d1N: 1Ņ^hݺ5z97f5i҄ih׮/Q ºyY6flٲcmȐ!~:z4i (:8y$Viy8S%1aBr-fHB 8=ܞW3B!FYB!yЦvvclDS \*u8o {)*}JV~w j7kZŤ([&#ޕ㯻at&M[ઙ jě6eɅ?G޾s/fCo/_Ƙ1cXЋ\.ǜ9sX׹s#12%JQJ1rt ϟgC//^*ÇYG?#peҥ st邌 1&E%kjyb+l$kNk#͛7#\r bCoW͛YKr:ƿo.D%j#Ppz*kčum&dTH! *S!Be=fUW I*Ũo fT O G+7Fl*3jh,|]'y;Wշq|MF[[8155$ gW~؞ND&xQ>WƎҥK$ S=e,Yu[u,-Z_c\xubf?3:FU˗k1pQB,\u ~۷G||<(z+RCtt4f{cVv-Zŋ1#9E`Ϲ߿~u H$,[ vvИ:AbrߘO(VFG*SѫNpb&.n.(Uc~ n-3KVM=s!ycM)88X{bժUc6mTwϖ-[.>1˗#3d OXX~g12zj߽{7䧟~BڵY07|ӧOabŊ)kk:7Ƭ `Ŋ ,-- ;vvR{#dKǬcM"_~aCoSNťKXKZ0sL1'k|F0\Im(?? 15R@?~ LE!ç?B!ĜY&B@rbcWJ?&A8&tb7XC2{{k?Ξdq/sb[ : sU؞1=ThZ-|FoS>sF'i+6@:~7te>u guRKe\:1ck>3 0u bcmժUd/[ul-Zu}ub&Æ CZXȑZ?j5(:u\Z6mbrl޴j Gf`-ºuXȕʕ+ׯ`V<7f!..+VӓAeddk׮8z((y?~3Y>}f3g`֬Yc!!!g'8cQ5s8wMƈ[*R Pk0B!,Y@!¡΃1fe4e-3RX + ~L dJ Zڲ+gXT>'f=0apS"u:4|]#p@:U |R;!KR&fyS"2N)m\:1+EsB&1~u 9:ub?>p1P(XGKXG fP`A̘1u ,X 8grܽ{޽{LwwwlذAo:qℐdژ:Y9:?iYCǎɞFA^pQƬ7OcERw 2fhժUTxb$'[Ʀ>`h C.􍐼yI͕-ɚ^m^&B1'j"BCv]6sF'cЉlԔ$>:x>œ>] w?G;û n!Ix(K jPcDrwS$y,ooomۖu ȑ#cc" :^/:19sՕu`chxYhi3%Kp¬cѣGڵ+QJ>;waVn+1+SfYVS$vFX=>>FbC/jBHH49sgΜa#Gru,YubbC>}X˨QRXȑZ3 r?Iv튞={aT|x (VhQ,XuOܺuKf1Yk׮)xXf F#BGXGЋ+Ǝ:^]&LSL:'V\)oZs wO):,bt'WO[xF6\B!Z)&BLպ6U[7RQF:GXG!HMmi7@Se2^*F7'b" [H K`'ziF:0epfHBZJ>XsqtEj8Mڹ)X1òz6GF[خ];|c%((/^`#GE,4iza!Ž;X۟e˖Xaaa|RtR1 6b' 4`!S]sk>l۷/… j2eʰH2rH˗uiZ : ?Y2)) gfd= hrj V+Y÷qT(&a'Pq*A&B1B!$K.$E}}NRts"=al<쫔:>~T,jyMYP>D+-^񱅱D"YrJ1rP)RuO9r'OdC/ɬ# e˖eH.]:F߲ac~2!?~ aSLiʕȟ??Yf ֮]:F5lؐuL]~u1]K/|*$$#GdDu9rwwl2\tuUV {=;d͟?_ S՚L_H'\Su]7o ^k !B̍S!B0eżxOą㖹1m9y ] Sk@C{/"'G11Z3=Fy-ST&(C/fϺ4,`ʼNzp;vڬcHVcСqݝ/_>_V(t bCo*u׏ubvvvL?>޽:o3]t 6DllI^_$/v횐 &fΎUΝ]ѿs,V1r4fX?uUZǎ(x5Ν:F g~䰣,bŒuD|*HG<Į!B1*"BDr4k>޼bHk%n\b d֭hڴ)5e(R.\:AХKAFv<<ulѣS(JHH@`` y)zswwd'NdC/#GDR؍ϟ?GfJLL^zYDS1,^cdb(Zn h$$$aVNNN#dYGgϞb?+jb#[7od!G}{W\-[XV pq,XuL]~˖-c!2B>j IDAT{E> 14X8>u zB!O !BfIRwDbɝg1Zz5hJwUt{ ī-whR=z4z駟1?i0ydxu <|uڵcIPP,GŮ]X07o^^^zj^c۶mT-ZdtENX0Ȋ+c1LJuLal<7ܿ?#*V:ʿѮ];B!F*B!(WUV]B[JWWmoqP.$ݘ nZѴ,sܘ~_vCmL&o=vx´sOjq/ohjVJWӇZtTY|CР%:.&fթS͚5c#G=ŋYR%pY|笣d)<<1 V^RJAH"oYȑFȑ#Y0gϢ^zhҤ ̙;wd?{ C5УG<{LI,7,smkkKY1K&!((ui4t aaan?ڷo_ϟu߿'Od#K7ӧQHQqF={u b758y@Y!ǶĊUoG\/?kڽ6 !Bw!B Ne`t7/%W1 gBY\2 mQԚ8[(=&f%.^j1/44jg{ep8 d,J[ B}mr >#hpԨQ#DZݪUP-Zu,j 0@]߼yW^ӓu*T7nׯ_Criɐchʕ`$Z-Μ93g`ܸq(\0-… p°Ç{AX[Ff̘bŊdt)))M֭:Fxo0v ~3Ga7n:B._:B$ʹjcdC߹|0blYfիcڹs:A*TC/@RR8@e˖?9R*2e fX1R~}!&}hԨQ}6Fս{wdYά#d5k_e,x ۣbŊchʕ{.2d.] UC A\\$kp`:9^JeNQv26oD&Byߪ+B!3k~ktpK)G2yy"}v5mH=4Y^wou{}3SRߝZ3ҁ1U{ݼdN{U|sTumZ`ϳo2 oIÈ#*ʴiӠK.?oʺ~:Yȓu\_>:QM[[fΜW^A8%ɰb H,˾vr>oTt EKcXkcւd֘>oa wO~σ6f 1 &,, f?R)f̘۷C.yRSSѧOdd}|rYf|2W: SժUѳgO1r A86tPԬYu |d:wm#Ѓ*NǏSNHO{&M@|uAL4u k׮9:rYoXGѡCpM1Pxq;v G޽ ???tLݼfa!,b!z}+Pfg`x{j"BɉO!BL&hMZn ChNblXGӇZ<}$ngW1ak}yAZJ$Mz^*'<'--FA9d_; 6_?d/ՋrJ;7h׮]àA0NC޽:edd`ʕcD"qmt҅u`ر{{ĉ#uU-]'N`$/_>1eY417_2֜u:BBCCYGTٲeѨQ#1rdгgOE-!!:t@BB(DVgjV&6و BekL^Q!u"9^(#BwaQ\mDQb,Q%j5KT0ػQ#b^vZGb nY F'~oKw>?JG7s?K(8ϥiӦpvvf!;駟ӧOٳgQtif9bʔ)8pFn:dfu/_عs'~7TTurrr epsa#"##߳aJ#F`#K/^\w͜Y:\(S U:F>}E޽;يDHH;88_~-[꒫н{wŭ tBq~ $;EXw{Ybpz=rj f IVZCuB!FCw!BDI š[0o 5+ZI9R / 4yd,U뛣t>?EGɫ( 0EӁӱgC:uN·Jzw~Z !YZ+k'χw[־} &ǮPΞ=iӦLEpp0fϞ:QEGGcͬcE˖-q lذnnnΠA`mb)S@86`*UuGrr2(FѥKxzz%9/YﳎE$oڵ3jsߢE ܺuKӇFm6bX;ky$!R9ڣRM靻i)zL을XG!B !B+3@_v88P+^JLr->u:I*9TnY+.J9lN|o:nv*FvNDb !0 d^{4ߋ3^ކ:oE"rA!!B(h!BGh1Mlf@VzUHopW\ef.ɻ010lMf ;8: f7c*h}9fc[tX +R-̺x<?g11C|(϶[VƍVf˗e׷ôi#=VV|۷oѼys̆ p1LׯGDDJ: :B._cǎA8UX1׏uIJJ¨QX0 (=z:#05w\|otQ۷g![{1j'wwwݻڵ+ Nrhٲ%XG! ]9ęk7ޚuB՗*?f nwL&׊yoG!b(һc$B1.Ͱ=F͵yLO>,{5i).D>}?_a o{*`%)A)\fSY^0$q͑zQF^Y",۱cQ^ GFdd$O;;;TЪU+ܺuuz=[$''brXz5>|C ]dRѢEѶm[1%R1^"3fHKQti1rHLLd 1uT1233Ð!CX֑#G/FDDss>Mr*<<͛7Ǜ7oXG!#ΆO۫PxxJ`, Rsi~Y藀2x B1 ZC! a7:^w0Jz BHRUW Ta}ZBWGj :h} 8 f I}~ \0o%J~E&N»S1O%uGI.}]vLv2빸`x .\'''> ޽CfpeQLbŰb DFFbĈ랎w}v )RDnYòeX0{{{ ^"##YG`F޽{ݻ#3S(ЩS'(Qulm߾u*RW:Fbbb UlٲXf ?~#Grq-'ݻF!&&u‰K'2p == ,m^#QNlZ' pN7#B14ZC!?0]m ʛa9 imEoǬŘ$2%hK 7/YǬ$=>Vv*xz uφtaU&/F{/PԃwRs9k(9hnf{]R ݙf˗e*_<cL6 y]^~&MPQ~EQ IDATglڴu )%K ** cǎ-HS*B,_z ɧ7NyCEFt7ؙ2ePr.̒kǬ}ɓ'c07j(_uj۶-Oٳ:"oԨ<{a֭[hذ!^x: ̺qf5g9d-S‚u;yPni΁B!Hh!BH6buoǤ 'T96Xu.nt)]\~L0:Ґi6u2,R*|}oiϵQOa#O=.APv^@7Ć,0Ww%}wN ڒ4C-?'ݛonnmø}6'bx%7n7n¥!Cڵkc0#** 'N=Hjٲ%<<qj{A/Tt&~@Pz1c]'O`X Sމ'аaCİ"ux5(\qpp@@@>|aÆAՠu҅6BTTS}EXVll,fϞ:aҥcɳgXG`ёu={6.^:~rnYиqc]f 4k[naܸqpss3QB6VZ]hۺqf5뤂WEi>)6J Mܽ%`47uK!Œn) !BL'_O@Z4 M>Wa){G*В)_ q^ Ieȹ6c;f,yzD_ A o$ *ߍ !BB!QrNB6jP9*T#6ZұgCJ`%DUPa߿$7GZ  8vK m&PKɒ97b>Ju. Y&#~?fdkw)f;ֲذaCu1xxx^zB P( 5c L>u N:8|lrAAA7nƎCd2_>YbB?'z!֯_:ԪU f#O222:3r蘥hЧOdfΝ:Bܹ޽c4h:B^|۷oB z,QhLwعs'(DPsҰxuiNo_saɈl ,ܦF|̣BTSq}W!BX,B!|:9e`5*դ+pqSb ko4c"ѮLzz(g;_1AAg CZ_Ilj.MY23J]ups:` ޾hڑnYkWfMjq9a;NF?6o:$ĠaÆؾ};Zn:믿رc5jn߾:u֍5k@/v(F:BL:Ҽw@``  ϟ?5Ff̘;wΝ;N:c2===:FlllkY_f'66۷ŋYG!;}HZcZ4먂+LOhtq&ts#=UmW#B2ד(!haVB ǦC(P1:šK.5j23uRTT>3̝;IdbŊ8}46l'''q ?g!K/_đ#GX ҥ YٳYG03gB c䛜*TJ%y&_n͟?cȢE2hffUA>[.YG!ubJU+B!ѤtB 4Jldklq(X3"e^YG(t̲Q`*[(ğ[Jt q>ōkZ>l.Lí \U4E {v6~u2ݚbO~á||nŊZfVѨQ# "3=t5~#Z+NOiSS0kh|B!ga&Bݫ~>>Xr%ft:'f*WM UnJ؋3лADS0I!B0B!4'{~Ju\)\Llp8٢dY1M 5ҷ.Jcprc&uc+"uX8¬b%͠Ϣ[ {C mc-- YļyPbE>}uKaaahҤ zXqVti\pzb%K͚5c!KpS"t駟$Wckkݻw֖ug...#԰aàb\ߢnݺc̙3㧔-[uيѠABTK.cdKݲ֮]˳ar.̒RǬԩScp cÇa1rju Yھ};vZE3niV`$k1'j5­jX> T0(qhB!3[C!©;W2ux,B; Bnj{zto k[1R  c6V ռ*a|1*3us+wvOǵ3!0 ,;IgxkՌd_wKll:F#') -Zu Yy-u֭[ѣQB۷u 0஻4h:F:T PH1tiܿu 8p z:Qz$%%T Z-&L:ͱyf؈3:edf1V:DDDݺuCLL 8o;8vRߪ7ja6 `~G@B!L+B!2VO<oMm;^f~-G8`)N51&VŞ A a-< \ݕ0ed$]d z$KzKzOfk11VNM{v:}- 1Y~|.#G L#$$>>>>|8޽{:1'Oz۷/?:j֬gravڬ#dٳHNNfpM6#d)..vb`gXZZb4t1)tJMMŴiXB͚51yd1rLc#Wt:֯_///,\ -';-я)5ErT98,uB!bb\!B[2ux.oi%on)̀&b_@۞PNEBKs,M'6S^רbt1G|'^wbZnWB)[{5&W_!VHic|$ IDAT-3K.yhٲ%޽:11N .]Ǐ([,;E>u,@8U|y(Qu,޽iitLȊ9v wwwQ*#Cfff(TfDGG6o ssqvEڴi\:Fsqݻ+WƷ~Xq1m&|>>e(ĭ!yP9V쳃Z>=Up4 !B !B8קc8l_LίKY3L_gCa?Kk\{ wMz*T7ǘcVfn%|:Sy.*'@ R$~4g93 a:F" OyK?ѡCԪU RSS1o}M6!3SZMرc矛*U21sӬ#N5jԈYڳg}J23ϳDyf<u cXZZcz~-YGz;NݻwF:)JHNNǏܹsx "##l2*Ғ hX]BAgNjI8:)pin;w&B!y'*!B@N :WGdzBqUoe{rRkzܑNa֗E?qtB ޽yu˫"ߋ< "kӠt1bJL_g:Fehy#SX-=V;wvڨW<:Iԯ_W^ťK |svvFϞ=q5AR8x"""ЧO+W6l}VPPɻTXѤ˭gϲ@8ՠA ./8x:{11KԎKT*e.]u\Yv2b xyysθr H&ѫW/DFFСCh׮'K,Ç7nSc8ę{Q+5 <`/VNMbsB!{ !Bm&ttR燧fnPch J 5أX^FϷa[}v~ LFcVE'(sh ~kz{QY)0\3q&.tRxyy/ŋYG2 kkk,Y'ODժUso~M֋sÇG2e ֑pttĪULzL Z-_:TÆ YG-R/QLNο"=zwaYfu֬cJtt4{1ёuaۡ}%6(SIk0-cɧr 憑#GѣG#LqM1<>4n&M2p2i{///Yu$СKʕ3ɱHM7=T:F9:B̟?9Lȹ0KYK.e.]`„ cڠA:F‚u t:>|ڵCɒ%1w\{u,iӦ ܹm5F???",ߔ훙gwE)1oQJqmL4F!"|$B!ORѮ\JEbW2f+ТZ|@ uY +|X@Lu-7 ix@/h~'!T1L^9{ Xݲ:D^cN  8[SG`` W5j`Æ HI‡5jkM8...H%/?ƠAPT)XiiyŰ6qR~z*Suօ:Nb#Ͼ;=u f\%jǬ(Lʕ:Fرd#_xbٳg@RЦMBw̋={b߾}骶d(|ᑬi!\~VOEPSרQ؟} OfB!_2 !BA%'8}֪x+#C+Y t>Azxt_bk[VsWƂQǬZlZL;̋'|_Wҥ(ާmՌf# _j:Fl^ۗhgj8ruWWW_M4QP!JB߾} Zr3 >%KĢE,8nnn:tяicǍ7XG jРY~:Xȓ.]`Ŭc0%,Q;fO++<[[_|i{c¬KNNFpp07oL4 QQQc11d7L2hڴA^oc:^jkPM϶_7.IoPJ!Br,B!`0?ma֐dD`~xP{Rp1qn gD.23J>3\|CfMFf$|zh/ t*w xzaV5zŚbRapE5 Ŋo.DԦM>|jڠ۾}{`̘1(Q̙D֑n„ ppp01<<VǏGtt4&P(i&ԬYu\[j>:AR߿?\]]營III17~xy/L'9gC:޼{LC1K՗*c:FDk1c"Ro&B! B!b4z=ppMDgxl1 I 48V6 l3(U|x+y7j 1yKfC6[(aa1 2+%˙ U.fyX VpuspxEr<33'OĨQPtib޼yb[ƞ={%J0k۷o1n8.]ׯV=E^ <بE}<fɓ'c-ZάcdҥK#䊧'=j.}"cAu"EXGȓ;v̙3ѥK1r3f #gJHNNƾ}зo_-ZM6E`` ޼y:7ƍ9s˗/o&&f+cV L_g: i7bB!k!B1Z,֥0,ᷤ(J7C{tl1Yqo[w5=Ԯ4<{kϟĨ<.4cS`7O8/R*ʵ ׎YkXG093s `޾bsodb 1P غu+z 4nK,ÇYGN˖-w^wqtt4Utt4[TPwfѱcG~ō =''QJK<}usuuEHHE9".8"ػw/&bҤIcZFFzTQ Fϔ#Ymڴ:v술 ƲƝ1c`޼yF=FT9GrgOxJyoZs9?J a.pp=Mgb}G!BГ/!B&gC:z|Mpxt֩ĢR`Lіuw_:[b4k1VR&2U-#’zPkUU$[NT0;HŚ5OMcbddqefSqqL0ժU z-[ݻwqe˖طoы񄅅sΨS_:Ahf/ [ik׮c8z(J*: wXP]X1rԩSӦM^u<6mPȜ3%$$$`߾}mW/tX34-9wcVӎ*_WYHʆd= PJ4iz:4iz<ա>I{ǥ(t'WFNʿ`L "":FK.ɓ8uΟ?1;ҡCl߾d11?5jA0k,I5k HHH0k;995 ٳg#NU\u,#vvv8rOV:IX:IU^۷oKѣGM) 11gϞի¿'S:u*f̘aIZ^$ΜVض:]@wP`^;to?24nI{~!BNܻZB!btqoش8 +ab$ܹB9o5ZtkʒIQJk6 j(9zzxW]LӲˋu,ݿulj9rkf?=z:%PL -_^ӧOѳgOxo=S@DDN5k~~~?>.^(ai޼y&-z 4A[HMc2 ́a?p{Y(QFy7⟄K'3/@!B>eB!WL d&oWkѹ0XpVYe:Y[T,dK{(¬@HX ;l#sVui,"1Ou&~gt1 2220tPaȑ8~8풝͛annk;f˗/ѫW/hB'Z2k*TiH^bpTR#d)<m +FHq%:Ž5|Lr1Hxmn,߯k<JZ*`fS (PsM&MTGcr&x\z5_sxsRVeef{'!1^k]bb"thժ?:$9-Ba{8mJͱcPR%^]ve'Oԩctrr2kһwXG%R5jf͚񁓓j5[\r̊ *&ΩgϞI8x 4h:hZtڕ `ru̺t$;0}pQxqQdԨQx"F:B|}7] Efnnףw&?6fIOJa P}7X O_wƗiT^/YB!4c!BɓuX0&ma]@p;WíXG( ?jgQVr Ǥ c| ty3 9"C{pJMqSv]o~$u*K`/c>âַ3*6 h"؍ [bK4ĚXA%Q(^*aEa:ÔD̬guw`kd) VTz,eoAmF,Xr%V\iR]_ƀqZj(_AAVV]v `͚5/УGt=z#vZ$''ĉWs>- xG@vXG׷~(8::2'f uU7j֬:JaڵcRԩ~JY₣G2)et^iv䵰ֆ~b/LZAv5KX۵^?r|QB!!BHdc"% xlU$#[6o <`J|יR~ӼO1lhJ=O!Hw󿁥V+2צ zCI8!n^حƮ3Gw7 eAk.L2Ypf&ھ};ZlﳎRdM41]f988`ҤIHNNƙ3g0bxzzvqqq 2rw^-  IDATR*HSNUVk޽X|97KXZ1ʕcH̽O)?fXnݺ/u 2776mbC*TsΡs2yyRM\+k),WSY:FVctŇ !B83B!0s =gQr9\qp'mr3lv{7Tʔ3Sf:1k =RmqHsٵf~S{kŬRblpESa>b* aKJJ VT):u }eرcLOul111 )|ss9gl1eܿWFZ8ؾ}{~qT\d*ׯ_ʕCdd$7o:Jܹ?楘TACb2U$n߾:Sjڴ)(Œ@u>W>x wĠQF2̎Ok:$צ»zfZ]+, O GɠӞB!y#B!&G_*C ݤ\XMĬRw4gElb,X4A{: g1kr'8)/hgRe)NVTmm+*Urai˗#cRk). @RT߿?Μ9:Jx{{eY|}}qe/*T0cIS\*?j}}}qETVu|z >wy21eX 3([,N>-R5 Ѭc畼y_pwwg0[*$]-Hrb [JXsEХ;4W\B!ĴB!yNqݥcy-|\hV2yFqP'9<}O5Rp0 Oc(| BD.DЭJ*95+k70UN{|?"0j9 ob%RaoIf¡C: `˖-#3ڵk|AbXlE5kҥKF/Ѻuk<\㼦GD2eXGyya666 WժUYG0)MKOOg༽qy4nܘubm61LJ:,:{{{_XlIJ%v:12D.@~@Wfw33XY8arGn_ ]-&B.oMB!0!BEL!ŭ+|l0R|lhqYĬL>jX0N)9U|O1mZ&Xu ,YsD||Dk&|_ptaY3Frs56.*,d?fh]Ṹ`׮]Xh &&cH$ L&c@}<^ $!ϐ'}QFF}>1Yp8::^;wĂ zedx f.\Ŵ:pf͚:Wɉu Ftt4:[7oFFFBU+8:0jkvȋ:.La= !B|B!rT`r)n'լⰃQaI]cߋakUrSḓͫ{ PĻ':A,Ue7[VH`Ok튶~܈1r1ѣG#|PڵYGFիfK,aғ'O߳Q CoU*.\*ᝣ#֮]-MrދYvv쮍888 ,, -;aĈy)f@jXG0MR(8@[LZ:J]|C kJt^i>z쉄M-<,_u b"l=vԬ^#PyF=+y Z1Q2t(E!!B1>*fB!f0O2ܽitN&hd#Հ͂GblpA|/ 6fd#*)F=-3l膺.h5w_ u߯euITm>+ )] T>Ob~sk|9뎺 w\*~ nsl wE`[I=O L\%1~=?8ɥzL#E&J:Fڵkrʱ%wwwڵ ֭c ?N *FÇ^RԠWP1B+ fgg~ ѨUɏoM,'RFҥM>o߾z*5jdB@PP?^鳓k*UP$P>}:vz :wLQw{qի… ꫯXGNu bbzsa-^/_ppRUo)o!B1.YF!BMNQ_, KNL#N*ϟOLsz \=_'% _:abT-I+- 2HŁ-ck1>ŎEnWKvX3Ny`k+Fqo;T&ho[ W86>g$ߛmmvƹ7h5!2K{)ܺuuYYY_~cpSNqYGWll,X :{I$>xdz͛#>>3f̀ح0մ9ދY666&Pٳ&9fqz 6 c$\]]7|pttdXm6,]ENCg}F|A&QUEcpgرHLLDfXG׆ p1,j0?y!8b|2$^gB!!BW\l*)ɽj7wMC%VJ\LAL4I෥El,jŬ^b8: S++΂I@-{itG:8Ӗ:bONǶȥ&~Xh7h 6i#UƥbvNpq3Ew&{1 F++nPNNNXv-"""PR%qh0zht||$'&3>7n:j*LJiwbὼ~O?׮]~,C9s&[?S1e˖ܗ AhӲ7=z`ȪT/bС\.GnpmQ둔:;unxyy!""֭8z9fΜ:a$'K=r4mVifqB$NN !åSuB!0vB!VzEJAa %itjeu}Wa0j%r>֫b|Xi\M^ޟ z=pgqUB!"LT"B!\SظXsW4&<ʈЬ7c6gesxS>u&Z ̡̣lV.6R41l+ {G>k1h ZZb1fwVi':F(WLNCj:,x e(ULxzzb֭B5X)Ç߳AH$aoYG)YehNNNc;UTqqx{{ضmZf]@+Fq۷ocԩY:t&M*ߑFJS^u=-8x|-(5M~sk4U`:f|3ʻԼnzr+f(X`&11yy.] ,`äD"KܹsÆ cPƏr_OB]v8')Jdee1 -((un8::b}6z:;lb((w٠פI:u {AJ B+54ފYڵcZCyXL}j4Yb1>s`ܹN8TK"7 A]vVZ Õ+WСC$3w"00Xe:ފY(WF%b.]:`Μ97=St>|8v: fo+WD͚5Y0:Hۘ5kllOA&LA8oˉ1h<_-<*%­0m_Ŵ~F!B "B!K@)u":?wS.𷠙z?fvD;EiM!kq4Tx@$z|3Xu שLxT%bV:^9-Ϝs(yQ1cbrAjVf:p;y%niuwx.]:Bb~MڵqA={͛7g0yd1H!9;;cҥFY)/qy/fyzzbc0ׯ~8VM[i}fϞ]ۡC9rw7e˗ҥ 233y +WƎ;p%4lؐiC3f E IH畵j޽{}07oG"22M6eH^ &A8*] oj#;=lѪsORǯN!BM!B?:pt{.z5KmM`)*>7 KsS]s3Ph&cIWwP'|+E-˕8" bV/ûem]4#st!0esdee͙X)2Fy| b bWW ،\bB2 ٳ#I*UpA88K͚5#55G@NAǬD" rPAt:>lNKK3R1~x1Lk׮pѲeKq &?fqbݻƍggg4k C͛$%%aΜ9V%'еkWǗqx,fhB0cܹsi&8::e˖Ųeː T^qaƍY cq,++ }En74Xv G } {J,ߏAǒ*!B1#";"B!eD5? GcD<]s73LieʋM4j$@gecRnx lLcX͙ubyL^ r~Su }]3œi6iZ_7.15~@7V&o;a v6f]_EWo7n@Y(h";;u"O0i$VV}3g-Z:yGGG૯8V2$R-Zƍ ӧ sHӡk׮8yɏo>- FǏ...puueJ%ufR ECܹsAHLLdàRSS1|p\p´i0zhMaȑ4)\\\+Mܼy3ƌV:JXYY{2e ڴi:Nt: <ĶmSޔRYaLy7kkkTZ^^^fYRݻ&(Jd2|)S])K $$JY J75 F}͍uB̙3q}5srM+Bt{,7i cԩSb 1FСCXz5|~~~իzꅊ+!)j5 "XǏGhh( 0qqq-v튐NxיzjLYa5~!J!b+cXGHJ=,EU7fV@tF)r:V~ T8Ew\0NCh5+[\Q6KRC%&?n*bs} ՝kLIY"Ao}`РATZBBڶm ]}гgOi66!sEz'NK.F=!%''#(({]Q`Ȑ!2dX)۷oEJ<[n8vO"$$(K.e˖ܒZ~=ƍ:A[cǎe$s!>>@ff&t:\\\oooT^kFVмys)DRO>8~8(GѣGy EbÆ +Ylll_~(U<3+a*WI7ac:I )⋎Τ-B!b\T"B!E,:3Pn/g V0, sF ^& uC|,|?Jۅ]u͠eNSxXgCc厬cpcTvoP19>͞ɱI\`R/)dtYVݪuV\w1qСCk׮PɎmJCV:888F(Wʕ+OOOz Cjj*^|:bYYYEܹ3дiS֑*##ժULf;/^3g41 -;;SL֭[YGɗH$B&MЫW/uaw2QlY.߃-F{n}áCs= jժ___|'OcY駟퍀}V*"** ѣG &-uM6ر#:twww֑Lfʔ)矍~ݻȑ#F?1DFFbΜ9x"((U:v.]K.fUPB۶mq Q=BʕYǰXj8tюi&9h_'NDhh(s}TZu гgеkW\~u1~xyq?~ܠS3Q^=lyW/_Fv YG!UZu". +w;u독!cdG %iYG!B!YB!5=١c/[88wSN \9{Ո>>Qll$ ڴik׮S{ÇøyR7nf͚d$4njK;::իWx~ 4x{{iӦhݺ5ڶm eAU"Cr (o۷{f")JF=w}~(۷oLJu RY۷oK.HKKcŬ-[O>yiH눉AbbL[aoo{{{B o++Wu^z6NINN233YG!7; FojVRC}BC!qc\4B! B,B!B>F#/yc+"+nŏMs'vAXlc *,`Xj5ŽKnc \gܩlpj}l1z$[>ِ }F oږœzyL>K.eät:t:m4,t/_f*U¢E0x`nNNNƞ={{nMBQ~}4hM6Eݺu!Mr|zt ѵkWX p?n*4Xˣf͚[.ԩq(UIPsΈfSLʕ+Yǰ8r4;v85flذuUY \pAAAb,޽cä4 b1}[ncǎ\LV,+^&D5W1>Hcr_M9#B!&G,B!B,TP;|މu [_Ƞәxe8nBR90|`11 ->9Ui>/~9O:Zd5`?0;]Gw}u^:RSSYǰ(ݺuÅ Lr͛#..$*RԌ[n8v`РAo'k۶#$$$>IYĠ[»֣Zkuv_uC:N-UӂtJYB!E!Brtw;XG1[y_j'RY;| kf ojVXc\)1Fiooo<|Ф$D:{ݼyc"xݺuCBBɎׯ_xšh0uT/ۤIzj1-[ ~-tqׯ:a,&&]vEvv6(xUc5aNZ8^[߈ґu|婁R!BaYB!X;k[1R\d&A2)ײ0g 58!r*jfCM<_sG*%MSB$zkLy13I9YzL/ŵ&n0u֭[LJ0>Dp}9o>1ALC"iӦ&%&&ALMCt)))hŘ9s&f/99]taR@2eL~ܢѣg͚5&HQ=z4n: :a(** d35oC75Sz~ w-g\Ӕf:6DsǩE!BرAB!wDu!:]) n^k0y1w+p6SS)C|i?*}TOF֭ Q ͛8<fСCС^z,C||Jub"|0NvY;2)ZnnH'c\w),c B!YB!XMiPNRۡ2h_uU<5 * 4T$3y <[Bw-S;  ظHieK8d, سgĄtQ0fL0u b"WիY@VV:a`ӦM֭R)(En:ѧO81qD$''cʔ)f齬PJ1ٳ~)=z:ںu`&Xr%Vym? sjVbҎu lo?ޝBQIp2ݔB!A8;!B!Ft':-FʸXHR)U]&ƓZ 7[+,43س߻^:{K,J0';w.4ڔ` ~WtޝRBٲed1[SLa 6@LHVc5j 7۷O0 //&Lqղ(se+WĵkPn]q 1jL4 dX4Fs粎AL@b6mt:8Ă"bipt:1ul֧Rnh1'B!T"B!`". ۟UX8^-cNZ]+"E+@Z"p"T".~Wz=| xl$M{IZ q{ *%%q9^3f`ر\lB˗ݝu b Ə=GMhܼyu bϞ=C۶mqFQ-//-b,dddcǎXv-(o%''#''uW"##Q^=QN:##y/BϞ={pE1d2o?*ZW+,2"c:VP`]Ȏ?B!5*fB!B^aN:N ,JճM9ƭ xỜΑ?=Ht:`92_*,]1BNXn\ ]>#dܹ4L)Jcٲe!CAL`Ř4iXG Fv4m.]b6l؀{!hh֬Ν;:;zf\r7(]6;&M ..u?z=7={ 8~8(Ă=L>a^2N.|q^,1rU]i-˕,BF cB!?T"B!x3$M!cr)mЖAN >MgZa^z;|eeM *’I,T7,TEEFcj ?M1<ɟD"ԩSY c޽JYObر={6(o>\zu b$ׯGv̦tw;v쀟XGӧYG0OOO,XuwP1˼믿F`` X!HLLĚ5kX vuh׮]cl,WOY8g.(s#=%X;O  !BE!BH^T#;Jpo~Rt@)~@X{3W;ޑ; >jsyHwF_4Kwt[\=$k.Bul1a֜cuZlQ!ѧO1IR +(Tt1C ¸q㐗g^vލϳ!(* ǏT*Yycǎ`0FzXxN:#ILLDfͰb .*\3gRRRX r1ɓ'G3y q${ ෟP ٮe>F I!BP1B!j> SsMam$H-N wg_tEXGyGV/[|:]__L!\*G'v1ig hihrzRd<Ҍ=/_dо}вeKܿuC X F͛ȑ#JDDΞ=:184naaa^!YG7nYfXn(t <~u  d-%|:K./n޼:)BCB ^… T:!شD !vt\D2f/TQ?U*]U B!B,!B!?V{IȚ[syl6p2O0SykZaqWTW9+)RGa*f  t#ax>R\&"lu t|`txZ[ >B/P:fB߾}!XWVXG Fk.hɬiz,]~~~\R 1c /nݺ:J,nnn(_<o/IзqWzOKeዎ@dB!B{Q1B!tO\WA ,Hpt{.(^a.c'x(J DYd?V\8%dcLY2=A0&VU_-W',ͼyp)1H!9s 6DDD(D,F~cD͛':䍈4l'OdŤz=QsNԫWGeXN<ϟaJuj5M}*xbڴi ÇYG!qF4owaJG/hjV!߬A_ SӵeB!bE!B׭+!^IO? Ro wJ<֊F/YGxc.hXx&0?rX'dZ~?Ыa6M#yN@JłrZ-{IZbZ^>59jׯXG!j3g:u$T2JfBV:Nbذah.OP(0i$t0@dggܓ'O"##ubh4ضm:Y c[r_5|}}:1W^! 999 88G\KHalZ"竽&E!BaYB!:7!2 &uŖJYe9T&)1yj*1ī]pG(_?g󸚬D GJKxf‹Jǹy=B5^cl=4Mn5LrVQdr l3TlXw%''-N'aH EDD~XdY^EA>ŋhԨ~-YJJ -v^=%߄>}7n`PNիWݻw^zXbZ/)) }A^]ӧѰaCٳuB,9QsDŽ]{E!B1=*fB!B tKVYS$'s'?{7B+"٣j(F /'Ku?)h m-THK5sP ܼP&IѾkL'Enq%P JkTq6nʅDR >DVe˖QFad2?~K.>8F1|8pu R3fwe7kq嬄nƍD"a`RSS:F]|uM̊ABBΝ;: 7^ =bӧ-gRcƌANGma8:0`=ؘ5kVݶm۶ٳgTTT$͍K8XfM|z*uNR6l &ĝwO?lmƍlfΜ7cڵSAtm[3q'FifuP_}[5N~Vi/;mtuҼ~[8io2쒘uBj&p_O*+"\Wַd>8E>}R:_"&NUUٽ馛 .HAwW^ye[.uNݻw̟??:U۸qc\r%qN 'xb{ѥK) 4ڸkcǎsٳcI[&Ow^8#???uN6m^z;3>Eiĉnpj+vǃ>:8)mذ!.Ҹ{R@8mL~ߥ/q Pg9cŒS4Wř#KvQVDĒYq3ƚ5ɮ*,hD_3GZL}}y|ЭKKZ+V1=1pk~jժ |L&ӦMA9*?7nƍ-[Niw]|FY0cƌ=ztNi0eeeq7A?O[(+"⪫J[jjjkILZ'x"N9VqksQSS_}r!FYH/gf|&uaP/[6wNQ:e oO:ij7\UMoԛVَL\4~{/h_IJqmk&&[-E-{֮^Z'5xEilzAѣcSZ_=ƍǏ9 _Nd2gqFHҥKcر~)ʌ3bqeSdW_}5FsI5\'⢋.ju͋~8uFvm|1hР ŷmmڴ 4s?*Ԟ~>|x\|űm۶9hnuv=~} ,*+"~_;~$m͞ח- Y d>Kkb9zIYT5ƷO^oA_&oH2j}qa[?GM8$]jk"=Q=N;8\e;_ocǎ[n%uJy 3fip?|TT41[2eJ <8N=xWR'5Z3&Sx-}s1nܸXbEꜬyg>_~y}ݸqcL0!+bӦM Ծ:cvbҥK|袋4ŋǹ}5}͟??RH˖-N:)=X*:^|:;k:H '"q^OoG.u{d"Ψ/л׾qߢ=S)2ʘpNIdUj.9ӛ;gO>eqǵtHh &ӎ1v\xWkⱿTTƖM׿C7|T[n뮻.~߷'Ϝ93;^IIIL4)&NآNek z'|2 :Y|y\uUqG&^eɓ#Hjjj'n-OUUyCmc83cԩ3>Tqqq;6,Y:eEŰaRgtʕ++ꫯn⢆WSS=P\wu1w9d6m5\ӬƝ٬ ~_ŤIڟoкvd۸n3v?-cZ,AwZ~`řxʘzSy]te?s]V3R+ȇ6lX{ѿ)Yi˖-?!?lѼZzuOqQ\\:'kt-nҗ:EXbE򗿌o483?yZz4iRL4)|9ԩS3LNٳgN)777o:uJeeeѥK}]\x>򚰬a+1eʔ:ujlذ!uYO[n%w:%+Z*~_Ŕ)S hn5F~y>̼2&IhM 1'ξC|cMzey&=Q[=YM5~sw/V}$*˳i^ǜ¹yqlXU}ȍӾ!Ɵ{<ZUWż' -:t+".򬼡4k_7|sobڵѳg)Fmmm̜93??p>_}?,_<:uAVk۶mwy}/d2pxGGiV+5g;vYfŘ1cR;ǏyNVJӢEbĈ 6,Mx`T}4֭S]wjZ={Ƶ^g}vꔬx8qbs=8|L۸ufU]1[-0\9q9yv>hgb񼪘hU}z_ѮՒ1o޼0`@ꔝ-[vZ,[,uʻ|#;s=N{?я /;6nX=K#ģ>/RZc9&n8p`f)Č3bĉ-u4;~k}f˲We3&b46Ʒ=#m[3sUpnu,S+_ ~l=-ɉ/[29U6Jmbȑmm6'{D^wzWeŧ)1JӐe:tʉ#iG.F.:M4ҧ-kcX&V^K^+D-'3Έk6o)BIIIs=qNj/:Yh׮],Y$9)-NUUUL>=&O3fhƔ]vY\~ѥK9Ryyy{quŋSڶmGyd|sO1ps=իckŋ/ ,Fnox'Ho}{QZZ:=]~q5פ?aL8^?f &ķh> k׮yų>=XI:hڵk?+hq6ٰaCyqwʕ+S@5qycɭ~Z ,IF 6ksҭ{nt#'t͉L(+DLd͵Q_+jbm~M-,Vm3F.M7zwvĦ.rsh"o ZN]r6PwHon?:u~~ޭDeeDey&*+"*3Lv[[X_1V,H]v|%.4hP&W[[s΍;3M;vH 2$ϟyyySZq]wԩSNj+~mڴI,,]4nָ뮻wIC=#>w}k׮ѵkҥKĎ;vy۸qc^:lْ:Uڵk}1~$_hQ|ߏs&~]M2%:;O֏ѣGr)qiűh#xW^yżybڵr-=#%\{NI&Ō3b'ŰOMQo={*u ZǴktx㎳V&4= I'_~y3&uNd2Ǵi 6Nj9眘4iR4с-XmmmӧO7N? 0 9]tIӨbq=SO=թ8w]| _hk^:n喸$;nɉԩSꔈرcGtڵQmѥK֭ΑVYYYEiiiEUrƉ'gyf?>v;{yӧǓO>ũ 6[ ]fUVD;m33 ""ڴeK:D.U_oR/=%͍>:/izJTgUUUp˜3gN̞=;fϞ婳97|sNivV\f͊3fO?-Kt-9眸 CI`cCży4 cw8SkhUUU<#q7SO='d~իSg/:Z: '_җOΝ;NxcΜ93󣶶6u(#?.n}_^#T:hdYc=rvϋ7FmF99Mߎg}6fΜf͊5k֤NÞ{_W㎋#Fdxc޼ysų>7on3~xSg4mڴ83Rg@бc8cb1f̘5jTjUUU믿/R,^8^xXx;4;ʮSY@#3=ϋ8|Lvqȶѣgnt+':vΉm[3eSmly+ jbX4*x (n|p=:F~E߾}]vrm۶Eaaa\2VX+V˗ҥKc۶mrM[⪫K/4:v:e2X|yq衇F={ѽ{h׮]lٲ%ߎxcǎs̏~:c:~΀VM61dȐ=zt ><88O>(|`k|ע7QǶήS*+"NEZ2,%77 rssc}~ǣsѩSw5O%ʨغuηz+xx7bvO"nnz_~y|߈.]iձbŊxc…hѢXxV{1lذ1bD1" ov͛7G~~ηe˖Œ%KbʕQ-l IDAT8SSgtg]wݕ:7۷?}ccǎQ[[5eUUUwމ 6o֭y{<[ >"NJ*Sg0 h;wO?=:;vl֐*++c͚5rX|y꫱dɒx=):ҥK;z&N:6mDeeη]n~cÆ ~X~+??YD8jԨX`A h|]\@v [ΩfM[nqg?1bDvaѡC&﨨7ڵkp[AAAڵkɻ5ڵkGNNNꔝw[nMޔ9b95k}am{h ڶmtP/}={^{{Wt1ڵkm۶mFMM.oQ^^QVVeeeQZZŻ6uشiSlڴ)z(..NѣGs=:c͛7GϞ=Sgq ͮS jSg${XձlٲXlY !CNŊ+R'ǫ/W!CA@#M/CMUVNͭ.OP/ h:hDY@NZfM<;2V,IQgb-a,ơ:cpR'ٞ=ݦ -fѩS0grivc9Fd4 C I.k֬IL&kԬ,h faСvQ]]֭KgU7SlM4",Y8S'bݺuQSo([NzgS&uЈ favQPP:O?XѼGN0 Hn}={Ś5kR'64S6a-a\s;-+‰Y f2 V4S=^:hDY@rÆ K.YF~M<5k(\|GcGg$,`w=X PL42, xbVaaajk"nmy]TVD}EMMM[.uPG[oj>fM,7qfI >}Rg ,77bاFrgܨ(-DَLdtGD(XYkQe;b ֩nQXX:h T9Kg4QFNxOY@]fIf0 HbȑSAAA fM}1tɉY@]fMnСѾ}0 ,ɍ5*u20 hruUTT%%%3,`4#<2u{rZPWY@իWx3ޓaPWY@:ꨣR'/, &5z 﫠 u% &5f̘ ˉY@]fM}1|0 +, >-+0 ,I3&u*((Hd,I}ѩ>ȉLeѣGl޼9rrrR;6nܘ:NGݬGY[oaƎ:]62L f S'Y0 hT]vC@Y@}fj̘1ѦM0 /,Q;6u‡*((Hd,Qe0ˉY@}DD&u2u1n۷OXvm 81 h4Fjx7SgY0 h4cǎM֭[5553,c4ѣGNP,d4#8"u‡2va({ge,Q92uBNa(8 u,`wf"[N2vGNDdRG-K۶mc۶mѱc)(D2u e4C=ُ""6nh,qꤠ u 7x uRXX:RY@0`@:1va:N e4=#:N R'Y0 hP HPgNvaР 0 hPLP'EEEcǎ@2TUPP:bY@۷o:),,Ld1,A'uBfa`G30 ( -eEDNa`g uz @3Ld"???u -'f[.RgY0 h0={LP'+WLd9,t9uB,Y$u өS ux @3L ^z @3LΝS'|XlY f &Nz碦&u  ìٳgNZ,UygR'-a` S'|z+.\:h f͚ G@ `4+WN@>`ȉLeѣG曑:]6l_ԤNZ'f ٞJ5yd,81 hPg駟N8蠃0u B81 hP{޽{G.]bӦMqظqc[Q]]:h )7u@1',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2',z2OA{I$$F,Y Z Bmdc\х+7Tiw" U&&U& ! R,ӄ6CPR޾.οd{ܙs=}?kfI&aYkfI&aYkfI&aYkfI&avݥG#;ՅW#YfI ;W#ݘ ,\ة/9S c䭝+3,Չꎅl՝;sksݝgp<f8a. XpqF՘s6UsΝ9^]tv{ub͗p|`^Y`qA5V7g0;=K,b9tk.k ^j9?awOlxYuϜܥ7.1k7 `?ʪ+¬g748s].TsͫnZ}Mb_e5¬ ]sΫc#ީ~u+qV|Wlgeun̪c|^#~Z}vk7fUQbO]/ʪ1jq_ulsηޘUӇ `=QQV}̍YUc3ՉCvsγ1jus `=qQVYUcU[[ns~?ƬA8*-o̪cbu FU'w#V>yؓ7e7fU1FZUkVkYUcWYXo٭~kuSVB__7ʪ1j;սk`;S=0<׾1j]pVo&ʪ 术U_,+Fꦌ9M?y1?C6y@aV꿪{t{zpy tjjgA:0j꫇qꪅ:1e=[=j6faV՜bD7vkX5K5望~w{7V\jooziRQV-fU9UUaWmAzl$-j91Ʃޥ[󵥇\Y0T_Ypm5z`ڲc| Ko6[_9k٪UV`Ck):QVmqU5<][n{ 9sι2|e\N,<8o]z̍:Va%cc9.VOW7 image/svg+xml <unbescape\> Java · HTML5 · HTML4 · XML · JavaScript · JSON · CSS · CSV <e\> unbescape-unbescape-1.1.5.RELEASE/src/artwork/unbescape_logo.png000066400000000000000000001132271311410233600244600ustar00rootroot00000000000000PNG  IHDRMsBIT|d pHYsBtEXtSoftwarewww.inkscape.org< IDATxw]e7:@D":bAT(6DPQ "88"(RbJUtvBs7b)眵}]x#W^뷞}ߢVEѕd$&d~]%i)dZL2e/f$K{W^,`^!($f~W $$7= F@AEQ/8:IK- `N$&dJV{ܒ>ߞdr+v楰/%0Pkl'Z7?_UZr=uK@_LEQ,INETuIJZ|}Eўd;%("ʛjy%SyBEy$3ɲ%PMrNj.)b$f~0`xݛGIάj]L/)b$_`^r9n^k}eSMЋ0ɑIHZr9f0OP,25m@/b$_Jkr]-ɅIZn.24]@/b$_Nk`.Mr|V]م EQ5 I&] IjS.d44|@/b$'%'FM-%9V=]v1#FJQ-EQ|:=lpPtE(76b(͒|7ɦe9Z n (e^#4M\_XbSCtЋד,_n5|>əuЋX9I)qUj.di{Q%59@3&ɭ/eĺU((i`~6(EVv1KF܋X59I,*${jG.dqU(3]8l#;]⨋^E{Q$(Ʉ&$(Sh/EQFMk.ݘ}Uyt@/b$&YZk%ywVSمʎEEk"VIrKY*Ћ!3!/eʩ\@/b$&)NO _ʞR^aILRPڒRJlWE$@;9 zQmI~r4|V YD(YI-^"P3?b|k8?3I1ogz@@ (5i ɮZ|Q EQl??;kuЋX?5I&y.ֵZOfЋX5ɵIV7X-kڣ#F#{QI΍p@Y%ɹ/e5Ǭ}-ɛG}`$9(vNrш]j/FG,\Gj=Eі4 Iy)Z~|-G,[f~v>^vI.IR @5ԒP~=/:(3P=OgzLJmĽ("h|'9,<,s I*&(IrOth.O'YV=/4\"|LԖ^fIU6-Zy EQ$ҾԱ$})#/Ջ,O&t)_ݦE|o  0%KA?)92uЋxkk ہjIjS.irEصEQld4/eŲ$//fy֠Ei:xfZEi1beEEacs8X$j;~dsXTEgEEEv.y]tW{\#jL^^*IHҾu@ә䵵ZТtpK=B-J$&hJju EysXZ^دF?2@3[h~(ړЙ7hMkFpMޱ#_a]gna 4#/0Br9}$h[ͦ5ɱeSzشZIae@Q$'W_ގKCCAW54:)*{tc.Z5-7{.w5&׍MGW}t\euI*_ꮛp$_VOƌzJt׮ךw_Ʉ[r=euI@jU"@=`% ЕUj- :T2gv2Z{GrWu`QPQ]mvFoq*+`!KJO%@ PQ7\1[e\w-:Tmˋo<'-<L@E͝xU㌹~k߳2tϞSv _NIwX *Kgg}5Z۾ :Tؼɯi.>ߝ2rt_+Ec0q6KNO.:_:ԁb% 󀮲J)43РZZoU^8֧?_N뽐nE IZ[vj@-[mQv)æȬz]cA:]gg ֲ^YnG@@]de2lz̜Vm:ԑ\tm.榃ud΋I[{M8]"ӟthn:Pgz\ltџ{j(;?-sf-y@77LyZI楃uȅw+5ιO?1]7x!s] C@2gvc;@kthN:Pړnk6N}Co,usE&30//]ưLNQ_:g<XT:Ա+>7Lmu6l']:7?ߟZ-X}lG㬯E!@떁ǍfuZ.FM,RKοm\{k] dO+5h3kik+KV˯ԒHn@)rZ64!XWphb/rص$iiM?zn|^Έ;47o˪mMh -Wи@YuƱj;ȍStwh0?3Oy2FQMO_=xD@t)e1VZ%JOe͝thm$xg޴uc' ]ư+Ǩ;E@f;q͖|aewH֘ԚuКu7nˊd"}c &/:Tv@|]9[=4|di[k@sСb"tr{ils{[q]xd(_1/>'w:0BU%9ʱpKv@} y6 @С"ZZmۑѝ׾uX^￘Ν濧K[v9绍yE@ mwzƤ /w9ӳн@plw>zxY6$&Cz՞c)Fx3sO3OM97jk2Mhn̲Қزf:dwx8Oֶdmڳ\K#Ќ8,a溭ց;+ј4`}_GNv&{yZM1M'g:m|jq@hn~y/q@#aLޱ#'Ouy2l6-O%߳1cSeW,|@A]}+;?﹧#oԽȁ5yTKԷ$:;/c^EEN'G~7ؓ:$GZ%wяdꥍw~NzWc4~Bu;ks)4:PVli|H}!t|Y1F݋bq0R.S[i͙WNhT -mc[ sgX0x|X㍺qc7[32ͫȱij2f\u;ЬtX DgN,bc|to0=2䷗4ި8#1y{;r΍ƭ1R"7޴5i%9zvl, /OXlɞ8vWoB^JK|_ꙀbU[rec^nss6'Cg]ư+ug+'wyqج lLNnϏ~7.뿱ƿfN4R`d'ssō@wLO5_̋ғd7k}tf:H@W݋d*uyW?۟igx%ә1d %^kǺ{|[d(O̘qEӾ՞4}/<'o繧r5yҚ|c^wZGyq q,mҖ;6<3}ns)jϛnw,7@Ov{݋dUE-EƚW%;'6;gղۦ灻w(ߊ7KO_, Y0[䲇# IDATI{=Y˷؟0#5ɱee-ri}6^pkh(9rYejc<3sz-/<['},塡{,s׿vDo(ym2s*4׮ךhQ3P sNF8;ݍ3@.?1cmqCt{v䔟+5s kNN=jveH___Yf?>mmmf5mtt6F[dNr˵&Xzyh({|a>WGg;z@fLMd :M39޼磍)r32X.*-묳N6pì8qbVYeL81'N̄ ݝ?LO~8=P|'|r= I ܓ|o;є ?וSvjh(^̿;R;XL: k9ތO{j(nFG8gɬ>;-\ ?rH~_]J*rc溍oȾLO]K=5gcqec[μjlZ$\iYz=e,Y\37>+Ӟ;8- ]m_pΒ'>񉬺e4&MO~j:ujjڢ#'ѕle{٥ mҖsO1C^YJ?<"oxKs,{u6l.{wLJr}`atioں='7opC9$+bK/^{gyRRGg׎kk6~?gŲˠ'?|lJ^:/_ܬ謰 eSG}4{GKiH뿩-gNiQ/Բ/d nXz+ђ_7)|]ٳj7/gĝW3R4O<yp(nz{g(|矟+eT ƍ>x wqG4JgwNagW"_a+ތjy𞡼M=I;홼CGe0O?~F@n15嘼qX븨g0nsyUo}[sy堃ʄ .rZ[[駟M7Tv9 kve6ioΝ뢳w03ղu ˭ؒ]ev@ٓtwȷ/VqSnye&LȩSO=5'N,J+";cr5ה]NCL`vګ;ʫҟI ;oH"m^S&KhI^m ՗wZ@{1ql4a!]yc. %_,W| wqp>ƌs=7}}}ePNrH:;;?'pB.aM0!Z.KiӞ+2墹nVdʅs3~lXq]Ȏ̪k֩bЩcr3gw+*hWϥ^vکRFm|Ш0'EKlR^Z2yH6ۦfu6lnvess#h<:׵u^|<|j.6.oZk]JSy׻ޕ>;ӦM+00/y=vy [Gvi tvcG6M7BЩ-mϩɲi+~7<#<+"sLN;X::::j?i٥4nʫ ԖΘ5F=O;YS'#eU[~])r>4J]9tv5ҟ?<#3ˮg|3)m3 Y.>`٥4?a0hWwnj/2N ?^'{Uv)8qS)e[n\xr-.$wuW6h bЯCwYwiyq3nBoxL޸^)G'|&O:蔦W/Yv)n_>5+?΋eBM4)SLK%/|{(qǍetwWȸe\ {2rN~9YfF!}a^_gg&wa@N)M(͟hr؞3ru:q:?3a„Ke޼uАp#9eԆo1-ӆq>ܙ/[O:hrgs:茺U^ے\26뾡w S;L}nX]v%/2f̘Ka]vvm.a{`޾=˯Tߋы"fk~ucy1j^O֥WjnvfZsƕc:{yCo+w^:;oG=9#.j)G]ưy۝[irjZZؕs0.oߥx3j6ܞ\4&iB?ދ92גsi{pUoVYe\xy'.a43^kc줓N^v,~8kfj O՝]vKލ_֕Qޑwxw>zxwڬX$5[W:tQ=;ԓfks`>G]_ujo~G}R?>ܙ1}3ȴj&7 dEs۲MY,ߒ]>ҙhm :'3b8;RwCo~6713Ӟ]c?|_, 3wBO6޲RPri/2n:tMKKrw{6W8|z^١e0ikko~<#ep|t(뼾5k[Ǯw,reRE?[ȪmkV)Vet'r=E> zίyϾye{WN>`meаN=zvC,z]Yi5ZTǍS4=4#^6ZWkZ3_!CҒ CCɿӟoo j9眓VF/.4Z&PdM{uW_N塡ꜹik+ִwXJV^5+]=7fGd :K%9{y ӟ}f+|;po~sWRJoΓO>_3fdVȊ+-"[lE:ݹ/ϻhX,Wwc׆=65iEuy;۾u`l=PF+kΛis؞3vd&MSf+Q3s\ve+rW殻z?jx?tvwA{Xj:ЯC*Q_fu=xuEQs{Qv)#G'ڝKwc_{$Za--_;.^_vznzBl};{|3݂+󦁜ths\}ό1~D^3Pr.cXpLO%yZᴜw Yٳ@n֖3/{oY΃ "đ?jߘw1`¢s=s1ǔ]ƈ2eJ_uQٰ.}}}e|^nm[۲;.3Oăge7OK39ZZχJ<Ɉ;dʁ5j9f%.:,7gv-}jVY|'tRCo}[u]K I2{p j̙Sv M3oj,LϬ_l<-(t8`tAKK>?fME?=Fr!e1jZ=r!wQLzwһt{oқ4QJHsBMRIf2>김!Y뮳oc̼>u?.:%%%:&bq:F }еZ".M8Aϑ}- ǢNA&. B}EGCmR-)˗QڵÜ9sDGh(66Vtyą?XDH¥t :ܸ@ b*a4tZv^ E߾C=@ BՏnkƦ#1p9xL\\7o'Nԭ[cRbb"BCCEP` v_ ChFyObT)KI>@>~3_t/Ɖqh * :2d``E]]/d…*ϟ?GZ$Y&?An,,:F,C朢9(5s-qw+-ôAX{2U)ތ+Xy宫9yNҥ t":šnݺz(%#Tmb bH#ER csǚѦL<lu a`,>|NƂrEJ- {ed7ڈ˟??,X :ǣ^z",K,#VLLf<0N ӡv NI]u&|a".uVcŕNĂb``d̪_ٍd4 ,:G$$$^zx(*k֬#o&:YkŽV~vG/˃^zC?"k.e>ajs+ŸX7V(&MB DD|Gp()"~ T~")z:i):WT '`ƧI{*+ޠ;bޡt,* M'LK\2EiWN9Rt hٲ%Ξ=+:J.\XtbA[lStR;ز؊dXUUO_h]qx͚i0uU5PO8y{#kMi_r#>c^Ztr Ixd̘n|0{fB6"8:Bˑkݾwc8i<*=˓ڕ\ΏaPDs9s(O0Av~p̎sG?e):+ Arzb04ؗZ+X߱pE IDATCgNLƲ򟚐,_\hTZlٲ޽{07Mt8Ȝ93DG+{щLޣ!tYM_8ŒU SV.ߍ1)ei{BBZl)r}d9ӧOKԯ 3FDiZмXz9^󩃓y9yބ ;f'Oƞ={DH6m wܢc־}DG7vvO{(?qa$.mpq96a"e܃%?m>&OB:NWX1\t >>phܸ1\2}:1 ~:{=Q^֭[(P/-Ce&El Joッ ٔWvbl7{ӥH_]`A˹ib9'h4XpΝ;˶a$[`ƍ#P ܹM^tԹ}݉;ЭF"u`q֜V]u?BUp؁.N;z˗&+W˗EGIY"&&!!=DR {Zl&Q]L8DiQ>"ea;0"CJ8Ac"es圼&cƌ9si6j(Ys2eytt4˹yۅ=k9E'"vtɟ$3&.HW L Oën|ƈV端B̙EH#M֭^zFK.ɰnb:jeDir;WZѲD<o!:4j0gk0B&P*]L @a~cxư6F\rNUZ5lRt4Yd v%:F͛7_-\PtJ\زX{{V?/1$t z|)wlf:~?. hlHޥhpTXQtTA2e$:J*U O8v>C1( 2fbׯˡ8y>"oV+:8\hTD]zW|9 %Sh߾˹F޽e]s̉pɗs>}FqO2E \E0I]fͥ{Etc ĵ_* ߜ]/|m ^I&&˗/DZcDH@#wܢ+W`߾}c.Y%*AmyA$e1HJu# ii9cxKX)}t #bcc1b1RMbÆ (S()2m4C^bYs%}fϟ}܋N.maɢcP <](N%Hi=VE@гVβf1Hz=~w;ÇQ`A>|8f͚%:[Yh  :yQZO#n5qgNщWѤ/Ią]"q.!C&+kf9'aڶm+rܻ-r>l0ٕObرc=}ΕɽD!W>-VU ׿>ϗ~KD>XKy.'0q@̵B*矋jW^ŪUDxk&Mœ9sDxk#G)r+gY`yG؀Ÿț{_!:jӡ*;O&R^2ՄݫeDVV--[VtT1b\.Ūxb7NtvQY ԉ}®U~h#@$E`PGevсYESoU냒(kmưVF$EH1???lݺ}孙L&ٓתYɲBnk>E{QgU9נx,P.xC Fڵ W^#E͋cǎzꢣJdd$~G1H&F|#/@O(-tz`@R]K;1gK`)gzy ݶ`̓eIΝ;#((HtT9tΟ?/:ƿ:t("##%KQRv{x($؊o¯ ȜuDh]݃?\\JI.ػYb?CȘf/:BI}zիWテ^/.̙p1Hu!b? ^t'+BPִe9 OM1jW&97%&76.`|+C>3gDHgϢRJcVB WܹsE [:wu@u-%7EdVS`h ~lMU]0߽)kXRI%Kԭ[WtTٶm={&:GTT&O,S.** }d^DHL !4⋥5Ly̼\F[*A[m~ISV``/*M$D۶me[(-Z$:1}t\rUVc]-Zfwlz2\2??0?pNF aSG/Oj߾@aAaj4jq 2g)\_v Ǐe˖~:Fl7y15jxQHFt6yɘEֽ9E'ʘU!D$eyE*UDHŋ ޽{}vɓGXo0hܸ1޽+: RLѻ 󃯿DA\UY0I"beb,qU4<)/Gʙg5k D].6mڔ?7C >}:Ѱatf6Ѹqc\xQt78CSLٴhكStRF on61 speܩ7WN©H'sc e_#j֬rq<~8~^`` Ǝ۷ocԨQS?Պ-Z6@tzVx Z-0dr&. R~߮8ѥZ"mKEz]BlV&9̒& bwz)$$~yt9ƭ[0eMovm۶Edd(9qdxТEw彈#` fo FOa=j%^hݰ4nk*rsh S'!1jֶmt+t:+W.t Ye*)PΆ\uP3.oZ9Ϙ1#ƌ;w`/v۷g9'Q>ΚKfݸΝbM>rq;:~rP,e1 +gYDGlX7&@Ϟ::5#U1/X ϟcԩȑ#l6m۷ojɴdҬg$Ei FH/oyKNhR242"!OiW*.qf|1v^ XS%}8*RbE={Vtv={vƦhPvm <M6VwV[FDD(p7Fcy}2$\cH43u7sӉpgѮtyݫ̈.߼_Fu'CЮZZ5k!U\r^P!L<wCмysUsɄ&MSX2M+z L^rv<sDsPϓ]8fG* 0#g`ÙPT'UrTЯ_?:u  ͛/665kġCDG!~Ɂ3Z4ʽ$O!a;J 1kdԂKeF v0mnl2wxDGykuÇS#G4jM6E ?.: Lrz>":F<Ӆ%aJwj1oG0-呻W[3&V5aA @`p96̷ BP>gΜ%''#C Z_hPlY4iM4Ar堑Ote4l?Tjގ`T/Y3?3c"/'u(ZN!cVu,ua'I8W+v(Xe,_a By 7:aX9AѣGcڴicA+PWիA8}mٳ:udTDE=VcOYjۍAHӆCjƂ.s>'YvNS-b+?UrƍFȿ yjՐ={vѱ$m֬Y9r$\.x?F:cƺytmeeAQsc Oލ6QHXb-L\ձǓ6 rɓ'O5kV1ޚ^Cv;KBX~XS.4/$>sI~I} f`@|D)6,n\"ycjeϣŐ)Z(_% ,~rNv{6$) iuE({7Xѥj"9' c_ `NNc| Ns)DFFnݺcf 0W(EVc~yOѓn4/SI0eETMٍiC͈X+XU [n-/ WN*tb "x@qqqȐ!!/_Fǎq Q!([]އ>nof1H| AXn#:p:XUEw_ PN=ƎVlтGxfzʙ3'?+ܹs1j(X*T &vкL<wnB Ena$M\2܃";WZѦLmAa~P'(r@S4iÆ c9':eS|2Afth6esvcX魰'.j§mx'ߔ{Vna=F}Z±Ν;QxqDDDBf&fP4_4i0oG0*Tn9O|ƠfFl\k }v- ,p{LzL\a;OX+>>]vE˖-+:G;b3k4)ck`ܗA;ѭFGA&7aFZ Lٴ? WQi$tyڿ?/k׊BqK^*UT `aD0J~r~k&ۜ~Q8rv~?A&O5<<# H{Q2˹ ̟`YoNNTF D|-InYkƅV܋֔*R_.:_lj'DG!JW~J -K&b#"M@ Fx $/zSv-ӓa 5h.b`T})7o^ 0d.]TI {ѳТP?1H^^rnJtcPDs8tz-ōEѶ|- P#;[.U/_ɓ' CDu|/0?dDJ_+XO[''/Y{77.b{U:70xR]z"""PD :{͉,&A׮3i0{sPn hl H5|;}Ȏ0wf{SH >ݿa 7Щ t~=2s+5ٍ=kmX;/VS||7`rdt9o@o/Q Ap2׵`ń>I๨$'b0s͋c< &~ `UT&-B\ދdTV  ĤIX_#{숊x9^N?csI>l^KV CͲ]-'usO~OO3Ǽqf<}=mAy9~9}_>_>>< %l6vލ: {۷/N<):͛'N@%3Zj6I ,i#7A NIފ^IzUV$ЗY^9Rw۬gL~I$?f չ}݉&Ax̷^Ұ'K*S_Ecǎș3' .O>;wd9B ĉB9f!?aV(dA,rjUF +\.`\OGEG!z-A'h^i*֒l˄'f͚8rip8~_FllHPdIIVStWZqEo/k.-nVl9?!du' JBBX4)Y*{-Z!@FQt4;w.ZjO*jÇrp-HZvɟʘ:km@rB9v`dg.]j,D)Ĉ&tS꼞=jРZ~䦅/ϟ͛7=ۍNjA2ڹɢcxL@PB3j0"z*s9\&-ˆ>qzؚ0&o#J֬YѠA1ddɒ8w7m۶qzNe q?o=eT%{-A~12mHnAq,Dt%bHKu{4^FF'r):cƌQdIqRb`ĈcLMn襫a fXa+XЉA;TM&U须VK_!U5j$)ZBp L:n iشȂʙ;padͩ3u%!S_0Q:qCmh[.&!ڞYF&ׂh0yd1$Oc|2*U$:[}6O.:ɜƺSB֡y7-{Z,FhFx-Xrh zt"r9]hY2iĞmOػ txִiS+Wƅ 0k,g˅ݻl6B qE1#o?] EȐY!Ȝ]ُ{7gl%S_2 d7VͶyxk"87Nϋ&/F@M 2ɓ'QT)qRmܹ8~IF7+h9(z`ƺ`|GُQ6|ϤnI=4Nerk1`?unښ' %4>˥qqq %.\C^zaȒ%8i *bQN"B4- A!ʘ<'h^, # @~qZ%țtH8ǎvِ#y 㤜sGn4թS#*T[nիӨQ#l߾={D``8ib6Q~}QJӑHQ/f' Oމd7>mcû9":B`߾}(X(\rؾ};.]u늎1V²eD KwcBl1+\z[}e/5n_wⓦFYI}H0_ :}!0XC фp\*>>>CPP(ivԪUKfWZƍC DGg?͑]!4 r+' &ZګɤHv\ C|ʜݿDF<{,!7)/HFn6-cb+ya|9ݮeԩS(Q(Ѷm[;v 'NPd9!ZlrN")g'qk(?€,n&ܘiڕO=_`$l`xx#G;vLE6k֬7nܹ͛7z#ylFy(u,0J}Cv5PƁ61}sR7t"LY;O8=ưFl[*I`DD{bڴij0мysl޼ǤI+W.ѱt}p(2غD^foLU|?T 761@=DWM {{0]ʈ[xe*UJt tǏJZժUCΝѶm[dȐAtt3`,ZHt R 5}- ؋#;.o!cVؒ؈Ir^;:TLyds37lӿ0ZHq~y9cGqف͸zV_yݻw(U~'̟?CrrrٳrʨR U+BU{~hZg^Llr)#|y :1j(1(-Y I}aʚmÈ{B|P9%kY ɍ\xԍX/8}oM#J7,D :GAEG!/3L8p ֬Y#: PWA;v+'/rw"RӉs]xe˖e9'tZ2t&F݉HXЉH5=z&MdI%;w.*WQ$M'mSZ WXA :ʕ+WСC8\"'4haÆq9Y:=nmfj#9E'"bA'"Չ@yZ ŋǁDG!78CY/5 {|%"eڵkѧO4ZRGiӦ޽;D!%6E=>Tk۷/'2r0|-Z­kN٥)zȜDEZ0ydNlәΝ;Q\9tܙ`4]-j42AD1,DDt/Dݺuqvcǎ([,ZlK.DX/9pblۗ܉H9XЉ^ȑ#(V-[&:"v]KFVpeёTaTeEXy p;) :$$$wި_>n޼):"xӧOG|еkW\zUt$"U*g{qNDʠ[1| &L0qdŋXd ֬Y$qTDE=V c_Ѡ@L2aĈ4hEǑx[˖-r"aw00IDAT*ca:ԇ(dɂ#F_~ Q$*, ݋M6aϞ=HNV~W"(YI凕uE "Jt"4 B=0x`,XPt!, "##i&޽F#`Ax0*RGC^IDłND!իWG.]жm[S>"""ÇsRN$Cer?7c,eND‚NDWZhM"k֬#Çqq?~QQQ<`Ѿ`)kN :QyVEŊQNԮ]UTXod2pe\x.\ɓ'qmѱ Vc~L[NDD‚ND|}}QT)/_˗G2eP`A!'Fܼy_yeܼy.q!([]/:G̟r  :D̙ »ヒܹs#wȕ+2dȀP $$0 twn7v;l6 ?ƃ?/&" #]t[D1RHZ-z=DfK#CP2OHDRrfG,e?TƋ"Rt""""¹#v\=#*|SH}XЉd2r wo -j51K%O4-MS%7MzV۴ iڤT=PjTPP r0 0bgf$;{L2<$3s=ӿ~+6'X2~Z֒WĆc~w}jw t` tE?%8rwӽ~>w =Šx@@0wlޡXGX2Zt`ttwe}ӹw:0}: }zWz`:6vӮ|on:G{яL*=Ǿ9?K&8]ykӳ";|reӳ~ˍ;`Y:횊뺿|>C,cOk?g3_ jI<$cې| ?zУ,/%M|c,h.&΁&XO;oC?zǷg߹q9N.g7Vs=R t'?r\^9C[w.ܖ#Հ]X %椼_sn#W_#v6X_:+r'>l\Nkw|Go_Ib{q:1|䞑'{|w[vy t&o9. ypzyp>[ۓ7ݳ'_ϯެt& 9s9r-v&vڙ<|D|=ߒt(`n%t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ P@: t(@@ K2?0lz q<=00<t($O ≠lq: <=ѡ\MCO3nSKrBg < ̢$'w$yhi`F={߱o|ڜMk%yd'tz}9h}k>̖yr6wXm@wX{t z^k5̠O>~k6̖d-Ir*j>l{Nh<̒]moz\A՞ f yr-m0iGl'IkmcKU fI^{߽>~ 5̘ѷ'fQI^3ɉ`lyk=+u̶^ ILqBC,ٝGc`cy$i*גl`0+&ymcp1נg|W:̘"WГ$_IV0̊'{-ŋZAOoZT0cnZl'KXAOYIYT0c{w/^ z|GrRɥ+d${\j+-)0 nJ$I {'ɄVГ֒gMPI' $i4ɗb;I{lR}ƃ]dr$M2Γ zoIr E\>n߉m$䜉sWLIZ;#_*'dFם?}_Z5vjy$'r5kq㮚UmLrgZ|s{W$Jr &$}Vu>?y]P$E'kI{?I9`'9ܲkb=Izw' ğ']3kI{DK4=%v]SkI{.{87{ͺ $_䊡bܪXǬ䭵$$h! .}Hl=IK2!\u+m@O$vwAI.O҆ugtC2ť=IZk%:qC'-..IZ{WLg`]ٞ!s~,%=IZkoNrs= “I= )IZ{][>,LG{Ad/$z瓜S9Γ⁞$ʡg`\q[VzZk?䚸.{2|Ak=IZkg$!p\8 *P&,@2j˒u<~&uINzxz =rMu'IkI6aܞWz =JLCޑ3 Z:XA?Pk$JY?|`AIJ֡uޔ/5,LԽI.3 .WPg'4ɺi ۚQ㝽D<xuCڏXCW'yޠC,޳I$R o ;%Pk%9#əm?_,p3j>CmU4뇻h\3 I^Q |NF-Ӈ|S è$i Qڦi?>N9NS~&I{a\- iOEsl>a0ƒEX?z@!td<t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\@t\ Y= \gVLyCɦk\eN7@1@)XPǞQj}WUjkrL-0Gmn!0$:7PǢt[(E;ٙgf[:&iӍ`zMx5ɫ…$GjƫHYBB.զ{FόW3~_62V`pCcbRV^m\IOf:2>B//O7ɧ. SV .! Ae ?_^<13\e[9ך;D'y:"u.hpqdtE;~Ke;u(p~{Ybay5@\djUQQhضHxůeg{Sm/JRj2 XC\$/WZ z}t ,x@.XڑG.׹eb > ziJoϲN#UicniK]@\%Z,זJXOP {4C~Ggiq Zv'&iӍ`#*{>iϪ#D\6&Y}ҝ-R:`܁R"-ԄalcIOLUx-C@sOWP/G9ov`Eb lTG(-ԟ]V-՟Yr[azge"ו-um=;lXr Tnt}'bN~U^M|2CYǣ1{.Uٴ*O^"?9R =#8] \S_c j -wE*-EںjӪ<ūgX?~ve2u-7JC7гcբMMx&SooE`# 5.B]o?UvE xWak%cP=`2}oT],+G謊Ymz]f~ 3"V<Ƀ\|W;[z4KkSxH,g[r/(J*{YB@< Vf+[w vna%׳ѦB{"UCnr~< kGLUT #%nBmzUiC7ط I/읮 ?0isҋ",,ۦ{f~Zbzxã"/~)æxe?vp{>MPÖ\VX~!aZaegA$GmTRLҺ9lhlc+_攽4q-:|ą5D5֞9`J-u!d_{k\fO7oQ]:Io=DqR\hO+Mϵ?tg۶)!4u_~~rI2ӈJvU3OS}u%,㠨#hٴ54%TSuw~Pqj?STES1q|>i v[';ˣKYT5Lm{D*=U{/C ӘYq^Ǿ9ҀZ.c)r+P TJ+WNʕSU\9EFF*--M_gZf6lؠН8\.ٙn4YETΫ6$Zo}ڻk:x뱊oʗ' 閦/?ɱPugCj֬4h5j }'={>c|PH ky=fgkv:}o,So<'dG=h6 <.l;MK'O&66VڵS׮]u*<<Ú{Ѹq4i$bjv!bR)aq*Ӭ  }OOMbZ69GgƩlSҵ\Ccǎ砓;vВ%Kl/8ǣOT|!qeKp.4gIoԔ粔E|٠5z[n:iJckTxj5i$իWO a/_^~|r?of*nZZ9zvvHT"T;=~]ޫ-HEvP̱|yҨ>Z40?V54|puUaayb iF))+5 iҧ񺼙/?CdzQ<-O8{Ȃ5 4" e =v#G[dz4Xj5d >\uɺutN7έ$ek#25E%>jiʒ%s$#M4$]ZkC܆@@Zaz8ۇ%)=[SW,,:^z:uׯtSN?_{ OY;fK9/\Im5s2-?'z5&B,י;rTRy a.I5jf̘J*9ݜSVbbbtRrZ[UFx %1b!Lo~m\:zlWwEʗ91u[CDi31805oOOޟgUj޼yKnJtE8$X67M֎M| ~p}/^ eK->=@: %oKUaԼys}:3nJeddvڷoM9cզ5sTKpjiLiJ;[Pj2'1^B&MP6n9h4e9R}۷f͚xR,JLLԂ nimΧD*k]aں.Ov1v[ɇM-KFU!չ,\7?~kVF[Dή+UB߆MSda%ztSJnݺڶmM9;D3.yOL,(X\;:Vdh.V^Li \02=MKRtt>cuQ 4grZ?|k;xX޺`3<:_?|O'X_w԰U(EQEs5y=bYvAS&)=UQUĩE1~Ԟ>=?Cb'CC/Vxx[S֩ڳZIӧ~͛;Kl߾]֭so_]nBC~K^d*g.2‘]8'RGmGr0m\t^JU!nz8yZVz]?cq$%$$>Sf͜nenPhcPR3ydGvFdKd]\=]hc:ooC/cm2"11QK.UFn*WcdžqɇM)oXz`PWvipR(I:dwrvS yAFjz]uCvlt\9BH }% V4Hwq=ŋ]9g~" 6Ԛ5knF)oh2%7Gji7|aHWG+T~i޴)ISQC?F걗mwnޙMm^ӪU4}t[>}֭[U\ٲ _-Z$)+S2d]H&ŗ1'>͛MT0]aH^{D)5ԎM>zC?N|l=@3kԨQ>|u/8q'իkܹ^>}4y䀗khCs7%ꬊ'u2Y?84P'uI}^x(#d ױ ե_dodKO{ 0OJJ҃>5jh' sIڵk7nl92ijSv jruwosY~oĪD֩_>/X{׽a1kժLb[}~j֬_~Yyy{koYg2lsv^]piroU)zgzeD1 ʑF@?Fi׋sսIrмի?TDuGeggWǎO#?oVh BL~3,6)-y?G'i\%6Pgbegf1z ҃Gej`TVs@dd̙D?բE k%*gjQgo>˵|U#Tul YjW7I゙eyQGgͥ !=O6:&'1vX]ve׳c5jHV*qY۷o@'999a<\]z zyts$Iϯ4'N0S=,\jz`ش*OݛhU7HuQwlٲEM6ݻRO?r :y>\CӾ]> 隦{Iֵ1%tՍ^^'ߌUŪ7J\RLq떻[a1Fz]?8 餪U7|zmۦVZkdb L~:lj uEHΪѨ)zׯ(U~cH2?^q &TY鄅7Tx?pwqV\iIٕ*U h/_<`e9mLdY;k(`q`_ISzqpRF<cR5ydK=ܣ!CTS_v.e;οP q/%^0]u=G,Cʴ.رs>%Ȍ9R'O$ۧP0,Kx饇k;z5x;ܞ|φ= gi\ZRkj-jԩ-"vi)ffu::`שOXItK?Bq][ ҰWcU̐O QF3 *?뮀{^xA_~e凂ٯfY: z8ʲQ2 /M9-_+MkWp@X՞ǓK͉;<`/+{[nV^ƍvZ5n8`eoڵz',+?T&z3o-R3lc/\~4g>}/D{Zb H>ٖGǺ@;+WN:uc Jp9R+Vtj۶rs3(w^ɲԺ8Lf(3NEzzj:a)z4ˏv+/3`Ej]VIiMF6mҏ?XװaC}OUF ZO>ƍgK]jLKevιM]ko4`44=? ]eW$=}_/V+׉xJ:t9s5jyiժU-j? :TGPtS}9pOʔwXJo,u-FZ~d\s9Q11(kOH:tH_V-ܹ_:hϑ?=nVLBwڋzmD n_h>iKtfsU~zXEF[xfOfj,啢JM47|cI?j֬y^zѣv:˒6iޏۿUp.FLצե( fX絩@kh&QnSJכ6mjYK.ǟ]~5j6oެkyvv:wL[㲔i]tKK':SJeK.UL=VWm_s&eilK/pڼyԶm[KСnݪMI&TreK*Çm۶믝nJH4:F]﷮imdohCcމS}ïR4yCcbl02M-w_Ҟc?tgZRvZZ,)vޭ֭[kN7%qG &eodkt/Mq^'🼘@U<F.Wp.97Miz,<{kժUm;KiVB+{(G.Wͺ%d?4]rDWR4 ǖ1 5zy^>Q{F*:6F`zHڵ#lKYGH1^gWͥ/;}8&ХfMiU.Z+Lբe1!{_t,o>5oޜo7M}CHA)Y`z4eIIh?oB3)Jh6=? ]i);h4Ky'NtT^&XjڴiKrJjfYz—#N/έ)%v-/Mz*S)=5xN*5s's9=bZbű}O_ҒrX7oVݺunF޽[zҲe˜nJXuiR;;rLΫ7s tSLӊE{@?zd\ή7:{p.IOOWLLϧ &'PFF)UήѼea{sCuDjYmWFݯx*1qz V>Q>8)7GZafT *KƍnJ5Xۺ^$ 5^)T8/s {:E~ NK!Oal"^`÷yz/ȑ"M6u*6mҐ!Cg9ݔRyTsɥ:GS>KP }|:UJVh/l.ꜦScs謤$\gi2?уtTX݁o>u]_>a$~'Xpj0rܙM\o[S󢢇~OIs}GYdjΤ,zmӧ&Nhkm6=Zrsz5 C]vjԨ!ϧ۷kΝ*n+Vh2^I|䠩vuXI] > ]~*0/J(ij[7YTJR'1td[ c낿`;t֬Y۫N:>}can۷kڵzwkӦMڿuHŁ=~-em/\W0;%:Єm CDϼBL75L|a|>SiQ1:Ҽex{VBgeewQհaC͝;WgVZU_~&Nxka˕+3gj.xL};e¯`ƾKsEFڦꗝ3lJ'RLMz*S7I::+حBڴi﯊+{ZbMRݺuߪYf\ 6*8ۯO߳2o{\#=f\mϭi9YvdkZIŔtԄj]3Im Dp%Y[}޽?~4hK/T9t$IW\qKUPP__|ykVc,qCg.Z3btM{v}c=ҵ+ ^Bɦfv'iH4}ua72ZK ۷o׳>+BUTw9ݬiԨ>s+WHϷEaO>-cm/0ϕ^Cթ=kLSzo³}K=@>9u]6Nւ/@~ -sIII?|AթSGkְaôn:RM6Ւ%KXY[<0vY;$n#RFw2,ߊX$ӓ}5aXn+R #e=aҠctԢ% @N4M-[LK._|^~Ҽys-\PN7%dӒrt}'kzqi*B^8Lzto N|YjS'ICi7DRʖwmY|7nkFcƌڵkC&[jE(tnI\*5Nw6S0~'hj^iKiCצV)]`sϬ졧UVZzeuX[nZpa/ԢжgOhkaюh3hG񊍷߷ln0ݖJfVi`T0YqirmɷZwkŋZnahԨQ9s"#K[dIZo>)(wGta31qg۔z4GUJ+!;44].O ?V oٲŲYfi)oӦMڷo_@r|Z6^zQ!wT8ϣ_$v={ٷ.ieAe Q$͙vO_doPkRJhg}/_.]̷~;`eŔ=̾VQfHP9>%5N Ez7 PK4F+jc7kժeYفt5hjԨQLJJɓV[nwgԴ'rCg&-JP3yw_IUajzm_OK׭'kG~%x޽j?_ҙgiY%z5vX}g>^uK'2;¥ ^zzjj6-?_ڤLہ@R{ԥAcX?mx?99ٲyް0vm]Rkի5hР~=:eɎ>[Nfm#^6N$Mrيm GtMRݗlw[v`Vmܸ1 СC׫~X֭Sz,PJJ%eŔ<:v 1}{ޜs an'=D>O}[Tպ{?#تjݺ6oެ1cƔx̝;Wsεl7پѧ _(\-ڄƑw lvI45c ܆@1.UF;=R)=}z]vm@9A}q*j… pBKٳG{e͔9NQM͑"̝@ _xf]WPZJ`'2fy/_.Ϻ0o+[f̘-[u֖֕;Ö&?ϳ4/M6cǀbJ|Da}Ұ= ejKYj{QfZ=s&eq$''[~}4qD[ UsQnݔ*@Q.f]d3x^ }S|2s&gi kP<̡>G.G={6[o]iU^@wnLL{ SsZ3pV^h @咓5~x&O;m~3$(/IOg|0%[zz5 '>}pq)99fgyF}ͳtuqKF쬊Of\ 4F-[:ݔ޽{_t)/~ .9J9:t>ռysmڴÇ5x`]ycĦuzݑO,ux:w^5nXM)4=ӪVƎyAۥںQLZ ޽TSh?~U'xmC]s'-l5+jܸqԩM9]v_״itbzչhs8 {#΁Թsg5oztRttbbb\eff*##C,L?l՘YssVQF\X@P4{uj\dm/}p4໅ *wiڳ/wO:܃@I_Q|^9::ݺ^ϒ%X@~ÿXA~iM/}kQp _E>X@,~?G{ lo~m;QzpO>fPLa!N7@soOҷKnt8Oz{Z^IOejЌ 81rSh"BόSBw2kW!ڱqve|:FW*{IM6V.s8 ) rs4Si~ů?nJ9`Q.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@{FlIDAT:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@:.@IN7HGRӭ%ꑔt+@C C<8 P"GaHDR4 "I7 B$q *mKgB UPmr0P89n+JKE tI2M+I=$k Ôԣ kȁ.Ii+i@q.8[d tI2MeIy [HNXaLԻDPM6MOI (vSx+iKUa4^p7Ssf?V] "i$o }rX N$.Ia44[>W>"oM;ϡdE?.a.Y_'$aqKěz\a|FIJ-ʿP%=cK,)iϾVdCoF%I$j[}IMoWЏe~4;Ij)iu`Z0lrh,ik%P3it_0zʟgER02$͕inLPQaKj/vIW)Nïa%}dfKP utfpF$-s~,0IjUx52$*4smD0 CReI$]P{uIe%I?h .R?G$풴C5C0kT+vIENDB`unbescape-unbescape-1.1.5.RELEASE/src/artwork/unbescape_motto.png000066400000000000000000000114211311410233600246530ustar00rootroot00000000000000PNG  IHDRsBIT|d pHYs  ԥ$tEXtSoftwarewww.inkscape.org<IDATxy_?IH$CbLLW<KjH҆5T(!TcWj(mҚy H绝}vsreoy}Z-\-h,$w_67=*,-Sv$_ i{@1-"MDR(k"baQɻVN/ҳ#K#%?ڐ0"));$"N+|s%݂/MG`y`e|y>zHz+޳z=pzzB{; \FIჱ"z"⟋1ou~ ף{15S?ED=48x:= :5!iYB|Vi,1"iLa=r|Vcj Lv'>`)"p$<\wE_ mNgoIc62*[@7>I=#Tp37qgroV^w0RRh$pg'dI06pl׹V2jev`_`-3p0'%f,iS`4ˌ2V-nGyM\16=ojf<_I!^鿧qWa\_J:vf^BЫUQ'oXbqJbMx)פ75!+ DMc&&bccdaFK:`rgW=/z)+ QDi>)++knI>gs<^h 9"^h\ڮ=W@x=/1/;2xN uMc="5cU $uٹwiJޑ<$ gXCʗvk2 {_'gcy6] ),7n*舘[{wQ~cFl <-iψxGD*{eFlIx}KI;KhJIԷoբV$ Jl^&4$̞ύgelQ[\{xvLJ)/{UwvB5_L <#i4-b#b8pKmSs`ջPv:{A1C҅~7WwgIEG}H_"bp+!=IҐx.Fks 0ΏS0 I}G~7-ɐ 덿55]_8 DչgqXIӀ r‚x,f!2Xsǿ'6,(M"5I`z|ڷw~B|.sG3%T|IFDܘ9MkWE '"浮xy7 ;w151 6] 23%t/`Sa֖YOŴQM[l/Riiإo=A3W/6_H$Y( BR4ZU$ 4X^.4`{RnI`32af_klT_N$!be`sBRd=DRc% [QPczuwLY6uOm(xz>76F_ 됤z`**LB ,IRЊouKS@a.c],+C`'c+]|V׉x~U8 tI %dO#+i̙8<) Ӏ"jiP.s+)'/_o>7J:L&62WΘ>\$@IYq" a 3f8x1"NTO{ꄚAiୀ+SrBHoԠ?$VaxB_ރ͵ceDʲ=656H}3Rd3zasCj5H7[sSpd4t9`'lL07 c1SvGļ\?Pt$]%Mk[1l:Ed{{`7~w{ZOo wxL.Qr.Ί#r)0:V8 Y;86Y=p<$p\D7a#ܘVgb6J*".w~bD/VQrB?Db 1,HPW^tr|_2B n <o;<1W}cj(d$<*Ee.">k~3_tL/fubh0C%x/s c FBVD܉tI&8$`EZYVJ 5oE.+"""Mm֧Υ=Vj,ć3g`-#b!"vכ%mz [=$b{L[cOSKy|kD1!"g&BL]]U'a 擻GĠ*"Fb1Iy~{.D,cE sL'v3<0X$U@ByG={sr&i .—)߭>x`ſݒFLmnkKD̎_bch^R8ϩ555<gyRt'% ;"?zg8mU4"9D=xx锌Ԫck""$>8{dZ=3-"F`Ef*06j#;"h,c15~Pz48.t. ,Τ8 TDĻU; LM.&K`G ׼ l-WV ֥.^E{P.ł5J<:GDw?lm7[ժ d%O MuW"uimX(^B`'Ǔ<~qRŸR]MD%84.qu՝1j4=ZcgFJsO`?0Ńv1ݭہSp:ofd B3I?Še!N)r/țlQ!0&_03r^ֽyM/E]QZZy^0^6Ae̺(bC%) ܏ eNUa-JE1KN& u^tNYUKEoiJ0276P| m> y9GBz p`>Po3sODLIҤ{8=4ȋAT{U})O SE 8d@*x%wVjX:ksE̋oYA 6;7sLVAn2NG9?wgl}^k {<q9uwI`.<ֈB'8yྜ2de5a*DayV;G}|!ǔ(?T^/aG;e^a(e / mF_`(|,g!Hc+7 KD-IoDO -hC[ЂFE-h2%ԇY-hAc/х*\ovIENDB`unbescape-unbescape-1.1.5.RELEASE/src/artwork/unbescape_small_transparent.png000066400000000000000000000041111311410233600272400ustar00rootroot00000000000000PNG  IHDRh|HsBIT|d pHYsxxtEXtSoftwarewww.inkscape.org<IDATX{Uu?spx#7$$!̨TpPtPJF tHɰ I 3^!N%-PV(w|p805Ú{~k[}DS@z;iO T`ʆS q\쏣d8 ƝӠ[NڬڤÙ@gAO w4>8 o_x*~D%mr˿ ,:)A8 ލ`r+blB`60?cZԥ`*>ʠ?ڜDڡQcumeX XB`>SB<T1&O&[Np B] Iq\X*zbQ`U (m~$]QR(Unp[D@H"nG0NK%LSUܲTT_u%nBC4G>p2]SmԩhEtI]l.vvJYD_hC% pz H.h$mw{KlQϊ?oG_%\U0`J'^q6p#f׾ {*= <= -:{H\fdn xeL@a`p0*͚=%EwV]hl*i k@w;0l^"u`T) \l6i02MˋW*S ^woXz ̜u"1L&@cZgg0X̠۾ua `Sl[bnG`lɻ6`x:_rwxX\Y 6sM>vfB/_vs ˏf 8 j̠Mq3\N !3`| v5>Qȍ[m09KP,lm^l|ө3fO݀9@W`3pm*ғ bENc*p#%z}8 .-g؊ 0"z@_` n8 *mlK^Ȁ.1B6!S@r `du.j)G UA]m WKp[z unh-E|YS-}L\L` TG7{ $r^~]?# i Q']FJdO<o׎l$noMLPӢ1 t of/P;AZNHœblyވ͊YH?aBާ9s]-(sϣ ˁECiqN|ˀ ``2+YP Xc9hPur}ZIU(==5U) 傋~9| 5ӑr+J.@7l; <6s4C/t{o>dd7C+쐰&P9h d/ ~/IENDB`unbescape-unbescape-1.1.5.RELEASE/src/assembly/000077500000000000000000000000001311410233600211055ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/assembly/dist.xml000066400000000000000000000016621311410233600225770ustar00rootroot00000000000000 dist zip ${basedir}/target/apidocs/ /apidocs **/* ${basedir}/target/ /dist unbescape-${version}.jar unbescape-${version}-javadoc.jar unbescape-${version}-sources.jar ${basedir}/ / LICENSE.txt README.txt NOTICE.txt unbescape-unbescape-1.1.5.RELEASE/src/main/000077500000000000000000000000001311410233600202125ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/000077500000000000000000000000001311410233600211335ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/000077500000000000000000000000001311410233600217225ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/000077500000000000000000000000001311410233600236675ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/000077500000000000000000000000001311410233600244575ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssEscape.java000066400000000000000000002437271311410233600272120ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing CSS escape/unescape operations. *

* *

* This class supports both escaping of CSS identifiers and * CSS Strings (or literals). *

* * Configuration of escape/unescape operations * *

* Escape operations can be (optionally) configured by means of: *

*
    *
  • Level, which defines how deep the escape operation must be (what * chars are to be considered eligible for escaping, depending on the specific * needs of the scenario). Its values are defined by the {@link CssIdentifierEscapeLevel} * and {@link CssStringEscapeLevel} enums.
  • *
  • Type, which defines whether escaping should be performed by means of backslash escapes * or by means of hexadecimal numerical escape sequences. * Its values are defined by the {@link CssIdentifierEscapeType} * and {@link CssStringEscapeType} enums.
  • *
*

* Unescape operations need no configuration parameters. Unescape operations * will always perform complete unescape of backslash and hexadecimal escapes, including all * required tweaks (i.e. optional whitespace characters) needed for unescaping. *

* * Features * *

* Specific features of the CSS escape/unescape operations performed by means of this class: *

*
    *
  • Complete set of CSS Backslash Escapes supported (e.g. \+, \(, * \), etc.).
  • *
  • Full set of escape syntax rules supported, both for CSS identifiers and * CSS Strings (or literals).
  • *
  • Non-standard tweaks supported: \: not used because of lacking support in * Internet Explorer < 8, \_ escaped at the beginning of identifiers for better * Internet Explorer 6 support, etc.
  • *
  • Hexadecimal escapes (a.k.a. unicode escapes) are supported both in escape * and unescape operations, and both in compact (\E1 ) and six-digit * forms (\0000E1).
  • *
  • Support for the whole Unicode character set: \u0000 to \u10FFFF, including * characters not representable by only one char in Java (>\uFFFF).
  • *
  • Support for unescaping unicode characters > U+FFFF both when represented in standard form (one char, * \20000) and non-standard (surrogate pair, \D840\DC00, used by older * WebKit browsers).
  • *
* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
Backslash escapes
*
Escape sequences performed by means of prefixing a backslash (\) to * the escaped char: \+, \(, \)
*
HEXA escapes
*
Complete representation of unicode codepoints up to U+10FFFF, in two forms: *
    *
  • Compact: non-zero-padded hexadecimal representation (\E1 ), followed * by an optional whitespace (U+0020), required if after the escaped character comes * a hexadecimal digit ([0-9A-Fa-f]) or another whitespace ( ).
  • *
  • Six-digit: zero-padded hexadecimal representation (\0000E1), followed * by an optional whitespace (U+0020), required if after the escaped character comes * another whitespace ( ).
  • *
*
*
Unicode Codepoint
*
Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the * first char is a high surrogate (\uD800 to \uDBFF) and the * second is a low surrogate (\uDC00 to \uDFFF).
*
* * References * *

* The following references apply: *

*
* * * @author Daniel Fernández * * @since 1.0.0 * */ public final class CssEscape { /** *

* Perform a CSS String level 1 (only basic set) escape operation * on a String input. *

*

* Level 1 means this method will only escape the CSS String basic escape set: *

*
    *
  • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeCssString(String, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeCssStringMinimal(final String text) { return escapeCssString(text, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS String level 2 (basic set and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS String basic escape set: *
      *
    • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssString(String, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeCssString(final String text) { return escapeCssString(text, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS String escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link CssStringEscapeType} and * {@link CssStringEscapeLevel} argument values. *

*

* All other String-based escapeCssString*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see * {@link CssStringEscapeType}. * @param level the escape level to be applied, see {@link CssStringEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeCssString(final String text, final CssStringEscapeType type, final CssStringEscapeLevel level) { if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return CssStringEscapeUtil.escape(text, type, level); } /** *

* Perform a CSS String level 1 (only basic set) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the CSS String basic escape set: *

*
    *
  • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeCssString(String, Writer, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssStringMinimal(final String text, final Writer writer) throws IOException { escapeCssString(text, writer, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS String level 2 (basic set and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS String basic escape set: *
      *
    • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssString(String, Writer, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssString(final String text, final Writer writer) throws IOException { escapeCssString(text, writer, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS String escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link CssStringEscapeType} and * {@link CssStringEscapeLevel} argument values. *

*

* All other String/Writer-based escapeCssString*(...) methods call this one * with preconfigured type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link CssStringEscapeType}. * @param level the escape level to be applied, see {@link CssStringEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssString(final String text, final Writer writer, final CssStringEscapeType type, final CssStringEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } CssStringEscapeUtil.escape(new InternalStringReader(text), writer, type, level); } /** *

* Perform a CSS String level 1 (only basic set) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the CSS String basic escape set: *

*
    *
  • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeCssString(Reader, Writer, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssStringMinimal(final Reader reader, final Writer writer) throws IOException { escapeCssString(reader, writer, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS String level 2 (basic set and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS String basic escape set: *
      *
    • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssString(Reader, Writer, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssString(final Reader reader, final Writer writer) throws IOException { escapeCssString(reader, writer, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS String escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link CssStringEscapeType} and * {@link CssStringEscapeLevel} argument values. *

*

* All other Reader/Writer-based escapeCssString*(...) methods call this one * with preconfigured type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link CssStringEscapeType}. * @param level the escape level to be applied, see {@link CssStringEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssString(final Reader reader, final Writer writer, final CssStringEscapeType type, final CssStringEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } CssStringEscapeUtil.escape(reader, writer, type, level); } /** *

* Perform a CSS String level 1 (only basic set) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the CSS String basic escape set: *

*
    *
  • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssString(char[], int, int, java.io.Writer, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeCssStringMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeCssString(text, offset, len, writer, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS String level 2 (basic set and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS String basic escape set: *
      *
    • The Backslash Escapes: * \" (U+0022) and * \' (U+0027). *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssString(char[], int, int, java.io.Writer, CssStringEscapeType, CssStringEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssStringEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssStringEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeCssString(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeCssString(text, offset, len, writer, CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssStringEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS String escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link CssStringEscapeType} and * {@link CssStringEscapeLevel} argument values. *

*

* All other char[]-based escapeCssString*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link CssStringEscapeType}. * @param level the escape level to be applied, see {@link CssStringEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeCssString(final char[] text, final int offset, final int len, final Writer writer, final CssStringEscapeType type, final CssStringEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } CssStringEscapeUtil.escape(text, offset, len, writer, type, level); } /** *

* Perform a CSS Identifier level 1 (only basic set) escape operation * on a String input. *

*

* Level 1 means this method will only escape the CSS Identifier basic escape set: *

*
    *
  • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeCssIdentifier(String, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeCssIdentifierMinimal(final String text) { return escapeCssIdentifier(text, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS Identifier level 2 (basic set and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS Identifier basic escape set: *
      *
    • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssIdentifier(String, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeCssIdentifier(final String text) { return escapeCssIdentifier(text, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS Identifier escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link CssIdentifierEscapeType} and * {@link CssIdentifierEscapeLevel} argument values. *

*

* All other String-based escapeCssIdentifier*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see * {@link CssIdentifierEscapeType}. * @param level the escape level to be applied, see {@link CssIdentifierEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeCssIdentifier(final String text, final CssIdentifierEscapeType type, final CssIdentifierEscapeLevel level) { if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return CssIdentifierEscapeUtil.escape(text, type, level); } /** *

* Perform a CSS Identifier level 1 (only basic set) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the CSS Identifier basic escape set: *

*
    *
  • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeCssIdentifier(String, Writer, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssIdentifierMinimal(final String text, final Writer writer) throws IOException { escapeCssIdentifier(text, writer, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS Identifier level 2 (basic set and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS Identifier basic escape set: *
      *
    • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssIdentifier(String, Writer, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssIdentifier(final String text, final Writer writer) throws IOException { escapeCssIdentifier(text, writer, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS Identifier escape operation on a String input, * writing the results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link CssIdentifierEscapeType} and * {@link CssIdentifierEscapeLevel} argument values. *

*

* All other String/Writer-based escapeCssIdentifier*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link CssIdentifierEscapeType}. * @param level the escape level to be applied, see {@link CssIdentifierEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssIdentifier(final String text, final Writer writer, final CssIdentifierEscapeType type, final CssIdentifierEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } CssIdentifierEscapeUtil.escape(new InternalStringReader(text), writer, type, level); } /** *

* Perform a CSS Identifier level 1 (only basic set) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the CSS Identifier basic escape set: *

*
    *
  • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeCssIdentifier(Reader, Writer, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssIdentifierMinimal(final Reader reader, final Writer writer) throws IOException { escapeCssIdentifier(reader, writer, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS Identifier level 2 (basic set and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS Identifier basic escape set: *
      *
    • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssIdentifier(Reader, Writer, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssIdentifier(final Reader reader, final Writer writer) throws IOException { escapeCssIdentifier(reader, writer, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS Identifier escape operation on a Reader input, * writing the results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link CssIdentifierEscapeType} and * {@link CssIdentifierEscapeLevel} argument values. *

*

* All other Reader/Writer-based escapeCssIdentifier*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link CssIdentifierEscapeType}. * @param level the escape level to be applied, see {@link CssIdentifierEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCssIdentifier(final Reader reader, final Writer writer, final CssIdentifierEscapeType type, final CssIdentifierEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } CssIdentifierEscapeUtil.escape(reader, writer, type, level); } /** *

* Perform a CSS Identifier level 1 (only basic set) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the CSS Identifier basic escape set: *

*
    *
  • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
  • *
  • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssIdentifier(char[], int, int, java.io.Writer, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeCssIdentifierMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeCssIdentifier(text, offset, len, writer, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a CSS Identifier level 2 (basic set and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The CSS Identifier basic escape set: *
      *
    • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using Backslash escapes whenever possible. For escaped * characters that do not have an associated Backslash, default to \FF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeCssIdentifier(char[], int, int, java.io.Writer, CssIdentifierEscapeType, CssIdentifierEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link CssIdentifierEscapeType#BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA}
  • *
  • level: * {@link CssIdentifierEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeCssIdentifier(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeCssIdentifier(text, offset, len, writer, CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA, CssIdentifierEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) CSS Identifier escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link CssIdentifierEscapeType} and * {@link CssIdentifierEscapeLevel} argument values. *

*

* All other char[]-based escapeCssIdentifier*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link CssIdentifierEscapeType}. * @param level the escape level to be applied, see {@link CssIdentifierEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeCssIdentifier(final char[] text, final int offset, final int len, final Writer writer, final CssIdentifierEscapeType type, final CssIdentifierEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } CssIdentifierEscapeUtil.escape(text, offset, len, writer, type, level); } /** *

* Perform a CSS unescape operation on a String input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete CSS unescape of backslash and hexadecimal escape * sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeCss(final String text) { if (text == null) { return null; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed return text; } return CssUnescapeUtil.unescape(text); } /** *

* Perform a CSS unescape operation on a String input, writing results * to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete CSS unescape of backslash and hexadecimal escape * sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeCss(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (text == null) { return; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed writer.write(text); return; } CssUnescapeUtil.unescape(new InternalStringReader(text), writer); } /** *

* Perform a CSS unescape operation on a String input, writing results * to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete CSS unescape of backslash and hexadecimal escape * sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeCss(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } CssUnescapeUtil.unescape(reader, writer); } /** *

* Perform a CSS unescape operation on a char[] input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete CSS unescape of backslash and hexadecimal escape * sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeCss(final char[] text, final int offset, final int len, final Writer writer) throws IOException{ if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } CssUnescapeUtil.unescape(text, offset, len, writer); } private CssEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssIdentifierEscapeLevel.java000066400000000000000000000150151311410233600321700ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; /** *

* Levels defined for escape/unescape operations of CSS identifiers: *

* *
    *
  • Level 1: Escape only the basic escape set. Note the result of a level-1 escape * operation might still contain non-ASCII characters if they existed in input, and therefore you * will still need to correctly manage your input/output character encoding settings. Such * basic set consists of: *
      *
    • The Backslash Escapes: * \ (U+0020), * \! (U+0021), * \" (U+0022), * \# (U+0023), * \$ (U+0024), * \% (U+0025), * \& (U+0026), * \' (U+0027), * \( (U+0028), * \) (U+0029), * \* (U+002A), * \+ (U+002B), * \, (U+002C), * \. (U+002E), * \/ (U+002F), * \; (U+003B), * \< (U+003C), * \= (U+003D), * \> (U+003E), * \? (U+003F), * \@ (U+0040), * \[ (U+005B), * \\ (U+005C), * \] (U+005D), * \^ (U+005E), * \` (U+0060), * \{ (U+007B), * \| (U+007C), * \} (U+007D) and * \~ (U+007E). * Note that the \- (U+002D) escape sequence exists, but will only be used * when an identifier starts with two hypens or hyphen + digit. Also, the \_ * (U+005F) escape will only be used at the beginning of an identifier to avoid * problems with Internet Explorer 6. In the same sense, note that the \: * (U+003A) escape sequence is also defined in the standard, but will not be * used for escaping as Internet Explorer < 8 does not recognize it. *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • Level 2: Escape the basic escape set (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link CssEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum CssIdentifierEscapeLevel { /** * Level 1 escape: escape only the basic escape set: Backslash Escape plus non-displayable control chars. */ LEVEL_1_BASIC_ESCAPE_SET(1), /** * Level 2 escape: escape the basic escape set plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static CssIdentifierEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_BASIC_ESCAPE_SET; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } CssIdentifierEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssIdentifierEscapeType.java000066400000000000000000000063751311410233600320530ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; /** *

* Types of escape operations to be performed on CSS identifiers: *

* *
    *
  • BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA: Use * backslash escapes whenever possible (depending on the specified * {@link CssIdentifierEscapeLevel}). For escaped characters that do * not have an associated backslash escape, default to using * \FF* variable-length hexadecimal escapes.
  • *
  • BACKSLASH_ESCAPES_DEFAULT_TO_SIX_DIGIT_HEXA: Use * backslash escapes whenever possible (depending on the specified * {@link CssIdentifierEscapeLevel}). For escaped characters that do * not have an associated backslash escape, default to using * \FFFFFF 6-digit hexadecimal escapes.
  • *
  • COMPACT_HEXA: Replace escaped characters with * \FF* variable-length hexadecimal escapes.
  • *
  • SIX_DIGIT_HEXA: Replace escaped characters with * \FFFFFF 6-digit hexadecimal escapes.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link CssEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum CssIdentifierEscapeType { /** * Use backslash escapes if possible, default to \FF* variable-length hexadecimal escapes. */ BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA(true, true), /** * Use backslash escapes if possible, default to \FFFFFF 6-digit hexadecimal escapes. */ BACKSLASH_ESCAPES_DEFAULT_TO_SIX_DIGIT_HEXA(true, false), /** * Always use \FF* variable-length hexadecimal escapes. */ COMPACT_HEXA(false, true), /** * Always use \FFFFFF 6-digit hexadecimal escapes. */ SIX_DIGIT_HEXA(false, false); private final boolean useBackslashEscapes; private final boolean useCompactHexa; CssIdentifierEscapeType(final boolean useBackslashEscapes, final boolean useCompactHexa) { this.useBackslashEscapes = useBackslashEscapes; this.useCompactHexa = useCompactHexa; } public boolean getUseBackslashEscapes() { return useBackslashEscapes; } public boolean getUseCompactHexa() { return useCompactHexa; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssIdentifierEscapeUtil.java000066400000000000000000000631551311410233600320460ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class CssIdentifierEscapeUtil { /* * CSS IDENTIFIER ESCAPE OPERATIONS * -------------------------------- * * See: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier * http://mathiasbynens.be/notes/css-escapes * http://mothereff.in/css-escapes * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - BACKSLASH ESCAPES: * U+0020 -> % (escape + whitespace) * U+0021 -> %! * U+0022 -> %" * U+0023 -> %# * U+0024 -> %$ * U+0025 -> %% * U+0026 -> %& * U+0027 -> %' * U+0028 -> %( * U+0029 -> %) * U+002A -> %* * U+002B -> %+ * U+002C -> %, * U+002D -> %- [ ONLY USED WHEN IDENTIFIER STARTS WITH -- OR -{DIGIT} ] * U+002E -> %. * U+002F -> %/ * U+003A -> %: [ NOT USED FOR ESCAPING, NOT RECOGNIZED BY IE < 8 ] * U+003B -> %; * U+003C -> %< * U+003D -> %= * U+003E -> %> * U+003F -> %? * U+0040 -> %@ * U+005B -> %[ * U+005C -> %% * U+005D -> %] * U+005E -> %^ * U+005F -> %_ [ ONLY USED AT THE BEGINNING OF AN INDENTIFIER, TO AVOID PROBLEMS WITH IE6 ] * U+0060 -> %` * U+007B -> %{ * U+007C -> %| * U+007D -> %} * U+007E -> %~ * * - UNICODE ESCAPE [HEXA] * Compact representation: %??* (variable-length. Optionally followed by a whitespace U+0020 - required * if after escape comes a hexadecimal char (0-9a-f) or a whitespace U+0020) * 6-digit representation: %?????? (fixed-length. Not required to be followed by whitespace, unless after * escape comes a whitespace U+0020) * * Characters > U+FFFF : * - Standard: %?????? or %??* (but not supported by older WebKit browsers) * - Non-standard: %u????%u???? (surrogate character pair, only in older WebKit browsers) * * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); /* * Structures for holding the Backslash Escapes */ private static int BACKSLASH_CHARS_LEN = '~' + 1; // 0x7E + 1 = 0x7F private static char BACKSLASH_CHARS_NO_ESCAPE = 0x0; private static char[] BACKSLASH_CHARS; /* * Structured for holding the 'escape level' assigned to chars (not codepoints) up to ESCAPE_LEVELS_LEN. * - The last position of the ESCAPE_LEVELS array will be used for determining the level of all * codepoints >= (ESCAPE_LEVELS_LEN - 1) */ private static final char ESCAPE_LEVELS_LEN = 0x9f + 2; // Last relevant char to be indexed is 0x9f private static final byte[] ESCAPE_LEVELS; static { /* * Initialize Single Escape Characters */ BACKSLASH_CHARS = new char[BACKSLASH_CHARS_LEN]; Arrays.fill(BACKSLASH_CHARS, BACKSLASH_CHARS_NO_ESCAPE); BACKSLASH_CHARS[0x20] = ' '; BACKSLASH_CHARS[0x21] = '!'; BACKSLASH_CHARS[0x22] = '"'; BACKSLASH_CHARS[0x23] = '#'; BACKSLASH_CHARS[0x24] = '$'; BACKSLASH_CHARS[0x25] = '%'; BACKSLASH_CHARS[0x26] = '&'; BACKSLASH_CHARS[0x27] = '\''; BACKSLASH_CHARS[0x28] = '('; BACKSLASH_CHARS[0x29] = ')'; BACKSLASH_CHARS[0x2A] = '*'; BACKSLASH_CHARS[0x2B] = '+'; BACKSLASH_CHARS[0x2C] = ','; // hyphen: will only be escaped when identifer starts with '--' or '-{digit}' BACKSLASH_CHARS[0x2D] = '-'; BACKSLASH_CHARS[0x2E] = '.'; BACKSLASH_CHARS[0x2F] = '/'; // colon: will not be used for escaping: not recognized by IE < 8 // BACKSLASH_CHARS[0x3A] = ':'; BACKSLASH_CHARS[0x3B] = ';'; BACKSLASH_CHARS[0x3C] = '<'; BACKSLASH_CHARS[0x3D] = '='; BACKSLASH_CHARS[0x3E] = '>'; BACKSLASH_CHARS[0x3F] = '?'; BACKSLASH_CHARS[0x40] = '@'; BACKSLASH_CHARS[0x5B] = '['; BACKSLASH_CHARS[0x5C] = '\\'; BACKSLASH_CHARS[0x5D] = ']'; BACKSLASH_CHARS[0x5E] = '^'; // underscore: will only be escaped at the beginning of an identifier (in order to avoid issues in IE6) BACKSLASH_CHARS[0x5F] = '_'; BACKSLASH_CHARS[0x60] = '`'; BACKSLASH_CHARS[0x7B] = '{'; BACKSLASH_CHARS[0x7C] = '|'; BACKSLASH_CHARS[0x7D] = '}'; BACKSLASH_CHARS[0x7E] = '~'; /* * Initialization of escape levels. * Defined levels : * * - Level 1 : Basic escape set * - Level 2 : Basic escape set plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters * */ ESCAPE_LEVELS = new byte[ESCAPE_LEVELS_LEN]; /* * Everything is level 3 unless contrary indication. */ Arrays.fill(ESCAPE_LEVELS, (byte)3); /* * Everything non-ASCII is level 2 unless contrary indication. */ for (char c = 0x80; c < ESCAPE_LEVELS_LEN; c++) { ESCAPE_LEVELS[c] = 2; } /* * Alphanumeric characters are level 4. */ for (char c = 'A'; c <= 'Z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = '0'; c <= '9'; c++) { ESCAPE_LEVELS[c] = 4; } /* * Backslash Escapes will be level 1 (always escaped) */ ESCAPE_LEVELS[0x20] = 1; ESCAPE_LEVELS[0x21] = 1; ESCAPE_LEVELS[0x22] = 1; ESCAPE_LEVELS[0x23] = 1; ESCAPE_LEVELS[0x24] = 1; ESCAPE_LEVELS[0x25] = 1; ESCAPE_LEVELS[0x26] = 1; ESCAPE_LEVELS[0x27] = 1; ESCAPE_LEVELS[0x28] = 1; ESCAPE_LEVELS[0x29] = 1; ESCAPE_LEVELS[0x2A] = 1; ESCAPE_LEVELS[0x2B] = 1; ESCAPE_LEVELS[0x2C] = 1; // hyphen: will only be escaped when identifer starts with '--' or '-{digit}' ESCAPE_LEVELS[0x2D] = 1; ESCAPE_LEVELS[0x2E] = 1; ESCAPE_LEVELS[0x2F] = 1; // colon: will not be used for escaping: not recognized by IE < 8 ESCAPE_LEVELS[0x3A] = 1; ESCAPE_LEVELS[0x3B] = 1; ESCAPE_LEVELS[0x3C] = 1; ESCAPE_LEVELS[0x3D] = 1; ESCAPE_LEVELS[0x3E] = 1; ESCAPE_LEVELS[0x3F] = 1; ESCAPE_LEVELS[0x40] = 1; ESCAPE_LEVELS[0x5B] = 1; ESCAPE_LEVELS[0x5C] = 1; ESCAPE_LEVELS[0x5D] = 1; ESCAPE_LEVELS[0x5E] = 1; // underscore: will only be escaped at the beginning of an identifier (in order to avoid issues in IE6) ESCAPE_LEVELS[0x5F] = 1; ESCAPE_LEVELS[0x60] = 1; ESCAPE_LEVELS[0x7B] = 1; ESCAPE_LEVELS[0x7C] = 1; ESCAPE_LEVELS[0x7D] = 1; ESCAPE_LEVELS[0x7E] = 1; /* * Two ranges of non-displayable, control characters: * U+0000 to U+001F and U+007F to U+009F. */ for (char c = 0x00; c <= 0x1F; c++) { ESCAPE_LEVELS[c] = 1; } for (char c = 0x7F; c <= 0x9F; c++) { ESCAPE_LEVELS[c] = 1; } } private CssIdentifierEscapeUtil() { super(); } static char[] toCompactHexa(final int codepoint, final char next, final int level) { // In identifiers, whitespace will always be escaped (no need for trailing whitespace) // If level is 4, hexadecimal characters will be escaped (no need to for trailing whitespaces) final boolean needTrailingSpace = (level < 4 && ((next >= '0' && next <= '9') || (next >= 'A' && next <= 'F') || (next >= 'a' && next <= 'f'))); if (codepoint == 0) { return (needTrailingSpace ? new char[] { '0', ' ' } : new char[] { '0' }); } int div = 20; char[] result = null; while (result == null && div >= 0) { if ((codepoint >>> div) % 0x10 > 0) { result = new char[(div / 4) + (needTrailingSpace? 2 : 1)]; } div -= 4; } div = 0; for (int i = (needTrailingSpace? result.length - 2 : result.length - 1); i >= 0; i--) { result[i] = HEXA_CHARS_UPPER[(codepoint >>> div) % 0x10]; div += 4; } if (needTrailingSpace) { result[result.length - 1] = ' '; } return result; } static char[] toSixDigitHexa(final int codepoint, final char next, final int level) { // In identifiers, whitespace will always be escaped (no need for trailing whitespace) final boolean needTrailingSpace = false; final char[] result = new char[6 + (needTrailingSpace? 1 : 0)]; if (needTrailingSpace) { result[6] = ' '; } result[5] = HEXA_CHARS_UPPER[codepoint % 0x10]; result[4] = HEXA_CHARS_UPPER[(codepoint >>> 4) % 0x10]; result[3] = HEXA_CHARS_UPPER[(codepoint >>> 8) % 0x10]; result[2] = HEXA_CHARS_UPPER[(codepoint >>> 12) % 0x10]; result[1] = HEXA_CHARS_UPPER[(codepoint >>> 16) % 0x10]; result[0] = HEXA_CHARS_UPPER[(codepoint >>> 20) % 0x10]; return result; } /* * Perform an escape operation, based on String, according to the specified level and type. */ static String escape(final String text, final CssIdentifierEscapeType escapeType, final CssIdentifierEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); final boolean useBackslashEscapes = escapeType.getUseBackslashEscapes(); final boolean useCompactHexa = escapeType.getUseCompactHexa(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint] && (i > offset || codepoint < '0' || codepoint > '9')) { // Note how we check whether the first char is a decimal number, in which case we have to escape it continue; } /* * Hyphen check: only escape when it's the first char and it's followed by '-' or a digit. */ if (codepoint == '-' && level < 3) { if (i > offset || i + 1 >= max) { continue; } final char c1 = text.charAt(i + 1); if (c1 != '-' && (c1 < '0' || c1 > '9')) { continue; } } /* * Underscore check: only escape when it's the first char. */ if (codepoint == '_' && level < 3 && i > offset) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ------------------------------------------------------------------------------------------ * * Perform the real escape, attending the different combinations of BACKSLASH and HEXA escapes * * ------------------------------------------------------------------------------------------ */ if (useBackslashEscapes && codepoint < BACKSLASH_CHARS_LEN) { // We will try to use a BACKSLASH ESCAPE final char escape = BACKSLASH_CHARS[codepoint]; if (escape != BACKSLASH_CHARS_NO_ESCAPE) { // Escape found! just write it and go for the next char strBuilder.append(ESCAPE_PREFIX); strBuilder.append(escape); continue; } } /* * No escape was possible, so we need hexa escape (compact or 6-digit). */ final char next = ((i + 1 < max) ? text.charAt(i + 1) : (char) 0x0); if (useCompactHexa) { strBuilder.append(ESCAPE_PREFIX); strBuilder.append(toCompactHexa(codepoint, next, level)); continue; } strBuilder.append(ESCAPE_PREFIX); strBuilder.append(toSixDigitHexa(codepoint, next, level)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final CssIdentifierEscapeType escapeType, final CssIdentifierEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useBackslashEscapes = escapeType.getUseBackslashEscapes(); final boolean useCompactHexa = escapeType.getUseCompactHexa(); int c0, c1, c2; // c0: last char, c1: current char, c2: next char c1 = -1; c2 = reader.read(); while (c2 >= 0) { c0 = c1; c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint] && (c0 >= 0 || codepoint < '0' || codepoint > '9')) { // Note how we check whether the first char is a decimal number, in which case we have to escape it writer.write(c1); continue; } /* * Hyphen check: only escape when it's the first char and it's followed by '-' or a digit. */ if (codepoint == '-' && level < 3) { if (c0 >= 0 || c2 < 0) { // not first or last writer.write(c1); continue; } if (c2 != '-' && (c2 < '0' || c2 > '9')) { writer.write(c1); continue; } } /* * Underscore check: only escape when it's the first char. */ if (codepoint == '_' && level < 3 && c0 >= 0) { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c0 = c1; c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c0 = c1; c1 = c2; c2 = reader.read(); } /* * ------------------------------------------------------------------------------------------ * * Perform the real escape, attending the different combinations of BACKSLASH and HEXA escapes * * ------------------------------------------------------------------------------------------ */ if (useBackslashEscapes && codepoint < BACKSLASH_CHARS_LEN) { // We will try to use a BACKSLASH ESCAPE final char escape = BACKSLASH_CHARS[codepoint]; if (escape != BACKSLASH_CHARS_NO_ESCAPE) { // Escape found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(escape); continue; } } /* * No escape was possible, so we need hexa escape (compact or 6-digit). */ final char next = (c2 >= 0 ? (char) c2 : (char) 0x0); if (useCompactHexa) { writer.write(ESCAPE_PREFIX); writer.write(toCompactHexa(codepoint, next, level)); continue; } writer.write(ESCAPE_PREFIX); writer.write(toSixDigitHexa(codepoint, next, level)); } } /* * Perform an escape operation, based on char[], according to the specified level and type. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final CssIdentifierEscapeType escapeType, final CssIdentifierEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useBackslashEscapes = escapeType.getUseBackslashEscapes(); final boolean useCompactHexa = escapeType.getUseCompactHexa(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint] && (i > offset || codepoint < '0' || codepoint > '9')) { // Note how we check whether the first char is a decimal number, in which case we have to escape it continue; } /* * Hyphen check: only escape when it's the first char and it's followed by '-' or a digit. */ if (codepoint == '-' && level < 3) { if (i > offset || i + 1 >= max) { continue; } final char c1 = text[i + 1]; if (c1 != '-' && (c1 < '0' || c1 > '9')) { continue; } } /* * Underscore check: only escape when it's the first char. */ if (codepoint == '_' && level < 3 && i > offset) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ------------------------------------------------------------------------------------------ * * Perform the real escape, attending the different combinations of BACKSLASH and HEXA escapes * * ------------------------------------------------------------------------------------------ */ if (useBackslashEscapes && codepoint < BACKSLASH_CHARS_LEN) { // We will try to use a BACKSLASH ESCAPE final char escape = BACKSLASH_CHARS[codepoint]; if (escape != BACKSLASH_CHARS_NO_ESCAPE) { // Escape found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(escape); continue; } } /* * No escape was possible, so we need hexa escape (compact or 6-digit). */ final char next = ((i + 1 < max) ? text[i + 1] : (char) 0x0); if (useCompactHexa) { writer.write(ESCAPE_PREFIX); writer.write(toCompactHexa(codepoint, next, level)); continue; } writer.write(ESCAPE_PREFIX); writer.write(toSixDigitHexa(codepoint, next, level)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssStringEscapeLevel.java000066400000000000000000000130561311410233600313570ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; /** *

* Levels defined for escape/unescape operations of CSS strings: *

* *
    *
  • Level 1: Escape only the basic escape set. Note the result of a level-1 escape * operation might still contain non-ASCII characters if they existed in input, and therefore you * will still need to correctly manage your input/output character encoding settings. Such * basic set consists of: *
      *
    • The Backslash Escapes: *
        *
      • The quote symbols: * \" (U+0022) and * \' (U+0027). *
      • *
      • The backslash: \\ (U+005C).
      • *
      • * The slash (solidus) symbol (/, U+002F), which will be escaped in * order to protect from code injection in HTML environments: browsers will parse * </style> close tags inside CSS literals and close the tag, therefore * allowing for further code injection. *
      • *
      • * The ampersand (&, U+0026) and semi-colon (;, U+003B) symbols, * which will be escaped in order to protect from code injection in XHTML environments: browsers will * parse XHTML escape codes inside literals in <style> tags, therefore allowing * the closing of the literal and the <style> tag itself. *
      • *
      *
    • *
    • * Two ranges of non-displayable, control characters: U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • Level 2: Escape the basic escape set (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link CssEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum CssStringEscapeLevel { /** * Level 1 escape: escape only the basic escape set: Backslash Escape plus non-displayable control chars. */ LEVEL_1_BASIC_ESCAPE_SET(1), /** * Level 2 escape: escape the basic escape set plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static CssStringEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_BASIC_ESCAPE_SET; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } CssStringEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssStringEscapeType.java000066400000000000000000000063511311410233600312310ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; /** *

* Types of escape operations to be performed on CSS strings: *

* *
    *
  • BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA: Use * backslash escapes whenever possible (depending on the specified * {@link CssStringEscapeLevel}). For escaped characters that do * not have an associated backslash escape, default to using * \FF* variable-length hexadecimal escapes.
  • *
  • BACKSLASH_ESCAPES_DEFAULT_TO_SIX_DIGIT_HEXA: Use * backslash escapes whenever possible (depending on the specified * {@link CssStringEscapeLevel}). For escaped characters that do * not have an associated backslash escape, default to using * \FFFFFF 6-digit hexadecimal escapes.
  • *
  • COMPACT_HEXA: Replace escaped characters with * \FF* variable-length hexadecimal escapes.
  • *
  • SIX_DIGIT_HEXA: Replace escaped characters with * \FFFFFF 6-digit hexadecimal escapes.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link CssEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum CssStringEscapeType { /** * Use backslash escapes if possible, default to \FF* variable-length hexadecimal escapes. */ BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA(true, true), /** * Use backslash escapes if possible, default to \FFFFFF 6-digit hexadecimal escapes. */ BACKSLASH_ESCAPES_DEFAULT_TO_SIX_DIGIT_HEXA(true, false), /** * Always use \FF* variable-length hexadecimal escapes. */ COMPACT_HEXA(false, true), /** * Always use \FFFFFF 6-digit hexadecimal escapes. */ SIX_DIGIT_HEXA(false, false); private final boolean useBackslashEscapes; private final boolean useCompactHexa; CssStringEscapeType(final boolean useBackslashEscapes, final boolean useCompactHexa) { this.useBackslashEscapes = useBackslashEscapes; this.useCompactHexa = useCompactHexa; } public boolean getUseBackslashEscapes() { return useBackslashEscapes; } public boolean getUseCompactHexa() { return useCompactHexa; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssStringEscapeUtil.java000066400000000000000000000513771311410233600312350ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class CssStringEscapeUtil { /* * CSS STRING ESCAPE OPERATIONS * ---------------------------- * * See: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier * http://mathiasbynens.be/notes/css-escapes * http://mothereff.in/css-escapes * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - BACKSLASH ESCAPES: * U+0022 -> %" * U+0027 -> %' * U+005C -> %% * * - UNICODE ESCAPE [HEXA] * Compact representation: %??* (variable-length. Optionally followed by a whitespace U+0020 - required * if after escape comes a hexadecimal char (0-9a-f) or a whitespace U+0020) * 6-digit representation: %?????? (fixed-length. Not required to be followed by whitespace, unless after * escape comes a whitespace U+0020) * * Characters > U+FFFF : * - Standard: %?????? or %??* (but not supported by older WebKit browsers) * - Non-standard: %u????%u???? (surrogate character pair, only in older WebKit browsers) * * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); /* * Structures for holding the Backslash Escapes */ private static int BACKSLASH_CHARS_LEN = '~' + 1; // 0x7E + 1 = 0x7F private static char BACKSLASH_CHARS_NO_ESCAPE = 0x0; private static char[] BACKSLASH_CHARS; /* * Structured for holding the 'escape level' assigned to chars (not codepoints) up to ESCAPE_LEVELS_LEN. * - The last position of the ESCAPE_LEVELS array will be used for determining the level of all * codepoints >= (ESCAPE_LEVELS_LEN - 1) */ private static final char ESCAPE_LEVELS_LEN = 0x9f + 2; // Last relevant char to be indexed is 0x9f private static final byte[] ESCAPE_LEVELS; static { /* * Initialize Single Escape Characters */ BACKSLASH_CHARS = new char[BACKSLASH_CHARS_LEN]; Arrays.fill(BACKSLASH_CHARS, BACKSLASH_CHARS_NO_ESCAPE); BACKSLASH_CHARS[0x20] = ' '; BACKSLASH_CHARS[0x21] = '!'; BACKSLASH_CHARS[0x22] = '"'; BACKSLASH_CHARS[0x23] = '#'; BACKSLASH_CHARS[0x24] = '$'; BACKSLASH_CHARS[0x25] = '%'; BACKSLASH_CHARS[0x26] = '&'; BACKSLASH_CHARS[0x27] = '\''; BACKSLASH_CHARS[0x28] = '('; BACKSLASH_CHARS[0x29] = ')'; BACKSLASH_CHARS[0x2A] = '*'; BACKSLASH_CHARS[0x2B] = '+'; BACKSLASH_CHARS[0x2C] = ','; BACKSLASH_CHARS[0x2D] = '-'; BACKSLASH_CHARS[0x2E] = '.'; BACKSLASH_CHARS[0x2F] = '/'; // colon: will not be used for escaping: not recognized by IE < 8 // BACKSLASH_CHARS[0x3A] = ':'; BACKSLASH_CHARS[0x3B] = ';'; BACKSLASH_CHARS[0x3C] = '<'; BACKSLASH_CHARS[0x3D] = '='; BACKSLASH_CHARS[0x3E] = '>'; BACKSLASH_CHARS[0x3F] = '?'; BACKSLASH_CHARS[0x40] = '@'; BACKSLASH_CHARS[0x5B] = '['; BACKSLASH_CHARS[0x5C] = '\\'; BACKSLASH_CHARS[0x5D] = ']'; BACKSLASH_CHARS[0x5E] = '^'; BACKSLASH_CHARS[0x5F] = '_'; BACKSLASH_CHARS[0x60] = '`'; BACKSLASH_CHARS[0x7B] = '{'; BACKSLASH_CHARS[0x7C] = '|'; BACKSLASH_CHARS[0x7D] = '}'; BACKSLASH_CHARS[0x7E] = '~'; /* * Initialization of escape levels. * Defined levels : * * - Level 1 : Basic escape set * - Level 2 : Basic escape set plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters * */ ESCAPE_LEVELS = new byte[ESCAPE_LEVELS_LEN]; /* * Everything is level 3 unless contrary indication. */ Arrays.fill(ESCAPE_LEVELS, (byte)3); /* * Everything non-ASCII is level 2 unless contrary indication. */ for (char c = 0x80; c < ESCAPE_LEVELS_LEN; c++) { ESCAPE_LEVELS[c] = 2; } /* * Alphanumeric characters are level 4. */ for (char c = 'A'; c <= 'Z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = '0'; c <= '9'; c++) { ESCAPE_LEVELS[c] = 4; } /* * Backslash Escapes will be level 1 (always escaped) */ ESCAPE_LEVELS[0x22] = 1; ESCAPE_LEVELS[0x27] = 1; ESCAPE_LEVELS[0x5C] = 1; /* * Escapes related to code injection protection: / (HTML) and &, ; (XHTML) */ ESCAPE_LEVELS[0x2F] = 1; ESCAPE_LEVELS[0x26] = 1; ESCAPE_LEVELS[0x3B] = 1; /* * Two ranges of non-displayable, control characters: * U+0000 to U+001F and U+007F to U+009F. */ for (char c = 0x00; c <= 0x1F; c++) { ESCAPE_LEVELS[c] = 1; } for (char c = 0x7F; c <= 0x9F; c++) { ESCAPE_LEVELS[c] = 1; } } private CssStringEscapeUtil() { super(); } static char[] toCompactHexa(final int codepoint, final char next, final int level) { // If level is 3 or higher, whitespace will be escaped (no need for trailing whitespace) // If level is 4, hexadecimal characters will be escaped (no need to for trailing whitespaces) final boolean needTrailingSpace = (level < 4 && ((next >= '0' && next <= '9') || (next >= 'A' && next <= 'F') || (next >= 'a' && next <= 'f'))) || (level < 3 && (next == ' ')); if (codepoint == 0) { return (needTrailingSpace ? new char[] { '0', ' ' } : new char[] { '0' }); } int div = 20; char[] result = null; while (result == null && div >= 0) { if ((codepoint >>> div) % 0x10 > 0) { result = new char[(div / 4) + (needTrailingSpace? 2 : 1)]; } div -= 4; } div = 0; for (int i = (needTrailingSpace? result.length - 2 : result.length - 1); i >= 0; i--) { result[i] = HEXA_CHARS_UPPER[(codepoint >>> div) % 0x10]; div += 4; } if (needTrailingSpace) { result[result.length - 1] = ' '; } return result; } static char[] toSixDigitHexa(final int codepoint, final char next, final int level) { // If level is 3 or higher, whitespace will be escaped and therefore no need to add trailing space final boolean needTrailingSpace = (level < 3 && next == ' '); final char[] result = new char[6 + (needTrailingSpace? 1 : 0)]; if (needTrailingSpace) { result[6] = ' '; } result[5] = HEXA_CHARS_UPPER[codepoint % 0x10]; result[4] = HEXA_CHARS_UPPER[(codepoint >>> 4) % 0x10]; result[3] = HEXA_CHARS_UPPER[(codepoint >>> 8) % 0x10]; result[2] = HEXA_CHARS_UPPER[(codepoint >>> 12) % 0x10]; result[1] = HEXA_CHARS_UPPER[(codepoint >>> 16) % 0x10]; result[0] = HEXA_CHARS_UPPER[(codepoint >>> 20) % 0x10]; return result; } /* * Perform an escape operation, based on String, according to the specified level and type. */ static String escape(final String text, final CssStringEscapeType escapeType, final CssStringEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); final boolean useBackslashEscapes = escapeType.getUseBackslashEscapes(); final boolean useCompactHexa = escapeType.getUseCompactHexa(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ------------------------------------------------------------------------------------------ * * Perform the real escape, attending the different combinations of BACKSLASH and HEXA escapes * * ------------------------------------------------------------------------------------------ */ if (useBackslashEscapes && codepoint < BACKSLASH_CHARS_LEN) { // We will try to use a BACKSLASH ESCAPE final char sec = BACKSLASH_CHARS[codepoint]; if (sec != BACKSLASH_CHARS_NO_ESCAPE) { // Escape found! just write it and go for the next char strBuilder.append(ESCAPE_PREFIX); strBuilder.append(sec); continue; } } /* * No escape was possible, so we need hexa escape (compact or 6-digit). */ final char next = ((i + 1 < max) ? text.charAt(i + 1) : (char) 0x0); if (useCompactHexa) { strBuilder.append(ESCAPE_PREFIX); strBuilder.append(toCompactHexa(codepoint, next, level)); continue; } strBuilder.append(ESCAPE_PREFIX); strBuilder.append(toSixDigitHexa(codepoint, next, level)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final CssStringEscapeType escapeType, final CssStringEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useBackslashEscapes = escapeType.getUseBackslashEscapes(); final boolean useCompactHexa = escapeType.getUseCompactHexa(); int c1, c2; // c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c1 = c2; c2 = reader.read(); } /* * ------------------------------------------------------------------------------------------ * * Perform the real escape, attending the different combinations of BACKSLASH and HEXA escapes * * ------------------------------------------------------------------------------------------ */ if (useBackslashEscapes && codepoint < BACKSLASH_CHARS_LEN) { // We will try to use a BACKSLASH ESCAPE final char sec = BACKSLASH_CHARS[codepoint]; if (sec != BACKSLASH_CHARS_NO_ESCAPE) { // Escape found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No escape was possible, so we need hexa escape (compact or 6-digit). */ final char next = (c2 >= 0 ? (char) c2 : (char) 0x0); if (useCompactHexa) { writer.write(ESCAPE_PREFIX); writer.write(toCompactHexa(codepoint, next, level)); continue; } writer.write(ESCAPE_PREFIX); writer.write(toSixDigitHexa(codepoint, next, level)); } } /* * Perform an escape operation, based on char[], according to the specified level and type. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final CssStringEscapeType escapeType, final CssStringEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useBackslashEscapes = escapeType.getUseBackslashEscapes(); final boolean useCompactHexa = escapeType.getUseCompactHexa(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ------------------------------------------------------------------------------------------ * * Perform the real escape, attending the different combinations of BACKSLASH and HEXA escapes * * ------------------------------------------------------------------------------------------ */ if (useBackslashEscapes && codepoint < BACKSLASH_CHARS_LEN) { // We will try to use a BACKSLASH ESCAPE final char escape = BACKSLASH_CHARS[codepoint]; if (escape != BACKSLASH_CHARS_NO_ESCAPE) { // Escape found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(escape); continue; } } /* * No escape was possible, so we need hexa escape (compact or 6-digit). */ final char next = ((i + 1 < max) ? text[i + 1] : (char) 0x0); if (useCompactHexa) { writer.write(ESCAPE_PREFIX); writer.write(toCompactHexa(codepoint, next, level)); continue; } writer.write(ESCAPE_PREFIX); writer.write(toSixDigitHexa(codepoint, next, level)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/css/CssUnescapeUtil.java000066400000000000000000000507061311410233600304040ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.css; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Internal class in charge of performing the real unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class CssUnescapeUtil { /* * CSS STRING AND IDENTIFIER UNESCAPE OPERATIONS * --------------------------------------------- * * See: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier * http://mathiasbynens.be/notes/css-escapes * http://mothereff.in/css-escapes * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - BACKSLASH ESCAPES: * U+0020 -> % (escape + whitespace) * U+0021 -> %! * U+0022 -> %" * U+0023 -> %# * U+0024 -> %$ * U+0025 -> %% * U+0026 -> %& * U+0027 -> %' * U+0028 -> %( * U+0029 -> %) * U+002A -> %* * U+002B -> %+ * U+002C -> %, * U+002D -> %- [ ONLY USED WHEN IDENTIFIER STARTS WITH -- OR -{DIGIT} ] * U+002E -> %. * U+002F -> %/ * U+003A -> %: [ NOT USED FOR ESCAPING, NOT RECOGNIZED BY IE < 8 ] * U+003B -> %; * U+003C -> %< * U+003D -> %= * U+003E -> %> * U+003F -> %? * U+0040 -> %@ * U+005B -> %[ * U+005C -> %% * U+005D -> %] * U+005E -> %^ * U+005F -> %_ [ ONLY USED AT THE BEGINNING OF AN INDENTIFIER, TO AVOID PROBLEMS WITH IE6 ] * U+0060 -> %` * U+007B -> %{ * U+007C -> %| * U+007D -> %} * U+007E -> %~ * * - UNICODE ESCAPE [HEXA] * Compact representation: %??* (variable-length. Optionally followed by a whitespace U+0020 - required * if after escape comes a hexadecimal char (0-9a-f) or a whitespace U+0020) * 6-digit representation: %?????? (fixed-length. Not required to be followed by whitespace, unless after * escape comes a whitespace U+0020) * * Characters > U+FFFF : * - Standard: %?????? or %??* (but not supported by older WebKit browsers) * - Non-standard: %u????%u???? (surrogate character pair, only in older WebKit browsers) * * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); private CssUnescapeUtil() { super(); } /* * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need * to create substrings of the text being unescaped to feed such method. * - No need to check all chars are within the radix limits - reference parsing code will already have done so. */ static int parseIntFromReference(final String text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text.charAt(i); int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } /* * Perform an unescape operation based on String. */ static String unescape(final String text) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text.charAt(i + 1); switch (c1) { case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': // hyphen: will only be escaped when identifer starts with '--' or '-{digit}' case '-': case '.': case '/': // colon: will not be used for escaping: not recognized by IE < 8 case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\\': case ']': case '^': // underscore: will only be escaped at the beginning of an identifier (in order to avoid issues in IE6) case '_': case '`': case '{': case '|': case '}': case '~': codepoint = (int)c1; referenceOffset = i + 1; break; } if (codepoint == -1) { if ((c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'F') || (c1 >= 'a' && c1 <= 'f')) { // This is a hexa escape int f = i + 2; while (f < (i + 7) && f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } codepoint = parseIntFromReference(text, i + 1, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // If there is a whitespace after the escape, just ignore it. if (f < max && text.charAt(f) == ' ') { referenceOffset++; } // Don't continue here, just let the unescape code below do its job } else if (c1 == '\n' || c1 == '\r' || c1 == '\f') { // The only characters that cannot be escaped by means of a backslash are line feed, // carriage return and form feed (besides hexadecimal digits). i++; continue; } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the CSS escape syntax. codepoint = (int) c1; referenceOffset = i + 1; } } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } int escapei = 0; final char[] escapes = new char[6]; int c1, c2, ce; // c1: current char, c2: next char, ce: current escape char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); /* * Check the need for an unescape operation at this point */ if (c1 != ESCAPE_PREFIX || c2 < 0) { writer.write(c1); continue; } int codepoint = -1; if (c1 == ESCAPE_PREFIX) { switch (c2) { case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': // hyphen: will only be escaped when identifer starts with '--' or '-{digit}' case '-': case '.': case '/': // colon: will not be used for escaping: not recognized by IE < 8 case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\\': case ']': case '^': // underscore: will only be escaped at the beginning of an identifier (in order to avoid issues in IE6) case '_': case '`': case '{': case '|': case '}': case '~': codepoint = c2; c1 = c2; c2 = reader.read(); break; } if (codepoint == -1) { if ((c2 >= '0' && c2 <= '9') || (c2 >= 'A' && c2 <= 'F') || (c2 >= 'a' && c2 <= 'f')) { // This is a hexa escape escapei = 0; ce = c2; while (ce >= 0 && escapei < 6) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) { break; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } c1 = escapes[5]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, escapei, 16); // If there is a whitespace after the escape, just ignore it. if (c2 == ' ') { c1 = c2; c2 = reader.read(); } // Don't continue here, just let the unescape code below do its job } else if (c2 == '\n' || c2 == '\r' || c2 == '\f') { // The only characters that cannot be escaped by means of a backslash are line feed, // carriage return and form feed (besides hexadecimal digits). writer.write(c1); continue; } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the CSS escape syntax. codepoint = c2; c1 = c2; c2 = reader.read(); } } } /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text[i + 1]; switch (c1) { case ' ': case '!': case '"': case '#': case '$': case '%': case '&': case '\'': case '(': case ')': case '*': case '+': case ',': // hyphen: will only be escaped when identifer starts with '--' or '-{digit}' case '-': case '.': case '/': // colon: will not be used for escaping: not recognized by IE < 8 case ':': case ';': case '<': case '=': case '>': case '?': case '@': case '[': case '\\': case ']': case '^': // underscore: will only be escaped at the beginning of an identifier (in order to avoid issues in IE6) case '_': case '`': case '{': case '|': case '}': case '~': codepoint = (int)c1; referenceOffset = i + 1; break; } if (codepoint == -1) { if ((c1 >= '0' && c1 <= '9') || (c1 >= 'A' && c1 <= 'F') || (c1 >= 'a' && c1 <= 'f')) { // This is a hexa escape int f = i + 2; while (f < (i + 7) && f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } codepoint = parseIntFromReference(text, i + 1, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // If there is a whitespace after the escape, just ignore it. if (f < max && text[f] == ' ') { referenceOffset++; } // Don't continue here, just let the unescape code below do its job } else if (c1 == '\n' || c1 == '\r' || c1 == '\f') { // The only characters that cannot be escaped by means of a backslash are line feed, // carriage return and form feed (besides hexadecimal digits). i++; continue; } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the CSS escape syntax. codepoint = (int) c1; referenceOffset = i + 1; } } } /* * At this point we know for sure we will need some kind of unescape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char) codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/csv/000077500000000000000000000000001311410233600244625ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/csv/CsvEscape.java000066400000000000000000000367131311410233600272130ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.csv; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing CSV escape/unescape operations. *

* * Features * *

* Specific features of the CSV escape/unescape operations performed by means of this class: *

*
    *
  • Works according to the rules specified in RFC4180 (there is no CSV standard as such).
  • *
  • Encloses escaped values in double-quotes ("value") if they contain any non-alphanumeric * characters.
  • *
  • Escapes double-quote characters (") by writing them twice: "".
  • *
* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Specific instructions for Microsoft Excel-compatible files * *

* In order for Microsoft Excel to correcly open a CSV file —including field values with line * breaks— these rules should be followed: *

*
    *
  • Separate fields with comma (,) in English-language setups, and semi-colon (;) in * non-English-language setups (this depends on the language of the installation of MS Excel you intend * your files to be open in).
  • *
  • Separate records with Windows-style line breaks * (\r\n, U+000D + U+000A).
  • *
  • Enclose field values in double-quotes (") if they contain any non-alphanumeric characters.
  • *
  • Don't leave any whitespace between the field separator (;) and the enclosing quotes * (").
  • *
  • Escape double-quote characters (") inside field values with two double-quotes ("").
  • *
  • Use \n (U+000A, unix-style line breaks) for line breaks inside field values, * even if records are separated with Windows-style line breaks (\r\n) * [ EXCEL 2003 compatibility ].
  • *
  • Open CSV files in Excel with File -> Open..., not with Data -> Import... * The latter option will not correctly understand line breaks inside field values (up to Excel 2010).
  • *
*

* (Note unbescape will perform escaping of field values only, so it will take care of enclosing in * double-quotes, using unix-style line breaks inside values, etc. But separating fields (e.g. with ;), * delimiting records (e.g. with \r\n) and using the correct character encoding when writing CSV files * will be the responsibility of the application calling unbescape.) *

*

* The described format for Excel is also supported by OpenOffice.org Calc (File -> Open...) and also * Google Spreadsheets (File -> Import...) *

* * References * *

* The following references apply: *

* * * * @author Daniel Fernández * * @since 1.0.0 * */ public final class CsvEscape { /** *

* Perform a CSV escape operation on a String input. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeCsv(final String text) { return CsvEscapeUtil.escape(text); } /** *

* Perform a CSV escape operation on a String input, writing results to * a Writer. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCsv(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } CsvEscapeUtil.escape(new InternalStringReader(text), writer); } /** *

* Perform a CSV escape operation on a Reader input, writing results to * a Writer. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeCsv(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } CsvEscapeUtil.escape(reader, writer); } /** *

* Perform a CSV escape operation on a char[] input. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeCsv(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } CsvEscapeUtil.escape(text, offset, len, writer); } /** *

* Perform a CSV unescape operation on a String input. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeCsv(final String text) { return CsvEscapeUtil.unescape(text); } /** *

* Perform a CSV unescape operation on a String input, writing results * to a Writer. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeCsv(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } CsvEscapeUtil.unescape(new InternalStringReader(text), writer); } /** *

* Perform a CSV unescape operation on a Reader input, writing results * to a Writer. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeCsv(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } CsvEscapeUtil.unescape(reader, writer); } /** *

* Perform a CSV unescape operation on a char[] input. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeCsv(final char[] text, final int offset, final int len, final Writer writer) throws IOException{ if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } CsvEscapeUtil.unescape(text, offset, len, writer); } private CsvEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/csv/CsvEscapeUtil.java000066400000000000000000000541721311410233600300500ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.csv; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class CsvEscapeUtil { /* * CSV ESCAPE/UNESCAPE OPERATIONS * ------------------------------ * * See: http://tools.ietf.org/html/rfc4180 (de-facto standard) * http://en.wikipedia.org/wiki/Comma-separated_values * http://creativyst.com/Doc/Articles/CSV/CSV01.htm * * --------------------------------------------------------------------------------------------------------------- * NOTE: in order for Microsoft Excel to correcly open a CSV file, including field values with line breaks, * you should follow these rules when creating them, besides escaping fields: * * - Separate fields with semi-colon (';'), records with Windows-style line breaks ('\r\n', U+000D + U+000A). * - Enclose field values in double-quotes ('"') if they contain any non-alphanumeric characters. * - Don't leave any whitespace between the field separator (';') and the enclosing quotes ('"'). * - Escape double-quotes ('"') inside field values that are enclosed in double-quotes with two * double-quotes ('""'). * - Use '\n' (U+000A, unix-style line breaks) for line breaks inside field values, even if records * are separated with Windows-style line breaks ('\r\n') [ EXCEL 2003 compatibility ]. * - Open your CSV file in Excel with File -> Open..., not with Data -> Import... The latter option will * not correctly understand line breaks inside field values (up to Excel 2010). * * (Note unbescape will perform escaping of field values only, so it will take care of enclosing in * double-quotes, using unix-style line breaks inside values, etc. But separating fields (e.g. with ';'), * delimiting records (e.g. with '\r\n') and using the correct character encoding when writing CSV files * will be the responsibility of the application calling unbescape.) * --------------------------------------------------------------------------------------------------------------- * NOTE: The described format for Excel is also supported by OpenOffice.org Calc (File -> Open...) and also * Google Spreadsheets (File -> Import...) * --------------------------------------------------------------------------------------------------------------- * */ private static final char DOUBLE_QUOTE = '"'; private static final char[] TWO_DOUBLE_QUOTES = "\"\"".toCharArray(); private CsvEscapeUtil() { super(); } /* * Perform an escape operation, based on String. */ static String escape(final String text) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Shortcut: most characters will be Alphanumeric, and we won't need to do anything at * all for them. */ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { continue; } /* * At this point we know for sure we will need some kind of escape, so we * initialize the string builder. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); // If we need this, it's because we have non-alphanumeric chars. And that means // we should enclose in double-quotes. strBuilder.append(DOUBLE_QUOTE); } /* * Now we copy all the contents pending up to this point. */ if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } readOffset = i + 1; /* * Check whether the character is a double-quote (in which case, we escape it) */ if (c == DOUBLE_QUOTE) { strBuilder.append(TWO_DOUBLE_QUOTES); continue; } strBuilder.append(c); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } // If we reached here, it's because we had non-alphanumeric chars. And that means // we should enclose in double-quotes. strBuilder.append(DOUBLE_QUOTE); return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, writing the results to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } /* * Escape in CSV requires using buffers because CSV escaped text might be surrounded by quotes or not * depending on whether they contain any non-alphanumeric chars or not, which is something we cannot * know until we find any. */ int doQuote = -1; int bufferSize = 0; char[] buffer = new char[10]; int read = reader.read(buffer, 0, buffer.length); if (read < 0) { return; } char cq; while (doQuote < 0 && read >= 0) { int i = bufferSize; bufferSize += read; while (doQuote < 0 && i < bufferSize) { cq = buffer[i++]; if (!((cq >= 'a' && cq <= 'z') || (cq >= 'A' && cq <= 'Z') || (cq >= '0' && cq <= '9'))) { doQuote = 1; // We must add quotes! break; } } if (doQuote < 0 && read >= 0) { if (bufferSize == buffer.length) { // Actually, there is no room for reading more, so let's grow the buffer final char[] newBuffer = new char[buffer.length + (buffer.length / 2)]; System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); buffer = newBuffer; } read = reader.read(buffer, bufferSize, (buffer.length - bufferSize)); } } doQuote = Math.max(doQuote, 0); // 0 = no quote, 1 = quote /* * Output initial quotes, if needed */ if (doQuote == 1) { writer.write('"'); } /* * First we will output the already-checked buffer, escaping quotes as needed */ if (bufferSize > 0) { char c; for (int i = 0; i < bufferSize; i++) { c = buffer[i]; /* * Check whether the character is a double-quote (in which case, we escape it) */ if (c == DOUBLE_QUOTE) { writer.write(TWO_DOUBLE_QUOTES); } else { writer.write(c); } } } /* * Once the buffer has been processed, we will process the rest of the input by reading it on-the-fly */ if (read >= 0) { int c1, c2; // c1: current char, c2: next char c1 = -1; c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); /* * Check whether the character is a double-quote (in which case, we escape it) */ if (c1 == DOUBLE_QUOTE) { writer.write(TWO_DOUBLE_QUOTES); } else { writer.write(c1); } } } /* * Output ending quotes, if needed */ if (doQuote == 1) { writer.write('"'); } } /* * Perform an escape operation, based on char[], according to the specified level and type. */ static void escape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null || text.length == 0) { return; } final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Shortcut: most characters will be Alphanumeric, and we won't need to do anything at * all for them. */ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { continue; } /* * At this point we know for sure we will need some kind of escape, so we * initialize the string builder. */ if (readOffset == offset) { // If we need this, it's because we have non-alphanumeric chars. And that means // we should enclose in double-quotes. writer.write(DOUBLE_QUOTE); } /* * Now we copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } readOffset = i + 1; /* * Check whether the character is a double-quote (in which case, we escape it) */ if (c == DOUBLE_QUOTE) { writer.write(TWO_DOUBLE_QUOTES); continue; } writer.write(c); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } if (readOffset > offset) { // If we reached here, it's because we had non-alphanumeric chars. And that means // we should enclose in double-quotes. writer.write(DOUBLE_QUOTE); } } /* * Perform an unescape operation based on String. */ static String unescape(final String text) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; boolean isQuoted = false; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Shortcut: from an unescape point of view, we will ignore most characters */ if (i > offset && c != DOUBLE_QUOTE) { continue; } /* * Check the only character that is really involved in unescape operations: the double-quote */ if (c == DOUBLE_QUOTE) { if (i == offset) { // If the first char is a double-quote, and so is the final one, we will need // to remove them both. if (i + 1 >= max) { // Shortcut: The double-quote is the only char, just don't do anything continue; } if (text.charAt(max - 1) == DOUBLE_QUOTE) { // Confirmed: the value is enclosed in double-quotes. We should remove them. isQuoted = true; // Skip these double quotes in the final result; referenceOffset = i + 1; readOffset = i + 1; continue; } // if none of the above are true, just consider the double-quotes a normal char continue; } else { if (isQuoted && i + 2 < max) { // Value is quoted, and we are in the middle of it final char c1 = text.charAt(i + 1); if (c1 == DOUBLE_QUOTE) { // This is an escaped double-quote: skip one of the chars (= unescape) referenceOffset = i + 1; } // else just write the quotes anyway (lenient behaviour). Not the last char, so don't remove. } else if (isQuoted && i + 1 >= max) { // This is the closing-double-quote, skip referenceOffset = i + 1; } else { // else not quoted. Write the quotes anyway (lenient behaviour). continue; } } } else { // If the character is not a double-quote, we don't need to do anything at all continue; } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * Write the character * -------------------------- */ if (referenceOffset < max) { strBuilder.append(c); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } boolean isQuoted = false; int c1, c2; // c1: current char, c2: next char c2 = reader.read(); if (c2 < 0) { // Nothing to output return; } else if (c2 == DOUBLE_QUOTE) { c1 = c2; c2 = reader.read(); if (c2 < 0) { // Output is just a double-quote symbol // (...which by the way is not a valid CSV value, as a " is non-alphanumeric) writer.write(c1); return; } else { isQuoted = true; } } while (c2 >= 0) { c1 = c2; c2 = reader.read(); /* * Shortcut: from an unescape point of view, we will ignore most characters */ if (c1 != DOUBLE_QUOTE) { writer.write(c1); continue; } if (c2 < 0) { if (!isQuoted) { // Last char is double-quote. If last and value is quoted, ignore - if not, write. writer.write(c1); } continue; } else if (c2 == DOUBLE_QUOTE) { // This is an escaped double quote writer.write(DOUBLE_QUOTE); c1 = c2; c2 = reader.read(); } else { // This is a non-escaped quote, which should only happen at the end, so this is actually // non-valid CSV... but anyway, we will be lenient and just write it writer.write(DOUBLE_QUOTE); } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; boolean isQuoted = false; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Shortcut: from an unescape point of view, we will ignore most characters */ if (i > offset && c != DOUBLE_QUOTE) { continue; } /* * Check the only character that is really involved in unescape operations: the double-quote */ if (c == DOUBLE_QUOTE) { if (i == offset) { // If the first char is a double-quote, and so is the final one, we will need // to remove them both. if (i + 1 >= max) { // Shortcut: The double-quote is the only char, just don't do anything continue; } if (text[max - 1] == DOUBLE_QUOTE) { // Confirmed: the value is enclosed in double-quotes. We should remove them. isQuoted = true; // Skip these double quotes in the final result; referenceOffset = i + 1; readOffset = i + 1; continue; } // if none of the above are true, just consider the double-quotes a normal char continue; } else { if (isQuoted && i + 2 < max) { // Value is quoted, and we are in the middle of it final char c1 = text[i + 1]; if (c1 == DOUBLE_QUOTE) { // This is an escaped double-quote: skip one of the chars (= unescape) referenceOffset = i + 1; } // else just write the quotes anyway (lenient behaviour). Not the last char, so don't remove. } else if (isQuoted && i + 1 >= max) { // This is the closing-double-quote, skip referenceOffset = i + 1; } else { // else not quoted. Write the quotes anyway (lenient behaviour). continue; } } } else { // If the character is not a double-quote, we don't need to do anything at all continue; } /* * At this point we know for sure we will need some kind of unescape, so we * can copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * Write the character * -------------------------- */ if (referenceOffset < max) { writer.write(c); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/000077500000000000000000000000001311410233600246335ustar00rootroot00000000000000Html4EscapeSymbolsInitializer.java000066400000000000000000000433371311410233600333170ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.html; import java.util.Arrays; /** *

* This class initializes the {@link org.unbescape.html.HtmlEscapeSymbols#HTML4_SYMBOLS} structure. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class Html4EscapeSymbolsInitializer { static HtmlEscapeSymbols initializeHtml4() { final HtmlEscapeSymbols.References html4References = new HtmlEscapeSymbols.References(); /* * ----------------------------------------------------------------- * HTML4 NAMED CHARACTER REFERENCES (CHARACTER ENTITY REFERENCES) * See: http://www.w3.org/TR/html4/sgml/entities.html * ----------------------------------------------------------------- */ /* HTML NCRs FOR MARKUP-SIGNIFICANT CHARACTERS */ // (Note HTML 4 does not include ' as a valid NCR) html4References.addReference('"', """); html4References.addReference('&', "&"); html4References.addReference('<', "<"); html4References.addReference('>', ">"); /* HTML NCRs FOR ISO-8859-1 CHARACTERS */ html4References.addReference('\u00A0', " "); html4References.addReference('\u00A1', "¡"); html4References.addReference('\u00A2', "¢"); html4References.addReference('\u00A3', "£"); html4References.addReference('\u00A4', "¤"); html4References.addReference('\u00A5', "¥"); html4References.addReference('\u00A6', "¦"); html4References.addReference('\u00A7', "§"); html4References.addReference('\u00A8', "¨"); html4References.addReference('\u00A9', "©"); html4References.addReference('\u00AA', "ª"); html4References.addReference('\u00AB', "«"); html4References.addReference('\u00AC', "¬"); html4References.addReference('\u00AD', "­"); html4References.addReference('\u00AE', "®"); html4References.addReference('\u00AF', "¯"); html4References.addReference('\u00B0', "°"); html4References.addReference('\u00B1', "±"); html4References.addReference('\u00B2', "²"); html4References.addReference('\u00B3', "³"); html4References.addReference('\u00B4', "´"); html4References.addReference('\u00B5', "µ"); html4References.addReference('\u00B6', "¶"); html4References.addReference('\u00B7', "·"); html4References.addReference('\u00B8', "¸"); html4References.addReference('\u00B9', "¹"); html4References.addReference('\u00BA', "º"); html4References.addReference('\u00BB', "»"); html4References.addReference('\u00BC', "¼"); html4References.addReference('\u00BD', "½"); html4References.addReference('\u00BE', "¾"); html4References.addReference('\u00BF', "¿"); html4References.addReference('\u00C0', "À"); html4References.addReference('\u00C1', "Á"); html4References.addReference('\u00C2', "Â"); html4References.addReference('\u00C3', "Ã"); html4References.addReference('\u00C4', "Ä"); html4References.addReference('\u00C5', "Å"); html4References.addReference('\u00C6', "Æ"); html4References.addReference('\u00C7', "Ç"); html4References.addReference('\u00C8', "È"); html4References.addReference('\u00C9', "É"); html4References.addReference('\u00CA', "Ê"); html4References.addReference('\u00CB', "Ë"); html4References.addReference('\u00CC', "Ì"); html4References.addReference('\u00CD', "Í"); html4References.addReference('\u00CE', "Î"); html4References.addReference('\u00CF', "Ï"); html4References.addReference('\u00D0', "Ð"); html4References.addReference('\u00D1', "Ñ"); html4References.addReference('\u00D2', "Ò"); html4References.addReference('\u00D3', "Ó"); html4References.addReference('\u00D4', "Ô"); html4References.addReference('\u00D5', "Õ"); html4References.addReference('\u00D6', "Ö"); html4References.addReference('\u00D7', "×"); html4References.addReference('\u00D8', "Ø"); html4References.addReference('\u00D9', "Ù"); html4References.addReference('\u00DA', "Ú"); html4References.addReference('\u00DB', "Û"); html4References.addReference('\u00DC', "Ü"); html4References.addReference('\u00DD', "Ý"); html4References.addReference('\u00DE', "Þ"); html4References.addReference('\u00DF', "ß"); html4References.addReference('\u00E0', "à"); html4References.addReference('\u00E1', "á"); html4References.addReference('\u00E2', "â"); html4References.addReference('\u00E3', "ã"); html4References.addReference('\u00E4', "ä"); html4References.addReference('\u00E5', "å"); html4References.addReference('\u00E6', "æ"); html4References.addReference('\u00E7', "ç"); html4References.addReference('\u00E8', "è"); html4References.addReference('\u00E9', "é"); html4References.addReference('\u00EA', "ê"); html4References.addReference('\u00EB', "ë"); html4References.addReference('\u00EC', "ì"); html4References.addReference('\u00ED', "í"); html4References.addReference('\u00EE', "î"); html4References.addReference('\u00EF', "ï"); html4References.addReference('\u00F0', "ð"); html4References.addReference('\u00F1', "ñ"); html4References.addReference('\u00F2', "ò"); html4References.addReference('\u00F3', "ó"); html4References.addReference('\u00F4', "ô"); html4References.addReference('\u00F5', "õ"); html4References.addReference('\u00F6', "ö"); html4References.addReference('\u00F7', "÷"); html4References.addReference('\u00F8', "ø"); html4References.addReference('\u00F9', "ù"); html4References.addReference('\u00FA', "ú"); html4References.addReference('\u00FB', "û"); html4References.addReference('\u00FC', "ü"); html4References.addReference('\u00FD', "ý"); html4References.addReference('\u00FE', "þ"); html4References.addReference('\u00FF', "ÿ"); /* HTML NCRs FOR SYMBOLS, MATHEMATICAL SYMBOLS AND GREEK LETTERS */ /* - Greek */ html4References.addReference('\u0192', "ƒ"); html4References.addReference('\u0391', "Α"); html4References.addReference('\u0392', "Β"); html4References.addReference('\u0393', "Γ"); html4References.addReference('\u0394', "Δ"); html4References.addReference('\u0395', "Ε"); html4References.addReference('\u0396', "Ζ"); html4References.addReference('\u0397', "Η"); html4References.addReference('\u0398', "Θ"); html4References.addReference('\u0399', "Ι"); html4References.addReference('\u039A', "Κ"); html4References.addReference('\u039B', "Λ"); html4References.addReference('\u039C', "Μ"); html4References.addReference('\u039D', "Ν"); html4References.addReference('\u039E', "Ξ"); html4References.addReference('\u039F', "Ο"); html4References.addReference('\u03A0', "Π"); html4References.addReference('\u03A1', "Ρ"); html4References.addReference('\u03A3', "Σ"); html4References.addReference('\u03A4', "Τ"); html4References.addReference('\u03A5', "Υ"); html4References.addReference('\u03A6', "Φ"); html4References.addReference('\u03A7', "Χ"); html4References.addReference('\u03A8', "Ψ"); html4References.addReference('\u03A9', "Ω"); html4References.addReference('\u03B1', "α"); html4References.addReference('\u03B2', "β"); html4References.addReference('\u03B3', "γ"); html4References.addReference('\u03B4', "δ"); html4References.addReference('\u03B5', "ε"); html4References.addReference('\u03B6', "ζ"); html4References.addReference('\u03B7', "η"); html4References.addReference('\u03B8', "θ"); html4References.addReference('\u03B9', "ι"); html4References.addReference('\u03BA', "κ"); html4References.addReference('\u03BB', "λ"); html4References.addReference('\u03BC', "μ"); html4References.addReference('\u03BD', "ν"); html4References.addReference('\u03BE', "ξ"); html4References.addReference('\u03BF', "ο"); html4References.addReference('\u03C0', "π"); html4References.addReference('\u03C1', "ρ"); html4References.addReference('\u03C2', "ς"); html4References.addReference('\u03C3', "σ"); html4References.addReference('\u03C4', "τ"); html4References.addReference('\u03C5', "υ"); html4References.addReference('\u03C6', "φ"); html4References.addReference('\u03C7', "χ"); html4References.addReference('\u03C8', "ψ"); html4References.addReference('\u03C9', "ω"); html4References.addReference('\u03D1', "ϑ"); html4References.addReference('\u03D2', "ϒ"); html4References.addReference('\u03D6', "ϖ"); /* - General punctuation */ html4References.addReference('\u2022', "•"); html4References.addReference('\u2026', "…"); html4References.addReference('\u2032', "′"); html4References.addReference('\u2033', "″"); html4References.addReference('\u203E', "‾"); html4References.addReference('\u2044', "⁄"); /* - Letter-like symbols */ html4References.addReference('\u2118', "℘"); html4References.addReference('\u2111', "ℑ"); html4References.addReference('\u211C', "ℜ"); html4References.addReference('\u2122', "™"); html4References.addReference('\u2135', "ℵ"); /* - Arrows */ html4References.addReference('\u2190', "←"); html4References.addReference('\u2191', "↑"); html4References.addReference('\u2192', "→"); html4References.addReference('\u2193', "↓"); html4References.addReference('\u2194', "↔"); html4References.addReference('\u21B5', "↵"); html4References.addReference('\u21D0', "⇐"); html4References.addReference('\u21D1', "⇑"); html4References.addReference('\u21D2', "⇒"); html4References.addReference('\u21D3', "⇓"); html4References.addReference('\u21D4', "⇔"); /* - Mathematical operators */ html4References.addReference('\u2200', "∀"); html4References.addReference('\u2202', "∂"); html4References.addReference('\u2203', "∃"); html4References.addReference('\u2205', "∅"); html4References.addReference('\u2207', "∇"); html4References.addReference('\u2208', "∈"); html4References.addReference('\u2209', "∉"); html4References.addReference('\u220B', "∋"); html4References.addReference('\u220F', "∏"); html4References.addReference('\u2211', "∑"); html4References.addReference('\u2212', "−"); html4References.addReference('\u2217', "∗"); html4References.addReference('\u221A', "√"); html4References.addReference('\u221D', "∝"); html4References.addReference('\u221E', "∞"); html4References.addReference('\u2220', "∠"); html4References.addReference('\u2227', "∧"); html4References.addReference('\u2228', "∨"); html4References.addReference('\u2229', "∩"); html4References.addReference('\u222A', "∪"); html4References.addReference('\u222B', "∫"); html4References.addReference('\u2234', "∴"); html4References.addReference('\u223C', "∼"); html4References.addReference('\u2245', "≅"); html4References.addReference('\u2248', "≈"); html4References.addReference('\u2260', "≠"); html4References.addReference('\u2261', "≡"); html4References.addReference('\u2264', "≤"); html4References.addReference('\u2265', "≥"); html4References.addReference('\u2282', "⊂"); html4References.addReference('\u2283', "⊃"); html4References.addReference('\u2284', "⊄"); html4References.addReference('\u2286', "⊆"); html4References.addReference('\u2287', "⊇"); html4References.addReference('\u2295', "⊕"); html4References.addReference('\u2297', "⊗"); html4References.addReference('\u22A5', "⊥"); html4References.addReference('\u22C5', "⋅"); /* - Miscellaneous technical */ html4References.addReference('\u2308', "⌈"); html4References.addReference('\u2309', "⌉"); html4References.addReference('\u230A', "⌊"); html4References.addReference('\u230B', "⌋"); html4References.addReference('\u2329', "⟨"); html4References.addReference('\u232A', "⟩"); /* - Geometric shapes */ html4References.addReference('\u25CA', "◊"); html4References.addReference('\u2660', "♠"); html4References.addReference('\u2663', "♣"); html4References.addReference('\u2665', "♥"); html4References.addReference('\u2666', "♦"); /* HTML NCRs FOR INTERNATIONALIZATION CHARACTERS */ /* - Latin Extended-A */ html4References.addReference('\u0152', "Œ"); html4References.addReference('\u0153', "œ"); html4References.addReference('\u0160', "Š"); html4References.addReference('\u0161', "š"); html4References.addReference('\u0178', "Ÿ"); /* - Spacing modifier letters */ html4References.addReference('\u02C6', "ˆ"); html4References.addReference('\u02DC', "˜"); /* - General punctuation */ html4References.addReference('\u2002', " "); html4References.addReference('\u2003', " "); html4References.addReference('\u2009', " "); html4References.addReference('\u200C', "‌"); html4References.addReference('\u200D', "‍"); html4References.addReference('\u200E', "‎"); html4References.addReference('\u200F', "‏"); html4References.addReference('\u2013', "–"); html4References.addReference('\u2014', "—"); html4References.addReference('\u2018', "‘"); html4References.addReference('\u2019', "’"); html4References.addReference('\u201A', "‚"); html4References.addReference('\u201C', "“"); html4References.addReference('\u201D', "”"); html4References.addReference('\u201E', "„"); html4References.addReference('\u2020', "†"); html4References.addReference('\u2021', "‡"); html4References.addReference('\u2030', "‰"); html4References.addReference('\u2039', "‹"); html4References.addReference('\u203A', "›"); html4References.addReference('\u20AC', "€"); /* * Initialization of escape levels. * Defined levels : * * - Level 0 : Only markup-significant characters except the apostrophe (') * - Level 1 : Only markup-significant characters (including the apostrophe) * - Level 2 : Markup-significant characters plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters */ final byte[] escapeLevels = new byte[0x7f + 2]; Arrays.fill(escapeLevels, (byte)3); for (char c = 'A'; c <= 'Z'; c++) { escapeLevels[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { escapeLevels[c] = 4; } for (char c = '0'; c <= '9'; c++) { escapeLevels[c] = 4; } escapeLevels['\''] = 1; escapeLevels['"'] = 0; escapeLevels['<'] = 0; escapeLevels['>'] = 0; escapeLevels['&'] = 0; escapeLevels[0x7f + 1] = 2; return new HtmlEscapeSymbols(html4References, escapeLevels); } private Html4EscapeSymbolsInitializer() { super(); } } Html5EscapeSymbolsInitializer.java000066400000000000000000004055301311410233600333150ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.html; import java.util.Arrays; /** *

* This class initializes the {@link org.unbescape.html.HtmlEscapeSymbols#HTML5_SYMBOLS} structure. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class Html5EscapeSymbolsInitializer { static HtmlEscapeSymbols initializeHtml5() { final HtmlEscapeSymbols.References html5References = new HtmlEscapeSymbols.References(); /* * -------------------------------------------------------------------------------------------------- * HTML5 NAMED CHARACTER REFERENCES * See: http://www.w3.org/TR/html5/syntax.html#named-character-references [HTML5] * http://www.w3.org/TR/html51/syntax.html#named-character-references [HTML 5.1] * -------------------------------------------------------------------------------------------------- */ html5References.addReference( 9, " "); html5References.addReference( 10, " "); html5References.addReference( 33, "!"); html5References.addReference( 34, """); html5References.addReference( 34, """); html5References.addReference( 34, """); html5References.addReference( 34, """); html5References.addReference( 35, "#"); html5References.addReference( 36, "$"); html5References.addReference( 37, "%"); html5References.addReference( 38, "&"); html5References.addReference( 38, "&"); html5References.addReference( 38, "&"); html5References.addReference( 38, "&"); html5References.addReference( 39, "'"); html5References.addReference( 40, "("); html5References.addReference( 41, ")"); html5References.addReference( 42, "*"); html5References.addReference( 42, "*"); html5References.addReference( 43, "+"); html5References.addReference( 44, ","); html5References.addReference( 46, "."); html5References.addReference( 47, "/"); html5References.addReference( 58, ":"); html5References.addReference( 59, ";"); html5References.addReference( 60, "<"); html5References.addReference( 60, "<"); html5References.addReference( 60, "<"); html5References.addReference( 60, "<"); html5References.addReference( 60, 8402, "<⃒"); html5References.addReference( 61, "="); html5References.addReference( 61, 8421, "=⃥"); html5References.addReference( 62, ">"); html5References.addReference( 62, ">"); html5References.addReference( 62, ">"); html5References.addReference( 62, ">"); html5References.addReference( 62, 8402, ">⃒"); html5References.addReference( 63, "?"); html5References.addReference( 64, "@"); html5References.addReference( 91, "["); html5References.addReference( 91, "["); html5References.addReference( 92, "\"); html5References.addReference( 93, "]"); html5References.addReference( 93, "]"); html5References.addReference( 94, "^"); html5References.addReference( 95, "_"); html5References.addReference( 95, "_"); html5References.addReference( 96, "`"); html5References.addReference( 96, "`"); html5References.addReference( 102, 106, "fj"); html5References.addReference( 123, "{"); html5References.addReference( 123, "{"); html5References.addReference( 124, "|"); html5References.addReference( 124, "|"); html5References.addReference( 124, "|"); html5References.addReference( 125, "}"); html5References.addReference( 125, "}"); html5References.addReference( 160, " "); html5References.addReference( 160, " "); html5References.addReference( 160, " "); html5References.addReference( 161, "¡"); html5References.addReference( 161, "¡"); html5References.addReference( 162, "¢"); html5References.addReference( 162, "¢"); html5References.addReference( 163, "£"); html5References.addReference( 163, "£"); html5References.addReference( 164, "¤"); html5References.addReference( 164, "¤"); html5References.addReference( 165, "¥"); html5References.addReference( 165, "¥"); html5References.addReference( 166, "¦"); html5References.addReference( 166, "¦"); html5References.addReference( 167, "§"); html5References.addReference( 167, "§"); html5References.addReference( 168, "¨"); html5References.addReference( 168, "¨"); html5References.addReference( 168, "¨"); html5References.addReference( 168, "¨"); html5References.addReference( 168, "¨"); html5References.addReference( 169, "©"); html5References.addReference( 169, "©"); html5References.addReference( 169, "©"); html5References.addReference( 169, "©"); html5References.addReference( 170, "ª"); html5References.addReference( 170, "ª"); html5References.addReference( 171, "«"); html5References.addReference( 171, "«"); html5References.addReference( 172, "¬"); html5References.addReference( 172, "¬"); html5References.addReference( 173, "­"); html5References.addReference( 173, "­"); html5References.addReference( 174, "®"); html5References.addReference( 174, "®"); html5References.addReference( 174, "®"); html5References.addReference( 174, "®"); html5References.addReference( 174, "®"); html5References.addReference( 175, "¯"); html5References.addReference( 175, "¯"); html5References.addReference( 175, "¯"); html5References.addReference( 176, "°"); html5References.addReference( 176, "°"); html5References.addReference( 177, "±"); html5References.addReference( 177, "±"); html5References.addReference( 177, "±"); html5References.addReference( 177, "±"); html5References.addReference( 178, "²"); html5References.addReference( 178, "²"); html5References.addReference( 179, "³"); html5References.addReference( 179, "³"); html5References.addReference( 180, "´"); html5References.addReference( 180, "´"); html5References.addReference( 180, "´"); html5References.addReference( 181, "µ"); html5References.addReference( 181, "µ"); html5References.addReference( 182, "¶"); html5References.addReference( 182, "¶"); html5References.addReference( 183, "·"); html5References.addReference( 183, "·"); html5References.addReference( 183, "·"); html5References.addReference( 183, "·"); html5References.addReference( 184, "¸"); html5References.addReference( 184, "¸"); html5References.addReference( 184, "¸"); html5References.addReference( 185, "¹"); html5References.addReference( 185, "¹"); html5References.addReference( 186, "º"); html5References.addReference( 186, "º"); html5References.addReference( 187, "»"); html5References.addReference( 187, "»"); html5References.addReference( 188, "¼"); html5References.addReference( 188, "¼"); html5References.addReference( 189, "½"); html5References.addReference( 189, "½"); html5References.addReference( 189, "½"); html5References.addReference( 190, "¾"); html5References.addReference( 190, "¾"); html5References.addReference( 191, "¿"); html5References.addReference( 191, "¿"); html5References.addReference( 192, "À"); html5References.addReference( 192, "À"); html5References.addReference( 193, "Á"); html5References.addReference( 193, "Á"); html5References.addReference( 194, "Â"); html5References.addReference( 194, "Â"); html5References.addReference( 195, "Ã"); html5References.addReference( 195, "Ã"); html5References.addReference( 196, "Ä"); html5References.addReference( 196, "Ä"); html5References.addReference( 197, "Å"); html5References.addReference( 197, "Å"); html5References.addReference( 197, "Å"); html5References.addReference( 198, "Æ"); html5References.addReference( 198, "Æ"); html5References.addReference( 199, "Ç"); html5References.addReference( 199, "Ç"); html5References.addReference( 200, "È"); html5References.addReference( 200, "È"); html5References.addReference( 201, "É"); html5References.addReference( 201, "É"); html5References.addReference( 202, "Ê"); html5References.addReference( 202, "Ê"); html5References.addReference( 203, "Ë"); html5References.addReference( 203, "Ë"); html5References.addReference( 204, "Ì"); html5References.addReference( 204, "Ì"); html5References.addReference( 205, "Í"); html5References.addReference( 205, "Í"); html5References.addReference( 206, "Î"); html5References.addReference( 206, "Î"); html5References.addReference( 207, "Ï"); html5References.addReference( 207, "Ï"); html5References.addReference( 208, "Ð"); html5References.addReference( 208, "Ð"); html5References.addReference( 209, "Ñ"); html5References.addReference( 209, "Ñ"); html5References.addReference( 210, "Ò"); html5References.addReference( 210, "Ò"); html5References.addReference( 211, "Ó"); html5References.addReference( 211, "Ó"); html5References.addReference( 212, "Ô"); html5References.addReference( 212, "Ô"); html5References.addReference( 213, "Õ"); html5References.addReference( 213, "Õ"); html5References.addReference( 214, "Ö"); html5References.addReference( 214, "Ö"); html5References.addReference( 215, "×"); html5References.addReference( 215, "×"); html5References.addReference( 216, "Ø"); html5References.addReference( 216, "Ø"); html5References.addReference( 217, "Ù"); html5References.addReference( 217, "Ù"); html5References.addReference( 218, "Ú"); html5References.addReference( 218, "Ú"); html5References.addReference( 219, "Û"); html5References.addReference( 219, "Û"); html5References.addReference( 220, "Ü"); html5References.addReference( 220, "Ü"); html5References.addReference( 221, "Ý"); html5References.addReference( 221, "Ý"); html5References.addReference( 222, "Þ"); html5References.addReference( 222, "Þ"); html5References.addReference( 223, "ß"); html5References.addReference( 223, "ß"); html5References.addReference( 224, "à"); html5References.addReference( 224, "à"); html5References.addReference( 225, "á"); html5References.addReference( 225, "á"); html5References.addReference( 226, "â"); html5References.addReference( 226, "â"); html5References.addReference( 227, "ã"); html5References.addReference( 227, "ã"); html5References.addReference( 228, "ä"); html5References.addReference( 228, "ä"); html5References.addReference( 229, "å"); html5References.addReference( 229, "å"); html5References.addReference( 230, "æ"); html5References.addReference( 230, "æ"); html5References.addReference( 231, "ç"); html5References.addReference( 231, "ç"); html5References.addReference( 232, "è"); html5References.addReference( 232, "è"); html5References.addReference( 233, "é"); html5References.addReference( 233, "é"); html5References.addReference( 234, "ê"); html5References.addReference( 234, "ê"); html5References.addReference( 235, "ë"); html5References.addReference( 235, "ë"); html5References.addReference( 236, "ì"); html5References.addReference( 236, "ì"); html5References.addReference( 237, "í"); html5References.addReference( 237, "í"); html5References.addReference( 238, "î"); html5References.addReference( 238, "î"); html5References.addReference( 239, "ï"); html5References.addReference( 239, "ï"); html5References.addReference( 240, "ð"); html5References.addReference( 240, "ð"); html5References.addReference( 241, "ñ"); html5References.addReference( 241, "ñ"); html5References.addReference( 242, "ò"); html5References.addReference( 242, "ò"); html5References.addReference( 243, "ó"); html5References.addReference( 243, "ó"); html5References.addReference( 244, "ô"); html5References.addReference( 244, "ô"); html5References.addReference( 245, "õ"); html5References.addReference( 245, "õ"); html5References.addReference( 246, "ö"); html5References.addReference( 246, "ö"); html5References.addReference( 247, "÷"); html5References.addReference( 247, "÷"); html5References.addReference( 247, "÷"); html5References.addReference( 248, "ø"); html5References.addReference( 248, "ø"); html5References.addReference( 249, "ù"); html5References.addReference( 249, "ù"); html5References.addReference( 250, "ú"); html5References.addReference( 250, "ú"); html5References.addReference( 251, "û"); html5References.addReference( 251, "û"); html5References.addReference( 252, "ü"); html5References.addReference( 252, "ü"); html5References.addReference( 253, "ý"); html5References.addReference( 253, "ý"); html5References.addReference( 254, "þ"); html5References.addReference( 254, "þ"); html5References.addReference( 255, "ÿ"); html5References.addReference( 255, "ÿ"); html5References.addReference( 256, "Ā"); html5References.addReference( 257, "ā"); html5References.addReference( 258, "Ă"); html5References.addReference( 259, "ă"); html5References.addReference( 260, "Ą"); html5References.addReference( 261, "ą"); html5References.addReference( 262, "Ć"); html5References.addReference( 263, "ć"); html5References.addReference( 264, "Ĉ"); html5References.addReference( 265, "ĉ"); html5References.addReference( 266, "Ċ"); html5References.addReference( 267, "ċ"); html5References.addReference( 268, "Č"); html5References.addReference( 269, "č"); html5References.addReference( 270, "Ď"); html5References.addReference( 271, "ď"); html5References.addReference( 272, "Đ"); html5References.addReference( 273, "đ"); html5References.addReference( 274, "Ē"); html5References.addReference( 275, "ē"); html5References.addReference( 278, "Ė"); html5References.addReference( 279, "ė"); html5References.addReference( 280, "Ę"); html5References.addReference( 281, "ę"); html5References.addReference( 282, "Ě"); html5References.addReference( 283, "ě"); html5References.addReference( 284, "Ĝ"); html5References.addReference( 285, "ĝ"); html5References.addReference( 286, "Ğ"); html5References.addReference( 287, "ğ"); html5References.addReference( 288, "Ġ"); html5References.addReference( 289, "ġ"); html5References.addReference( 290, "Ģ"); html5References.addReference( 292, "Ĥ"); html5References.addReference( 293, "ĥ"); html5References.addReference( 294, "Ħ"); html5References.addReference( 295, "ħ"); html5References.addReference( 296, "Ĩ"); html5References.addReference( 297, "ĩ"); html5References.addReference( 298, "Ī"); html5References.addReference( 299, "ī"); html5References.addReference( 302, "Į"); html5References.addReference( 303, "į"); html5References.addReference( 304, "İ"); html5References.addReference( 305, "ı"); html5References.addReference( 305, "ı"); html5References.addReference( 306, "IJ"); html5References.addReference( 307, "ij"); html5References.addReference( 308, "Ĵ"); html5References.addReference( 309, "ĵ"); html5References.addReference( 310, "Ķ"); html5References.addReference( 311, "ķ"); html5References.addReference( 312, "ĸ"); html5References.addReference( 313, "Ĺ"); html5References.addReference( 314, "ĺ"); html5References.addReference( 315, "Ļ"); html5References.addReference( 316, "ļ"); html5References.addReference( 317, "Ľ"); html5References.addReference( 318, "ľ"); html5References.addReference( 319, "Ŀ"); html5References.addReference( 320, "ŀ"); html5References.addReference( 321, "Ł"); html5References.addReference( 322, "ł"); html5References.addReference( 323, "Ń"); html5References.addReference( 324, "ń"); html5References.addReference( 325, "Ņ"); html5References.addReference( 326, "ņ"); html5References.addReference( 327, "Ň"); html5References.addReference( 328, "ň"); html5References.addReference( 329, "ʼn"); html5References.addReference( 330, "Ŋ"); html5References.addReference( 331, "ŋ"); html5References.addReference( 332, "Ō"); html5References.addReference( 333, "ō"); html5References.addReference( 336, "Ő"); html5References.addReference( 337, "ő"); html5References.addReference( 338, "Œ"); html5References.addReference( 339, "œ"); html5References.addReference( 340, "Ŕ"); html5References.addReference( 341, "ŕ"); html5References.addReference( 342, "Ŗ"); html5References.addReference( 343, "ŗ"); html5References.addReference( 344, "Ř"); html5References.addReference( 345, "ř"); html5References.addReference( 346, "Ś"); html5References.addReference( 347, "ś"); html5References.addReference( 348, "Ŝ"); html5References.addReference( 349, "ŝ"); html5References.addReference( 350, "Ş"); html5References.addReference( 351, "ş"); html5References.addReference( 352, "Š"); html5References.addReference( 353, "š"); html5References.addReference( 354, "Ţ"); html5References.addReference( 355, "ţ"); html5References.addReference( 356, "Ť"); html5References.addReference( 357, "ť"); html5References.addReference( 358, "Ŧ"); html5References.addReference( 359, "ŧ"); html5References.addReference( 360, "Ũ"); html5References.addReference( 361, "ũ"); html5References.addReference( 362, "Ū"); html5References.addReference( 363, "ū"); html5References.addReference( 364, "Ŭ"); html5References.addReference( 365, "ŭ"); html5References.addReference( 366, "Ů"); html5References.addReference( 367, "ů"); html5References.addReference( 368, "Ű"); html5References.addReference( 369, "ű"); html5References.addReference( 370, "Ų"); html5References.addReference( 371, "ų"); html5References.addReference( 372, "Ŵ"); html5References.addReference( 373, "ŵ"); html5References.addReference( 374, "Ŷ"); html5References.addReference( 375, "ŷ"); html5References.addReference( 376, "Ÿ"); html5References.addReference( 377, "Ź"); html5References.addReference( 378, "ź"); html5References.addReference( 379, "Ż"); html5References.addReference( 380, "ż"); html5References.addReference( 381, "Ž"); html5References.addReference( 382, "ž"); html5References.addReference( 402, "ƒ"); html5References.addReference( 437, "Ƶ"); html5References.addReference( 501, "ǵ"); html5References.addReference( 567, "ȷ"); html5References.addReference( 710, "ˆ"); html5References.addReference( 711, "ˇ"); html5References.addReference( 711, "ˇ"); html5References.addReference( 728, "˘"); html5References.addReference( 728, "˘"); html5References.addReference( 729, "˙"); html5References.addReference( 729, "˙"); html5References.addReference( 730, "˚"); html5References.addReference( 731, "˛"); html5References.addReference( 732, "˜"); html5References.addReference( 732, "˜"); html5References.addReference( 733, "˝"); html5References.addReference( 733, "˝"); html5References.addReference( 785, "̑"); html5References.addReference( 913, "Α"); html5References.addReference( 914, "Β"); html5References.addReference( 915, "Γ"); html5References.addReference( 916, "Δ"); html5References.addReference( 917, "Ε"); html5References.addReference( 918, "Ζ"); html5References.addReference( 919, "Η"); html5References.addReference( 920, "Θ"); html5References.addReference( 921, "Ι"); html5References.addReference( 922, "Κ"); html5References.addReference( 923, "Λ"); html5References.addReference( 924, "Μ"); html5References.addReference( 925, "Ν"); html5References.addReference( 926, "Ξ"); html5References.addReference( 927, "Ο"); html5References.addReference( 928, "Π"); html5References.addReference( 929, "Ρ"); html5References.addReference( 931, "Σ"); html5References.addReference( 932, "Τ"); html5References.addReference( 933, "Υ"); html5References.addReference( 934, "Φ"); html5References.addReference( 935, "Χ"); html5References.addReference( 936, "Ψ"); html5References.addReference( 937, "Ω"); html5References.addReference( 937, "Ω"); html5References.addReference( 945, "α"); html5References.addReference( 946, "β"); html5References.addReference( 947, "γ"); html5References.addReference( 948, "δ"); html5References.addReference( 949, "ε"); html5References.addReference( 949, "ε"); html5References.addReference( 950, "ζ"); html5References.addReference( 951, "η"); html5References.addReference( 952, "θ"); html5References.addReference( 953, "ι"); html5References.addReference( 954, "κ"); html5References.addReference( 955, "λ"); html5References.addReference( 956, "μ"); html5References.addReference( 957, "ν"); html5References.addReference( 958, "ξ"); html5References.addReference( 959, "ο"); html5References.addReference( 960, "π"); html5References.addReference( 961, "ρ"); html5References.addReference( 962, "ς"); html5References.addReference( 962, "ς"); html5References.addReference( 962, "ς"); html5References.addReference( 963, "σ"); html5References.addReference( 964, "τ"); html5References.addReference( 965, "υ"); html5References.addReference( 965, "υ"); html5References.addReference( 966, "φ"); html5References.addReference( 967, "χ"); html5References.addReference( 968, "ψ"); html5References.addReference( 969, "ω"); html5References.addReference( 977, "ϑ"); html5References.addReference( 977, "ϑ"); html5References.addReference( 977, "ϑ"); html5References.addReference( 978, "ϒ"); html5References.addReference( 978, "ϒ"); html5References.addReference( 981, "ϕ"); html5References.addReference( 981, "ϕ"); html5References.addReference( 981, "ϕ"); html5References.addReference( 982, "ϖ"); html5References.addReference( 982, "ϖ"); html5References.addReference( 988, "Ϝ"); html5References.addReference( 989, "ϝ"); html5References.addReference( 989, "ϝ"); html5References.addReference( 1008, "ϰ"); html5References.addReference( 1008, "ϰ"); html5References.addReference( 1009, "ϱ"); html5References.addReference( 1009, "ϱ"); html5References.addReference( 1013, "ϵ"); html5References.addReference( 1013, "ϵ"); html5References.addReference( 1013, "ϵ"); html5References.addReference( 1014, "϶"); html5References.addReference( 1014, "϶"); html5References.addReference( 1025, "Ё"); html5References.addReference( 1026, "Ђ"); html5References.addReference( 1027, "Ѓ"); html5References.addReference( 1028, "Є"); html5References.addReference( 1029, "Ѕ"); html5References.addReference( 1030, "І"); html5References.addReference( 1031, "Ї"); html5References.addReference( 1032, "Ј"); html5References.addReference( 1033, "Љ"); html5References.addReference( 1034, "Њ"); html5References.addReference( 1035, "Ћ"); html5References.addReference( 1036, "Ќ"); html5References.addReference( 1038, "Ў"); html5References.addReference( 1039, "Џ"); html5References.addReference( 1040, "А"); html5References.addReference( 1041, "Б"); html5References.addReference( 1042, "В"); html5References.addReference( 1043, "Г"); html5References.addReference( 1044, "Д"); html5References.addReference( 1045, "Е"); html5References.addReference( 1046, "Ж"); html5References.addReference( 1047, "З"); html5References.addReference( 1048, "И"); html5References.addReference( 1049, "Й"); html5References.addReference( 1050, "К"); html5References.addReference( 1051, "Л"); html5References.addReference( 1052, "М"); html5References.addReference( 1053, "Н"); html5References.addReference( 1054, "О"); html5References.addReference( 1055, "П"); html5References.addReference( 1056, "Р"); html5References.addReference( 1057, "С"); html5References.addReference( 1058, "Т"); html5References.addReference( 1059, "У"); html5References.addReference( 1060, "Ф"); html5References.addReference( 1061, "Х"); html5References.addReference( 1062, "Ц"); html5References.addReference( 1063, "Ч"); html5References.addReference( 1064, "Ш"); html5References.addReference( 1065, "Щ"); html5References.addReference( 1066, "Ъ"); html5References.addReference( 1067, "Ы"); html5References.addReference( 1068, "Ь"); html5References.addReference( 1069, "Э"); html5References.addReference( 1070, "Ю"); html5References.addReference( 1071, "Я"); html5References.addReference( 1072, "а"); html5References.addReference( 1073, "б"); html5References.addReference( 1074, "в"); html5References.addReference( 1075, "г"); html5References.addReference( 1076, "д"); html5References.addReference( 1077, "е"); html5References.addReference( 1078, "ж"); html5References.addReference( 1079, "з"); html5References.addReference( 1080, "и"); html5References.addReference( 1081, "й"); html5References.addReference( 1082, "к"); html5References.addReference( 1083, "л"); html5References.addReference( 1084, "м"); html5References.addReference( 1085, "н"); html5References.addReference( 1086, "о"); html5References.addReference( 1087, "п"); html5References.addReference( 1088, "р"); html5References.addReference( 1089, "с"); html5References.addReference( 1090, "т"); html5References.addReference( 1091, "у"); html5References.addReference( 1092, "ф"); html5References.addReference( 1093, "х"); html5References.addReference( 1094, "ц"); html5References.addReference( 1095, "ч"); html5References.addReference( 1096, "ш"); html5References.addReference( 1097, "щ"); html5References.addReference( 1098, "ъ"); html5References.addReference( 1099, "ы"); html5References.addReference( 1100, "ь"); html5References.addReference( 1101, "э"); html5References.addReference( 1102, "ю"); html5References.addReference( 1103, "я"); html5References.addReference( 1105, "ё"); html5References.addReference( 1106, "ђ"); html5References.addReference( 1107, "ѓ"); html5References.addReference( 1108, "є"); html5References.addReference( 1109, "ѕ"); html5References.addReference( 1110, "і"); html5References.addReference( 1111, "ї"); html5References.addReference( 1112, "ј"); html5References.addReference( 1113, "љ"); html5References.addReference( 1114, "њ"); html5References.addReference( 1115, "ћ"); html5References.addReference( 1116, "ќ"); html5References.addReference( 1118, "ў"); html5References.addReference( 1119, "џ"); html5References.addReference( 8194, " "); html5References.addReference( 8195, " "); html5References.addReference( 8196, " "); html5References.addReference( 8197, " "); html5References.addReference( 8199, " "); html5References.addReference( 8200, " "); html5References.addReference( 8201, " "); html5References.addReference( 8201, " "); html5References.addReference( 8202, " "); html5References.addReference( 8202, " "); html5References.addReference( 8203, "​"); html5References.addReference( 8203, "​"); html5References.addReference( 8203, "​"); html5References.addReference( 8203, "​"); html5References.addReference( 8203, "​"); html5References.addReference( 8204, "‌"); html5References.addReference( 8205, "‍"); html5References.addReference( 8206, "‎"); html5References.addReference( 8207, "‏"); html5References.addReference( 8208, "‐"); html5References.addReference( 8208, "‐"); html5References.addReference( 8211, "–"); html5References.addReference( 8212, "—"); html5References.addReference( 8213, "―"); html5References.addReference( 8214, "‖"); html5References.addReference( 8214, "‖"); html5References.addReference( 8216, "‘"); html5References.addReference( 8216, "‘"); html5References.addReference( 8217, "’"); html5References.addReference( 8217, "’"); html5References.addReference( 8217, "’"); html5References.addReference( 8218, "‚"); html5References.addReference( 8218, "‚"); html5References.addReference( 8220, "“"); html5References.addReference( 8220, "“"); html5References.addReference( 8221, "”"); html5References.addReference( 8221, "”"); html5References.addReference( 8221, "”"); html5References.addReference( 8222, "„"); html5References.addReference( 8222, "„"); html5References.addReference( 8224, "†"); html5References.addReference( 8225, "‡"); html5References.addReference( 8225, "‡"); html5References.addReference( 8226, "•"); html5References.addReference( 8226, "•"); html5References.addReference( 8229, "‥"); html5References.addReference( 8230, "…"); html5References.addReference( 8230, "…"); html5References.addReference( 8240, "‰"); html5References.addReference( 8241, "‱"); html5References.addReference( 8242, "′"); html5References.addReference( 8243, "″"); html5References.addReference( 8244, "‴"); html5References.addReference( 8245, "‵"); html5References.addReference( 8245, "‵"); html5References.addReference( 8249, "‹"); html5References.addReference( 8250, "›"); html5References.addReference( 8254, "‾"); html5References.addReference( 8254, "‾"); html5References.addReference( 8257, "⁁"); html5References.addReference( 8259, "⁃"); html5References.addReference( 8260, "⁄"); html5References.addReference( 8271, "⁏"); html5References.addReference( 8279, "⁗"); html5References.addReference( 8287, " "); html5References.addReference( 8287, 8202, "  "); html5References.addReference( 8288, "⁠"); html5References.addReference( 8289, "⁡"); html5References.addReference( 8289, "⁡"); html5References.addReference( 8290, "⁢"); html5References.addReference( 8290, "⁢"); html5References.addReference( 8291, "⁣"); html5References.addReference( 8291, "⁣"); html5References.addReference( 8364, "€"); html5References.addReference( 8411, "⃛"); html5References.addReference( 8411, "⃛"); html5References.addReference( 8412, "⃜"); html5References.addReference( 8450, "ℂ"); html5References.addReference( 8450, "ℂ"); html5References.addReference( 8453, "℅"); html5References.addReference( 8458, "ℊ"); html5References.addReference( 8459, "ℋ"); html5References.addReference( 8459, "ℋ"); html5References.addReference( 8459, "ℋ"); html5References.addReference( 8460, "ℌ"); html5References.addReference( 8460, "ℌ"); html5References.addReference( 8461, "ℍ"); html5References.addReference( 8461, "ℍ"); html5References.addReference( 8462, "ℎ"); html5References.addReference( 8463, "ℏ"); html5References.addReference( 8463, "ℏ"); html5References.addReference( 8463, "ℏ"); html5References.addReference( 8463, "ℏ"); html5References.addReference( 8464, "ℐ"); html5References.addReference( 8464, "ℐ"); html5References.addReference( 8465, "ℑ"); html5References.addReference( 8465, "ℑ"); html5References.addReference( 8465, "ℑ"); html5References.addReference( 8465, "ℑ"); html5References.addReference( 8466, "ℒ"); html5References.addReference( 8466, "ℒ"); html5References.addReference( 8466, "ℒ"); html5References.addReference( 8467, "ℓ"); html5References.addReference( 8469, "ℕ"); html5References.addReference( 8469, "ℕ"); html5References.addReference( 8470, "№"); html5References.addReference( 8471, "℗"); html5References.addReference( 8472, "℘"); html5References.addReference( 8472, "℘"); html5References.addReference( 8473, "ℙ"); html5References.addReference( 8473, "ℙ"); html5References.addReference( 8474, "ℚ"); html5References.addReference( 8474, "ℚ"); html5References.addReference( 8475, "ℛ"); html5References.addReference( 8475, "ℛ"); html5References.addReference( 8476, "ℜ"); html5References.addReference( 8476, "ℜ"); html5References.addReference( 8476, "ℜ"); html5References.addReference( 8476, "ℜ"); html5References.addReference( 8477, "ℝ"); html5References.addReference( 8477, "ℝ"); html5References.addReference( 8478, "℞"); html5References.addReference( 8482, "™"); html5References.addReference( 8482, "™"); html5References.addReference( 8484, "ℤ"); html5References.addReference( 8484, "ℤ"); html5References.addReference( 8487, "℧"); html5References.addReference( 8488, "ℨ"); html5References.addReference( 8488, "ℨ"); html5References.addReference( 8489, "℩"); html5References.addReference( 8492, "ℬ"); html5References.addReference( 8492, "ℬ"); html5References.addReference( 8492, "ℬ"); html5References.addReference( 8493, "ℭ"); html5References.addReference( 8493, "ℭ"); html5References.addReference( 8495, "ℯ"); html5References.addReference( 8496, "ℰ"); html5References.addReference( 8496, "ℰ"); html5References.addReference( 8497, "ℱ"); html5References.addReference( 8497, "ℱ"); html5References.addReference( 8499, "ℳ"); html5References.addReference( 8499, "ℳ"); html5References.addReference( 8499, "ℳ"); html5References.addReference( 8500, "ℴ"); html5References.addReference( 8500, "ℴ"); html5References.addReference( 8500, "ℴ"); html5References.addReference( 8501, "ℵ"); html5References.addReference( 8501, "ℵ"); html5References.addReference( 8502, "ℶ"); html5References.addReference( 8503, "ℷ"); html5References.addReference( 8504, "ℸ"); html5References.addReference( 8517, "ⅅ"); html5References.addReference( 8517, "ⅅ"); html5References.addReference( 8518, "ⅆ"); html5References.addReference( 8518, "ⅆ"); html5References.addReference( 8519, "ⅇ"); html5References.addReference( 8519, "ⅇ"); html5References.addReference( 8519, "ⅇ"); html5References.addReference( 8520, "ⅈ"); html5References.addReference( 8520, "ⅈ"); html5References.addReference( 8531, "⅓"); html5References.addReference( 8532, "⅔"); html5References.addReference( 8533, "⅕"); html5References.addReference( 8534, "⅖"); html5References.addReference( 8535, "⅗"); html5References.addReference( 8536, "⅘"); html5References.addReference( 8537, "⅙"); html5References.addReference( 8538, "⅚"); html5References.addReference( 8539, "⅛"); html5References.addReference( 8540, "⅜"); html5References.addReference( 8541, "⅝"); html5References.addReference( 8542, "⅞"); html5References.addReference( 8592, "←"); html5References.addReference( 8592, "←"); html5References.addReference( 8592, "←"); html5References.addReference( 8592, "←"); html5References.addReference( 8592, "←"); html5References.addReference( 8593, "↑"); html5References.addReference( 8593, "↑"); html5References.addReference( 8593, "↑"); html5References.addReference( 8593, "↑"); html5References.addReference( 8594, "→"); html5References.addReference( 8594, "→"); html5References.addReference( 8594, "→"); html5References.addReference( 8594, "→"); html5References.addReference( 8594, "→"); html5References.addReference( 8595, "↓"); html5References.addReference( 8595, "↓"); html5References.addReference( 8595, "↓"); html5References.addReference( 8595, "↓"); html5References.addReference( 8596, "↔"); html5References.addReference( 8596, "↔"); html5References.addReference( 8596, "↔"); html5References.addReference( 8597, "↕"); html5References.addReference( 8597, "↕"); html5References.addReference( 8597, "↕"); html5References.addReference( 8598, "↖"); html5References.addReference( 8598, "↖"); html5References.addReference( 8598, "↖"); html5References.addReference( 8599, "↗"); html5References.addReference( 8599, "↗"); html5References.addReference( 8599, "↗"); html5References.addReference( 8600, "↘"); html5References.addReference( 8600, "↘"); html5References.addReference( 8600, "↘"); html5References.addReference( 8601, "↙"); html5References.addReference( 8601, "↙"); html5References.addReference( 8601, "↙"); html5References.addReference( 8602, "↚"); html5References.addReference( 8602, "↚"); html5References.addReference( 8603, "↛"); html5References.addReference( 8603, "↛"); html5References.addReference( 8605, "↝"); html5References.addReference( 8605, "↝"); html5References.addReference( 8605, 824, "↝̸"); html5References.addReference( 8606, "↞"); html5References.addReference( 8606, "↞"); html5References.addReference( 8607, "↟"); html5References.addReference( 8608, "↠"); html5References.addReference( 8608, "↠"); html5References.addReference( 8609, "↡"); html5References.addReference( 8610, "↢"); html5References.addReference( 8610, "↢"); html5References.addReference( 8611, "↣"); html5References.addReference( 8611, "↣"); html5References.addReference( 8612, "↤"); html5References.addReference( 8612, "↤"); html5References.addReference( 8613, "↥"); html5References.addReference( 8613, "↥"); html5References.addReference( 8614, "↦"); html5References.addReference( 8614, "↦"); html5References.addReference( 8614, "↦"); html5References.addReference( 8615, "↧"); html5References.addReference( 8615, "↧"); html5References.addReference( 8617, "↩"); html5References.addReference( 8617, "↩"); html5References.addReference( 8618, "↪"); html5References.addReference( 8618, "↪"); html5References.addReference( 8619, "↫"); html5References.addReference( 8619, "↫"); html5References.addReference( 8620, "↬"); html5References.addReference( 8620, "↬"); html5References.addReference( 8621, "↭"); html5References.addReference( 8621, "↭"); html5References.addReference( 8622, "↮"); html5References.addReference( 8622, "↮"); html5References.addReference( 8624, "↰"); html5References.addReference( 8624, "↰"); html5References.addReference( 8625, "↱"); html5References.addReference( 8625, "↱"); html5References.addReference( 8626, "↲"); html5References.addReference( 8627, "↳"); html5References.addReference( 8629, "↵"); html5References.addReference( 8630, "↶"); html5References.addReference( 8630, "↶"); html5References.addReference( 8631, "↷"); html5References.addReference( 8631, "↷"); html5References.addReference( 8634, "↺"); html5References.addReference( 8634, "↺"); html5References.addReference( 8635, "↻"); html5References.addReference( 8635, "↻"); html5References.addReference( 8636, "↼"); html5References.addReference( 8636, "↼"); html5References.addReference( 8636, "↼"); html5References.addReference( 8637, "↽"); html5References.addReference( 8637, "↽"); html5References.addReference( 8637, "↽"); html5References.addReference( 8638, "↾"); html5References.addReference( 8638, "↾"); html5References.addReference( 8638, "↾"); html5References.addReference( 8639, "↿"); html5References.addReference( 8639, "↿"); html5References.addReference( 8639, "↿"); html5References.addReference( 8640, "⇀"); html5References.addReference( 8640, "⇀"); html5References.addReference( 8640, "⇀"); html5References.addReference( 8641, "⇁"); html5References.addReference( 8641, "⇁"); html5References.addReference( 8641, "⇁"); html5References.addReference( 8642, "⇂"); html5References.addReference( 8642, "⇂"); html5References.addReference( 8642, "⇂"); html5References.addReference( 8643, "⇃"); html5References.addReference( 8643, "⇃"); html5References.addReference( 8643, "⇃"); html5References.addReference( 8644, "⇄"); html5References.addReference( 8644, "⇄"); html5References.addReference( 8644, "⇄"); html5References.addReference( 8645, "⇅"); html5References.addReference( 8645, "⇅"); html5References.addReference( 8646, "⇆"); html5References.addReference( 8646, "⇆"); html5References.addReference( 8646, "⇆"); html5References.addReference( 8647, "⇇"); html5References.addReference( 8647, "⇇"); html5References.addReference( 8648, "⇈"); html5References.addReference( 8648, "⇈"); html5References.addReference( 8649, "⇉"); html5References.addReference( 8649, "⇉"); html5References.addReference( 8650, "⇊"); html5References.addReference( 8650, "⇊"); html5References.addReference( 8651, "⇋"); html5References.addReference( 8651, "⇋"); html5References.addReference( 8651, "⇋"); html5References.addReference( 8652, "⇌"); html5References.addReference( 8652, "⇌"); html5References.addReference( 8652, "⇌"); html5References.addReference( 8653, "⇍"); html5References.addReference( 8653, "⇍"); html5References.addReference( 8654, "⇎"); html5References.addReference( 8654, "⇎"); html5References.addReference( 8655, "⇏"); html5References.addReference( 8655, "⇏"); html5References.addReference( 8656, "⇐"); html5References.addReference( 8656, "⇐"); html5References.addReference( 8656, "⇐"); html5References.addReference( 8657, "⇑"); html5References.addReference( 8657, "⇑"); html5References.addReference( 8657, "⇑"); html5References.addReference( 8658, "⇒"); html5References.addReference( 8658, "⇒"); html5References.addReference( 8658, "⇒"); html5References.addReference( 8658, "⇒"); html5References.addReference( 8659, "⇓"); html5References.addReference( 8659, "⇓"); html5References.addReference( 8659, "⇓"); html5References.addReference( 8660, "⇔"); html5References.addReference( 8660, "⇔"); html5References.addReference( 8660, "⇔"); html5References.addReference( 8660, "⇔"); html5References.addReference( 8661, "⇕"); html5References.addReference( 8661, "⇕"); html5References.addReference( 8661, "⇕"); html5References.addReference( 8662, "⇖"); html5References.addReference( 8663, "⇗"); html5References.addReference( 8664, "⇘"); html5References.addReference( 8665, "⇙"); html5References.addReference( 8666, "⇚"); html5References.addReference( 8666, "⇚"); html5References.addReference( 8667, "⇛"); html5References.addReference( 8667, "⇛"); html5References.addReference( 8669, "⇝"); html5References.addReference( 8676, "⇤"); html5References.addReference( 8676, "⇤"); html5References.addReference( 8677, "⇥"); html5References.addReference( 8677, "⇥"); html5References.addReference( 8693, "⇵"); html5References.addReference( 8693, "⇵"); html5References.addReference( 8701, "⇽"); html5References.addReference( 8702, "⇾"); html5References.addReference( 8703, "⇿"); html5References.addReference( 8704, "∀"); html5References.addReference( 8704, "∀"); html5References.addReference( 8705, "∁"); html5References.addReference( 8705, "∁"); html5References.addReference( 8706, "∂"); html5References.addReference( 8706, "∂"); html5References.addReference( 8706, 824, "∂̸"); html5References.addReference( 8707, "∃"); html5References.addReference( 8707, "∃"); html5References.addReference( 8708, "∄"); html5References.addReference( 8708, "∄"); html5References.addReference( 8708, "∄"); html5References.addReference( 8709, "∅"); html5References.addReference( 8709, "∅"); html5References.addReference( 8709, "∅"); html5References.addReference( 8709, "∅"); html5References.addReference( 8711, "∇"); html5References.addReference( 8711, "∇"); html5References.addReference( 8712, "∈"); html5References.addReference( 8712, "∈"); html5References.addReference( 8712, "∈"); html5References.addReference( 8712, "∈"); html5References.addReference( 8713, "∉"); html5References.addReference( 8713, "∉"); html5References.addReference( 8713, "∉"); html5References.addReference( 8715, "∋"); html5References.addReference( 8715, "∋"); html5References.addReference( 8715, "∋"); html5References.addReference( 8715, "∋"); html5References.addReference( 8716, "∌"); html5References.addReference( 8716, "∌"); html5References.addReference( 8716, "∌"); html5References.addReference( 8719, "∏"); html5References.addReference( 8719, "∏"); html5References.addReference( 8720, "∐"); html5References.addReference( 8720, "∐"); html5References.addReference( 8721, "∑"); html5References.addReference( 8721, "∑"); html5References.addReference( 8722, "−"); html5References.addReference( 8723, "∓"); html5References.addReference( 8723, "∓"); html5References.addReference( 8723, "∓"); html5References.addReference( 8724, "∔"); html5References.addReference( 8724, "∔"); html5References.addReference( 8726, "∖"); html5References.addReference( 8726, "∖"); html5References.addReference( 8726, "∖"); html5References.addReference( 8726, "∖"); html5References.addReference( 8726, "∖"); html5References.addReference( 8727, "∗"); html5References.addReference( 8728, "∘"); html5References.addReference( 8728, "∘"); html5References.addReference( 8730, "√"); html5References.addReference( 8730, "√"); html5References.addReference( 8733, "∝"); html5References.addReference( 8733, "∝"); html5References.addReference( 8733, "∝"); html5References.addReference( 8733, "∝"); html5References.addReference( 8733, "∝"); html5References.addReference( 8734, "∞"); html5References.addReference( 8735, "∟"); html5References.addReference( 8736, "∠"); html5References.addReference( 8736, "∠"); html5References.addReference( 8736, 8402, "∠⃒"); html5References.addReference( 8737, "∡"); html5References.addReference( 8737, "∡"); html5References.addReference( 8738, "∢"); html5References.addReference( 8739, "∣"); html5References.addReference( 8739, "∣"); html5References.addReference( 8739, "∣"); html5References.addReference( 8739, "∣"); html5References.addReference( 8740, "∤"); html5References.addReference( 8740, "∤"); html5References.addReference( 8740, "∤"); html5References.addReference( 8740, "∤"); html5References.addReference( 8741, "∥"); html5References.addReference( 8741, "∥"); html5References.addReference( 8741, "∥"); html5References.addReference( 8741, "∥"); html5References.addReference( 8741, "∥"); html5References.addReference( 8742, "∦"); html5References.addReference( 8742, "∦"); html5References.addReference( 8742, "∦"); html5References.addReference( 8742, "∦"); html5References.addReference( 8742, "∦"); html5References.addReference( 8743, "∧"); html5References.addReference( 8743, "∧"); html5References.addReference( 8744, "∨"); html5References.addReference( 8744, "∨"); html5References.addReference( 8745, "∩"); html5References.addReference( 8745, 65024, "∩︀"); html5References.addReference( 8746, "∪"); html5References.addReference( 8746, 65024, "∪︀"); html5References.addReference( 8747, "∫"); html5References.addReference( 8747, "∫"); html5References.addReference( 8748, "∬"); html5References.addReference( 8749, "∭"); html5References.addReference( 8749, "∭"); html5References.addReference( 8750, "∮"); html5References.addReference( 8750, "∮"); html5References.addReference( 8750, "∮"); html5References.addReference( 8751, "∯"); html5References.addReference( 8751, "∯"); html5References.addReference( 8752, "∰"); html5References.addReference( 8753, "∱"); html5References.addReference( 8754, "∲"); html5References.addReference( 8754, "∲"); html5References.addReference( 8755, "∳"); html5References.addReference( 8755, "∳"); html5References.addReference( 8756, "∴"); html5References.addReference( 8756, "∴"); html5References.addReference( 8756, "∴"); html5References.addReference( 8757, "∵"); html5References.addReference( 8757, "∵"); html5References.addReference( 8757, "∵"); html5References.addReference( 8758, "∶"); html5References.addReference( 8759, "∷"); html5References.addReference( 8759, "∷"); html5References.addReference( 8760, "∸"); html5References.addReference( 8760, "∸"); html5References.addReference( 8762, "∺"); html5References.addReference( 8763, "∻"); html5References.addReference( 8764, "∼"); html5References.addReference( 8764, "∼"); html5References.addReference( 8764, "∼"); html5References.addReference( 8764, "∼"); html5References.addReference( 8764, 8402, "∼⃒"); html5References.addReference( 8765, "∽"); html5References.addReference( 8765, "∽"); html5References.addReference( 8765, 817, "∽̱"); html5References.addReference( 8766, "∾"); html5References.addReference( 8766, "∾"); html5References.addReference( 8766, 819, "∾̳"); html5References.addReference( 8767, "∿"); html5References.addReference( 8768, "≀"); html5References.addReference( 8768, "≀"); html5References.addReference( 8768, "≀"); html5References.addReference( 8769, "≁"); html5References.addReference( 8769, "≁"); html5References.addReference( 8770, "≂"); html5References.addReference( 8770, "≂"); html5References.addReference( 8770, "≂"); html5References.addReference( 8770, 824, "≂̸"); html5References.addReference( 8770, 824, "≂̸"); html5References.addReference( 8771, "≃"); html5References.addReference( 8771, "≃"); html5References.addReference( 8771, "≃"); html5References.addReference( 8772, "≄"); html5References.addReference( 8772, "≄"); html5References.addReference( 8772, "≄"); html5References.addReference( 8773, "≅"); html5References.addReference( 8773, "≅"); html5References.addReference( 8774, "≆"); html5References.addReference( 8775, "≇"); html5References.addReference( 8775, "≇"); html5References.addReference( 8776, "≈"); html5References.addReference( 8776, "≈"); html5References.addReference( 8776, "≈"); html5References.addReference( 8776, "≈"); html5References.addReference( 8776, "≈"); html5References.addReference( 8776, "≈"); html5References.addReference( 8777, "≉"); html5References.addReference( 8777, "≉"); html5References.addReference( 8777, "≉"); html5References.addReference( 8778, "≊"); html5References.addReference( 8778, "≊"); html5References.addReference( 8779, "≋"); html5References.addReference( 8779, 824, "≋̸"); html5References.addReference( 8780, "≌"); html5References.addReference( 8780, "≌"); html5References.addReference( 8781, "≍"); html5References.addReference( 8781, "≍"); html5References.addReference( 8781, 8402, "≍⃒"); html5References.addReference( 8782, "≎"); html5References.addReference( 8782, "≎"); html5References.addReference( 8782, "≎"); html5References.addReference( 8782, 824, "≎̸"); html5References.addReference( 8782, 824, "≎̸"); html5References.addReference( 8783, "≏"); html5References.addReference( 8783, "≏"); html5References.addReference( 8783, "≏"); html5References.addReference( 8783, 824, "≏̸"); html5References.addReference( 8783, 824, "≏̸"); html5References.addReference( 8784, "≐"); html5References.addReference( 8784, "≐"); html5References.addReference( 8784, "≐"); html5References.addReference( 8784, 824, "≐̸"); html5References.addReference( 8785, "≑"); html5References.addReference( 8785, "≑"); html5References.addReference( 8786, "≒"); html5References.addReference( 8786, "≒"); html5References.addReference( 8787, "≓"); html5References.addReference( 8787, "≓"); html5References.addReference( 8788, "≔"); html5References.addReference( 8788, "≔"); html5References.addReference( 8788, "≔"); html5References.addReference( 8789, "≕"); html5References.addReference( 8789, "≕"); html5References.addReference( 8790, "≖"); html5References.addReference( 8790, "≖"); html5References.addReference( 8791, "≗"); html5References.addReference( 8791, "≗"); html5References.addReference( 8793, "≙"); html5References.addReference( 8794, "≚"); html5References.addReference( 8796, "≜"); html5References.addReference( 8796, "≜"); html5References.addReference( 8799, "≟"); html5References.addReference( 8799, "≟"); html5References.addReference( 8800, "≠"); html5References.addReference( 8800, "≠"); html5References.addReference( 8801, "≡"); html5References.addReference( 8801, "≡"); html5References.addReference( 8801, 8421, "≡⃥"); html5References.addReference( 8802, "≢"); html5References.addReference( 8802, "≢"); html5References.addReference( 8804, "≤"); html5References.addReference( 8804, "≤"); html5References.addReference( 8804, 8402, "≤⃒"); html5References.addReference( 8805, "≥"); html5References.addReference( 8805, "≥"); html5References.addReference( 8805, "≥"); html5References.addReference( 8805, 8402, "≥⃒"); html5References.addReference( 8806, "≦"); html5References.addReference( 8806, "≦"); html5References.addReference( 8806, "≦"); html5References.addReference( 8806, 824, "≦̸"); html5References.addReference( 8806, 824, "≦̸"); html5References.addReference( 8807, "≧"); html5References.addReference( 8807, "≧"); html5References.addReference( 8807, "≧"); html5References.addReference( 8807, 824, "≧̸"); html5References.addReference( 8807, 824, "≧̸"); html5References.addReference( 8807, 824, "≧̸"); html5References.addReference( 8808, "≨"); html5References.addReference( 8808, "≨"); html5References.addReference( 8808, 65024, "≨︀"); html5References.addReference( 8808, 65024, "≨︀"); html5References.addReference( 8809, "≩"); html5References.addReference( 8809, "≩"); html5References.addReference( 8809, 65024, "≩︀"); html5References.addReference( 8809, 65024, "≩︀"); html5References.addReference( 8810, "≪"); html5References.addReference( 8810, "≪"); html5References.addReference( 8810, "≪"); html5References.addReference( 8810, 824, "≪̸"); html5References.addReference( 8810, 824, "≪̸"); html5References.addReference( 8810, 8402, "≪⃒"); html5References.addReference( 8811, "≫"); html5References.addReference( 8811, "≫"); html5References.addReference( 8811, "≫"); html5References.addReference( 8811, 824, "≫̸"); html5References.addReference( 8811, 824, "≫̸"); html5References.addReference( 8811, 8402, "≫⃒"); html5References.addReference( 8812, "≬"); html5References.addReference( 8812, "≬"); html5References.addReference( 8813, "≭"); html5References.addReference( 8814, "≮"); html5References.addReference( 8814, "≮"); html5References.addReference( 8814, "≮"); html5References.addReference( 8815, "≯"); html5References.addReference( 8815, "≯"); html5References.addReference( 8815, "≯"); html5References.addReference( 8816, "≰"); html5References.addReference( 8816, "≰"); html5References.addReference( 8816, "≰"); html5References.addReference( 8817, "≱"); html5References.addReference( 8817, "≱"); html5References.addReference( 8817, "≱"); html5References.addReference( 8818, "≲"); html5References.addReference( 8818, "≲"); html5References.addReference( 8818, "≲"); html5References.addReference( 8819, "≳"); html5References.addReference( 8819, "≳"); html5References.addReference( 8819, "≳"); html5References.addReference( 8820, "≴"); html5References.addReference( 8820, "≴"); html5References.addReference( 8821, "≵"); html5References.addReference( 8821, "≵"); html5References.addReference( 8822, "≶"); html5References.addReference( 8822, "≶"); html5References.addReference( 8822, "≶"); html5References.addReference( 8823, "≷"); html5References.addReference( 8823, "≷"); html5References.addReference( 8823, "≷"); html5References.addReference( 8824, "≸"); html5References.addReference( 8824, "≸"); html5References.addReference( 8825, "≹"); html5References.addReference( 8825, "≹"); html5References.addReference( 8826, "≺"); html5References.addReference( 8826, "≺"); html5References.addReference( 8826, "≺"); html5References.addReference( 8827, "≻"); html5References.addReference( 8827, "≻"); html5References.addReference( 8827, "≻"); html5References.addReference( 8828, "≼"); html5References.addReference( 8828, "≼"); html5References.addReference( 8828, "≼"); html5References.addReference( 8829, "≽"); html5References.addReference( 8829, "≽"); html5References.addReference( 8829, "≽"); html5References.addReference( 8830, "≾"); html5References.addReference( 8830, "≾"); html5References.addReference( 8830, "≾"); html5References.addReference( 8831, "≿"); html5References.addReference( 8831, "≿"); html5References.addReference( 8831, "≿"); html5References.addReference( 8831, 824, "≿̸"); html5References.addReference( 8832, "⊀"); html5References.addReference( 8832, "⊀"); html5References.addReference( 8832, "⊀"); html5References.addReference( 8833, "⊁"); html5References.addReference( 8833, "⊁"); html5References.addReference( 8833, "⊁"); html5References.addReference( 8834, "⊂"); html5References.addReference( 8834, "⊂"); html5References.addReference( 8834, 8402, "⊂⃒"); html5References.addReference( 8834, 8402, "⊂⃒"); html5References.addReference( 8834, 8402, "⊂⃒"); html5References.addReference( 8835, "⊃"); html5References.addReference( 8835, "⊃"); html5References.addReference( 8835, "⊃"); html5References.addReference( 8835, 8402, "⊃⃒"); html5References.addReference( 8835, 8402, "⊃⃒"); html5References.addReference( 8835, 8402, "⊃⃒"); html5References.addReference( 8836, "⊄"); html5References.addReference( 8837, "⊅"); html5References.addReference( 8838, "⊆"); html5References.addReference( 8838, "⊆"); html5References.addReference( 8838, "⊆"); html5References.addReference( 8839, "⊇"); html5References.addReference( 8839, "⊇"); html5References.addReference( 8839, "⊇"); html5References.addReference( 8840, "⊈"); html5References.addReference( 8840, "⊈"); html5References.addReference( 8840, "⊈"); html5References.addReference( 8841, "⊉"); html5References.addReference( 8841, "⊉"); html5References.addReference( 8841, "⊉"); html5References.addReference( 8842, "⊊"); html5References.addReference( 8842, "⊊"); html5References.addReference( 8842, 65024, "⊊︀"); html5References.addReference( 8842, 65024, "⊊︀"); html5References.addReference( 8843, "⊋"); html5References.addReference( 8843, "⊋"); html5References.addReference( 8843, 65024, "⊋︀"); html5References.addReference( 8843, 65024, "⊋︀"); html5References.addReference( 8845, "⊍"); html5References.addReference( 8846, "⊎"); html5References.addReference( 8846, "⊎"); html5References.addReference( 8847, "⊏"); html5References.addReference( 8847, "⊏"); html5References.addReference( 8847, "⊏"); html5References.addReference( 8847, 824, "⊏̸"); html5References.addReference( 8848, "⊐"); html5References.addReference( 8848, "⊐"); html5References.addReference( 8848, "⊐"); html5References.addReference( 8848, 824, "⊐̸"); html5References.addReference( 8849, "⊑"); html5References.addReference( 8849, "⊑"); html5References.addReference( 8849, "⊑"); html5References.addReference( 8850, "⊒"); html5References.addReference( 8850, "⊒"); html5References.addReference( 8850, "⊒"); html5References.addReference( 8851, "⊓"); html5References.addReference( 8851, "⊓"); html5References.addReference( 8851, 65024, "⊓︀"); html5References.addReference( 8852, "⊔"); html5References.addReference( 8852, "⊔"); html5References.addReference( 8852, 65024, "⊔︀"); html5References.addReference( 8853, "⊕"); html5References.addReference( 8853, "⊕"); html5References.addReference( 8854, "⊖"); html5References.addReference( 8854, "⊖"); html5References.addReference( 8855, "⊗"); html5References.addReference( 8855, "⊗"); html5References.addReference( 8856, "⊘"); html5References.addReference( 8857, "⊙"); html5References.addReference( 8857, "⊙"); html5References.addReference( 8858, "⊚"); html5References.addReference( 8858, "⊚"); html5References.addReference( 8859, "⊛"); html5References.addReference( 8859, "⊛"); html5References.addReference( 8861, "⊝"); html5References.addReference( 8861, "⊝"); html5References.addReference( 8862, "⊞"); html5References.addReference( 8862, "⊞"); html5References.addReference( 8863, "⊟"); html5References.addReference( 8863, "⊟"); html5References.addReference( 8864, "⊠"); html5References.addReference( 8864, "⊠"); html5References.addReference( 8865, "⊡"); html5References.addReference( 8865, "⊡"); html5References.addReference( 8866, "⊢"); html5References.addReference( 8866, "⊢"); html5References.addReference( 8867, "⊣"); html5References.addReference( 8867, "⊣"); html5References.addReference( 8868, "⊤"); html5References.addReference( 8868, "⊤"); html5References.addReference( 8869, "⊥"); html5References.addReference( 8869, "⊥"); html5References.addReference( 8869, "⊥"); html5References.addReference( 8869, "⊥"); html5References.addReference( 8871, "⊧"); html5References.addReference( 8872, "⊨"); html5References.addReference( 8872, "⊨"); html5References.addReference( 8873, "⊩"); html5References.addReference( 8874, "⊪"); html5References.addReference( 8875, "⊫"); html5References.addReference( 8876, "⊬"); html5References.addReference( 8877, "⊭"); html5References.addReference( 8878, "⊮"); html5References.addReference( 8879, "⊯"); html5References.addReference( 8880, "⊰"); html5References.addReference( 8882, "⊲"); html5References.addReference( 8882, "⊲"); html5References.addReference( 8882, "⊲"); html5References.addReference( 8883, "⊳"); html5References.addReference( 8883, "⊳"); html5References.addReference( 8883, "⊳"); html5References.addReference( 8884, "⊴"); html5References.addReference( 8884, "⊴"); html5References.addReference( 8884, "⊴"); html5References.addReference( 8884, 8402, "⊴⃒"); html5References.addReference( 8885, "⊵"); html5References.addReference( 8885, "⊵"); html5References.addReference( 8885, "⊵"); html5References.addReference( 8885, 8402, "⊵⃒"); html5References.addReference( 8886, "⊶"); html5References.addReference( 8887, "⊷"); html5References.addReference( 8888, "⊸"); html5References.addReference( 8888, "⊸"); html5References.addReference( 8889, "⊹"); html5References.addReference( 8890, "⊺"); html5References.addReference( 8890, "⊺"); html5References.addReference( 8891, "⊻"); html5References.addReference( 8893, "⊽"); html5References.addReference( 8894, "⊾"); html5References.addReference( 8895, "⊿"); html5References.addReference( 8896, "⋀"); html5References.addReference( 8896, "⋀"); html5References.addReference( 8896, "⋀"); html5References.addReference( 8897, "⋁"); html5References.addReference( 8897, "⋁"); html5References.addReference( 8897, "⋁"); html5References.addReference( 8898, "⋂"); html5References.addReference( 8898, "⋂"); html5References.addReference( 8898, "⋂"); html5References.addReference( 8899, "⋃"); html5References.addReference( 8899, "⋃"); html5References.addReference( 8899, "⋃"); html5References.addReference( 8900, "⋄"); html5References.addReference( 8900, "⋄"); html5References.addReference( 8900, "⋄"); html5References.addReference( 8901, "⋅"); html5References.addReference( 8902, "⋆"); html5References.addReference( 8902, "⋆"); html5References.addReference( 8903, "⋇"); html5References.addReference( 8903, "⋇"); html5References.addReference( 8904, "⋈"); html5References.addReference( 8905, "⋉"); html5References.addReference( 8906, "⋊"); html5References.addReference( 8907, "⋋"); html5References.addReference( 8907, "⋋"); html5References.addReference( 8908, "⋌"); html5References.addReference( 8908, "⋌"); html5References.addReference( 8909, "⋍"); html5References.addReference( 8909, "⋍"); html5References.addReference( 8910, "⋎"); html5References.addReference( 8910, "⋎"); html5References.addReference( 8911, "⋏"); html5References.addReference( 8911, "⋏"); html5References.addReference( 8912, "⋐"); html5References.addReference( 8912, "⋐"); html5References.addReference( 8913, "⋑"); html5References.addReference( 8913, "⋑"); html5References.addReference( 8914, "⋒"); html5References.addReference( 8915, "⋓"); html5References.addReference( 8916, "⋔"); html5References.addReference( 8916, "⋔"); html5References.addReference( 8917, "⋕"); html5References.addReference( 8918, "⋖"); html5References.addReference( 8918, "⋖"); html5References.addReference( 8919, "⋗"); html5References.addReference( 8919, "⋗"); html5References.addReference( 8920, "⋘"); html5References.addReference( 8920, 824, "⋘̸"); html5References.addReference( 8921, "⋙"); html5References.addReference( 8921, "⋙"); html5References.addReference( 8921, 824, "⋙̸"); html5References.addReference( 8922, "⋚"); html5References.addReference( 8922, "⋚"); html5References.addReference( 8922, "⋚"); html5References.addReference( 8922, 65024, "⋚︀"); html5References.addReference( 8923, "⋛"); html5References.addReference( 8923, "⋛"); html5References.addReference( 8923, "⋛"); html5References.addReference( 8923, 65024, "⋛︀"); html5References.addReference( 8926, "⋞"); html5References.addReference( 8926, "⋞"); html5References.addReference( 8927, "⋟"); html5References.addReference( 8927, "⋟"); html5References.addReference( 8928, "⋠"); html5References.addReference( 8928, "⋠"); html5References.addReference( 8929, "⋡"); html5References.addReference( 8929, "⋡"); html5References.addReference( 8930, "⋢"); html5References.addReference( 8930, "⋢"); html5References.addReference( 8931, "⋣"); html5References.addReference( 8931, "⋣"); html5References.addReference( 8934, "⋦"); html5References.addReference( 8935, "⋧"); html5References.addReference( 8936, "⋨"); html5References.addReference( 8936, "⋨"); html5References.addReference( 8937, "⋩"); html5References.addReference( 8937, "⋩"); html5References.addReference( 8938, "⋪"); html5References.addReference( 8938, "⋪"); html5References.addReference( 8938, "⋪"); html5References.addReference( 8939, "⋫"); html5References.addReference( 8939, "⋫"); html5References.addReference( 8939, "⋫"); html5References.addReference( 8940, "⋬"); html5References.addReference( 8940, "⋬"); html5References.addReference( 8940, "⋬"); html5References.addReference( 8941, "⋭"); html5References.addReference( 8941, "⋭"); html5References.addReference( 8941, "⋭"); html5References.addReference( 8942, "⋮"); html5References.addReference( 8943, "⋯"); html5References.addReference( 8944, "⋰"); html5References.addReference( 8945, "⋱"); html5References.addReference( 8946, "⋲"); html5References.addReference( 8947, "⋳"); html5References.addReference( 8948, "⋴"); html5References.addReference( 8949, "⋵"); html5References.addReference( 8949, 824, "⋵̸"); html5References.addReference( 8950, "⋶"); html5References.addReference( 8951, "⋷"); html5References.addReference( 8953, "⋹"); html5References.addReference( 8953, 824, "⋹̸"); html5References.addReference( 8954, "⋺"); html5References.addReference( 8955, "⋻"); html5References.addReference( 8956, "⋼"); html5References.addReference( 8957, "⋽"); html5References.addReference( 8958, "⋾"); html5References.addReference( 8965, "⌅"); html5References.addReference( 8965, "⌅"); html5References.addReference( 8966, "⌆"); html5References.addReference( 8966, "⌆"); html5References.addReference( 8968, "⌈"); html5References.addReference( 8968, "⌈"); html5References.addReference( 8969, "⌉"); html5References.addReference( 8969, "⌉"); html5References.addReference( 8970, "⌊"); html5References.addReference( 8970, "⌊"); html5References.addReference( 8971, "⌋"); html5References.addReference( 8971, "⌋"); html5References.addReference( 8972, "⌌"); html5References.addReference( 8973, "⌍"); html5References.addReference( 8974, "⌎"); html5References.addReference( 8975, "⌏"); html5References.addReference( 8976, "⌐"); html5References.addReference( 8978, "⌒"); html5References.addReference( 8979, "⌓"); html5References.addReference( 8981, "⌕"); html5References.addReference( 8982, "⌖"); html5References.addReference( 8988, "⌜"); html5References.addReference( 8988, "⌜"); html5References.addReference( 8989, "⌝"); html5References.addReference( 8989, "⌝"); html5References.addReference( 8990, "⌞"); html5References.addReference( 8990, "⌞"); html5References.addReference( 8991, "⌟"); html5References.addReference( 8991, "⌟"); html5References.addReference( 8994, "⌢"); html5References.addReference( 8994, "⌢"); html5References.addReference( 8995, "⌣"); html5References.addReference( 8995, "⌣"); html5References.addReference( 9005, "⌭"); html5References.addReference( 9006, "⌮"); html5References.addReference( 9014, "⌶"); html5References.addReference( 9021, "⌽"); html5References.addReference( 9023, "⌿"); html5References.addReference( 9084, "⍼"); html5References.addReference( 9136, "⎰"); html5References.addReference( 9136, "⎰"); html5References.addReference( 9137, "⎱"); html5References.addReference( 9137, "⎱"); html5References.addReference( 9140, "⎴"); html5References.addReference( 9140, "⎴"); html5References.addReference( 9141, "⎵"); html5References.addReference( 9141, "⎵"); html5References.addReference( 9142, "⎶"); html5References.addReference( 9180, "⏜"); html5References.addReference( 9181, "⏝"); html5References.addReference( 9182, "⏞"); html5References.addReference( 9183, "⏟"); html5References.addReference( 9186, "⏢"); html5References.addReference( 9191, "⏧"); html5References.addReference( 9251, "␣"); html5References.addReference( 9416, "Ⓢ"); html5References.addReference( 9416, "Ⓢ"); html5References.addReference( 9472, "─"); html5References.addReference( 9472, "─"); html5References.addReference( 9474, "│"); html5References.addReference( 9484, "┌"); html5References.addReference( 9488, "┐"); html5References.addReference( 9492, "└"); html5References.addReference( 9496, "┘"); html5References.addReference( 9500, "├"); html5References.addReference( 9508, "┤"); html5References.addReference( 9516, "┬"); html5References.addReference( 9524, "┴"); html5References.addReference( 9532, "┼"); html5References.addReference( 9552, "═"); html5References.addReference( 9553, "║"); html5References.addReference( 9554, "╒"); html5References.addReference( 9555, "╓"); html5References.addReference( 9556, "╔"); html5References.addReference( 9557, "╕"); html5References.addReference( 9558, "╖"); html5References.addReference( 9559, "╗"); html5References.addReference( 9560, "╘"); html5References.addReference( 9561, "╙"); html5References.addReference( 9562, "╚"); html5References.addReference( 9563, "╛"); html5References.addReference( 9564, "╜"); html5References.addReference( 9565, "╝"); html5References.addReference( 9566, "╞"); html5References.addReference( 9567, "╟"); html5References.addReference( 9568, "╠"); html5References.addReference( 9569, "╡"); html5References.addReference( 9570, "╢"); html5References.addReference( 9571, "╣"); html5References.addReference( 9572, "╤"); html5References.addReference( 9573, "╥"); html5References.addReference( 9574, "╦"); html5References.addReference( 9575, "╧"); html5References.addReference( 9576, "╨"); html5References.addReference( 9577, "╩"); html5References.addReference( 9578, "╪"); html5References.addReference( 9579, "╫"); html5References.addReference( 9580, "╬"); html5References.addReference( 9600, "▀"); html5References.addReference( 9604, "▄"); html5References.addReference( 9608, "█"); html5References.addReference( 9617, "░"); html5References.addReference( 9618, "▒"); html5References.addReference( 9619, "▓"); html5References.addReference( 9633, "□"); html5References.addReference( 9633, "□"); html5References.addReference( 9633, "□"); html5References.addReference( 9642, "▪"); html5References.addReference( 9642, "▪"); html5References.addReference( 9642, "▪"); html5References.addReference( 9642, "▪"); html5References.addReference( 9643, "▫"); html5References.addReference( 9645, "▭"); html5References.addReference( 9646, "▮"); html5References.addReference( 9649, "▱"); html5References.addReference( 9651, "△"); html5References.addReference( 9651, "△"); html5References.addReference( 9652, "▴"); html5References.addReference( 9652, "▴"); html5References.addReference( 9653, "▵"); html5References.addReference( 9653, "▵"); html5References.addReference( 9656, "▸"); html5References.addReference( 9656, "▸"); html5References.addReference( 9657, "▹"); html5References.addReference( 9657, "▹"); html5References.addReference( 9661, "▽"); html5References.addReference( 9661, "▽"); html5References.addReference( 9662, "▾"); html5References.addReference( 9662, "▾"); html5References.addReference( 9663, "▿"); html5References.addReference( 9663, "▿"); html5References.addReference( 9666, "◂"); html5References.addReference( 9666, "◂"); html5References.addReference( 9667, "◃"); html5References.addReference( 9667, "◃"); html5References.addReference( 9674, "◊"); html5References.addReference( 9674, "◊"); html5References.addReference( 9675, "○"); html5References.addReference( 9708, "◬"); html5References.addReference( 9711, "◯"); html5References.addReference( 9711, "◯"); html5References.addReference( 9720, "◸"); html5References.addReference( 9721, "◹"); html5References.addReference( 9722, "◺"); html5References.addReference( 9723, "◻"); html5References.addReference( 9724, "◼"); html5References.addReference( 9733, "★"); html5References.addReference( 9733, "★"); html5References.addReference( 9734, "☆"); html5References.addReference( 9742, "☎"); html5References.addReference( 9792, "♀"); html5References.addReference( 9794, "♂"); html5References.addReference( 9824, "♠"); html5References.addReference( 9824, "♠"); html5References.addReference( 9827, "♣"); html5References.addReference( 9827, "♣"); html5References.addReference( 9829, "♥"); html5References.addReference( 9829, "♥"); html5References.addReference( 9830, "♦"); html5References.addReference( 9830, "♦"); html5References.addReference( 9834, "♪"); html5References.addReference( 9837, "♭"); html5References.addReference( 9838, "♮"); html5References.addReference( 9838, "♮"); html5References.addReference( 9839, "♯"); html5References.addReference( 10003, "✓"); html5References.addReference( 10003, "✓"); html5References.addReference( 10007, "✗"); html5References.addReference( 10016, "✠"); html5References.addReference( 10016, "✠"); html5References.addReference( 10038, "✶"); html5References.addReference( 10072, "❘"); html5References.addReference( 10098, "❲"); html5References.addReference( 10099, "❳"); html5References.addReference( 10184, "⟈"); html5References.addReference( 10185, "⟉"); html5References.addReference( 10214, "⟦"); html5References.addReference( 10214, "⟦"); html5References.addReference( 10215, "⟧"); html5References.addReference( 10215, "⟧"); html5References.addReference( 10216, "⟨"); html5References.addReference( 10216, "⟨"); html5References.addReference( 10216, "⟨"); html5References.addReference( 10217, "⟩"); html5References.addReference( 10217, "⟩"); html5References.addReference( 10217, "⟩"); html5References.addReference( 10218, "⟪"); html5References.addReference( 10219, "⟫"); html5References.addReference( 10220, "⟬"); html5References.addReference( 10221, "⟭"); html5References.addReference( 10229, "⟵"); html5References.addReference( 10229, "⟵"); html5References.addReference( 10229, "⟵"); html5References.addReference( 10230, "⟶"); html5References.addReference( 10230, "⟶"); html5References.addReference( 10230, "⟶"); html5References.addReference( 10231, "⟷"); html5References.addReference( 10231, "⟷"); html5References.addReference( 10231, "⟷"); html5References.addReference( 10232, "⟸"); html5References.addReference( 10232, "⟸"); html5References.addReference( 10232, "⟸"); html5References.addReference( 10233, "⟹"); html5References.addReference( 10233, "⟹"); html5References.addReference( 10233, "⟹"); html5References.addReference( 10234, "⟺"); html5References.addReference( 10234, "⟺"); html5References.addReference( 10234, "⟺"); html5References.addReference( 10236, "⟼"); html5References.addReference( 10236, "⟼"); html5References.addReference( 10239, "⟿"); html5References.addReference( 10498, "⤂"); html5References.addReference( 10499, "⤃"); html5References.addReference( 10500, "⤄"); html5References.addReference( 10501, "⤅"); html5References.addReference( 10508, "⤌"); html5References.addReference( 10509, "⤍"); html5References.addReference( 10509, "⤍"); html5References.addReference( 10510, "⤎"); html5References.addReference( 10511, "⤏"); html5References.addReference( 10511, "⤏"); html5References.addReference( 10512, "⤐"); html5References.addReference( 10512, "⤐"); html5References.addReference( 10513, "⤑"); html5References.addReference( 10514, "⤒"); html5References.addReference( 10515, "⤓"); html5References.addReference( 10518, "⤖"); html5References.addReference( 10521, "⤙"); html5References.addReference( 10522, "⤚"); html5References.addReference( 10523, "⤛"); html5References.addReference( 10524, "⤜"); html5References.addReference( 10525, "⤝"); html5References.addReference( 10526, "⤞"); html5References.addReference( 10527, "⤟"); html5References.addReference( 10528, "⤠"); html5References.addReference( 10531, "⤣"); html5References.addReference( 10532, "⤤"); html5References.addReference( 10533, "⤥"); html5References.addReference( 10533, "⤥"); html5References.addReference( 10534, "⤦"); html5References.addReference( 10534, "⤦"); html5References.addReference( 10535, "⤧"); html5References.addReference( 10536, "⤨"); html5References.addReference( 10536, "⤨"); html5References.addReference( 10537, "⤩"); html5References.addReference( 10537, "⤩"); html5References.addReference( 10538, "⤪"); html5References.addReference( 10547, "⤳"); html5References.addReference( 10547, 824, "⤳̸"); html5References.addReference( 10549, "⤵"); html5References.addReference( 10550, "⤶"); html5References.addReference( 10551, "⤷"); html5References.addReference( 10552, "⤸"); html5References.addReference( 10553, "⤹"); html5References.addReference( 10556, "⤼"); html5References.addReference( 10557, "⤽"); html5References.addReference( 10565, "⥅"); html5References.addReference( 10568, "⥈"); html5References.addReference( 10569, "⥉"); html5References.addReference( 10570, "⥊"); html5References.addReference( 10571, "⥋"); html5References.addReference( 10574, "⥎"); html5References.addReference( 10575, "⥏"); html5References.addReference( 10576, "⥐"); html5References.addReference( 10577, "⥑"); html5References.addReference( 10578, "⥒"); html5References.addReference( 10579, "⥓"); html5References.addReference( 10580, "⥔"); html5References.addReference( 10581, "⥕"); html5References.addReference( 10582, "⥖"); html5References.addReference( 10583, "⥗"); html5References.addReference( 10584, "⥘"); html5References.addReference( 10585, "⥙"); html5References.addReference( 10586, "⥚"); html5References.addReference( 10587, "⥛"); html5References.addReference( 10588, "⥜"); html5References.addReference( 10589, "⥝"); html5References.addReference( 10590, "⥞"); html5References.addReference( 10591, "⥟"); html5References.addReference( 10592, "⥠"); html5References.addReference( 10593, "⥡"); html5References.addReference( 10594, "⥢"); html5References.addReference( 10595, "⥣"); html5References.addReference( 10596, "⥤"); html5References.addReference( 10597, "⥥"); html5References.addReference( 10598, "⥦"); html5References.addReference( 10599, "⥧"); html5References.addReference( 10600, "⥨"); html5References.addReference( 10601, "⥩"); html5References.addReference( 10602, "⥪"); html5References.addReference( 10603, "⥫"); html5References.addReference( 10604, "⥬"); html5References.addReference( 10605, "⥭"); html5References.addReference( 10606, "⥮"); html5References.addReference( 10606, "⥮"); html5References.addReference( 10607, "⥯"); html5References.addReference( 10607, "⥯"); html5References.addReference( 10608, "⥰"); html5References.addReference( 10609, "⥱"); html5References.addReference( 10610, "⥲"); html5References.addReference( 10611, "⥳"); html5References.addReference( 10612, "⥴"); html5References.addReference( 10613, "⥵"); html5References.addReference( 10614, "⥶"); html5References.addReference( 10616, "⥸"); html5References.addReference( 10617, "⥹"); html5References.addReference( 10619, "⥻"); html5References.addReference( 10620, "⥼"); html5References.addReference( 10621, "⥽"); html5References.addReference( 10622, "⥾"); html5References.addReference( 10623, "⥿"); html5References.addReference( 10629, "⦅"); html5References.addReference( 10630, "⦆"); html5References.addReference( 10635, "⦋"); html5References.addReference( 10636, "⦌"); html5References.addReference( 10637, "⦍"); html5References.addReference( 10638, "⦎"); html5References.addReference( 10639, "⦏"); html5References.addReference( 10640, "⦐"); html5References.addReference( 10641, "⦑"); html5References.addReference( 10642, "⦒"); html5References.addReference( 10643, "⦓"); html5References.addReference( 10644, "⦔"); html5References.addReference( 10645, "⦕"); html5References.addReference( 10646, "⦖"); html5References.addReference( 10650, "⦚"); html5References.addReference( 10652, "⦜"); html5References.addReference( 10653, "⦝"); html5References.addReference( 10660, "⦤"); html5References.addReference( 10661, "⦥"); html5References.addReference( 10662, "⦦"); html5References.addReference( 10663, "⦧"); html5References.addReference( 10664, "⦨"); html5References.addReference( 10665, "⦩"); html5References.addReference( 10666, "⦪"); html5References.addReference( 10667, "⦫"); html5References.addReference( 10668, "⦬"); html5References.addReference( 10669, "⦭"); html5References.addReference( 10670, "⦮"); html5References.addReference( 10671, "⦯"); html5References.addReference( 10672, "⦰"); html5References.addReference( 10673, "⦱"); html5References.addReference( 10674, "⦲"); html5References.addReference( 10675, "⦳"); html5References.addReference( 10676, "⦴"); html5References.addReference( 10677, "⦵"); html5References.addReference( 10678, "⦶"); html5References.addReference( 10679, "⦷"); html5References.addReference( 10681, "⦹"); html5References.addReference( 10683, "⦻"); html5References.addReference( 10684, "⦼"); html5References.addReference( 10686, "⦾"); html5References.addReference( 10687, "⦿"); html5References.addReference( 10688, "⧀"); html5References.addReference( 10689, "⧁"); html5References.addReference( 10690, "⧂"); html5References.addReference( 10691, "⧃"); html5References.addReference( 10692, "⧄"); html5References.addReference( 10693, "⧅"); html5References.addReference( 10697, "⧉"); html5References.addReference( 10701, "⧍"); html5References.addReference( 10702, "⧎"); html5References.addReference( 10703, "⧏"); html5References.addReference( 10703, 824, "⧏̸"); html5References.addReference( 10704, "⧐"); html5References.addReference( 10704, 824, "⧐̸"); html5References.addReference( 10716, "⧜"); html5References.addReference( 10717, "⧝"); html5References.addReference( 10718, "⧞"); html5References.addReference( 10723, "⧣"); html5References.addReference( 10724, "⧤"); html5References.addReference( 10725, "⧥"); html5References.addReference( 10731, "⧫"); html5References.addReference( 10731, "⧫"); html5References.addReference( 10740, "⧴"); html5References.addReference( 10742, "⧶"); html5References.addReference( 10752, "⨀"); html5References.addReference( 10752, "⨀"); html5References.addReference( 10753, "⨁"); html5References.addReference( 10753, "⨁"); html5References.addReference( 10754, "⨂"); html5References.addReference( 10754, "⨂"); html5References.addReference( 10756, "⨄"); html5References.addReference( 10756, "⨄"); html5References.addReference( 10758, "⨆"); html5References.addReference( 10758, "⨆"); html5References.addReference( 10764, "⨌"); html5References.addReference( 10764, "⨌"); html5References.addReference( 10765, "⨍"); html5References.addReference( 10768, "⨐"); html5References.addReference( 10769, "⨑"); html5References.addReference( 10770, "⨒"); html5References.addReference( 10771, "⨓"); html5References.addReference( 10772, "⨔"); html5References.addReference( 10773, "⨕"); html5References.addReference( 10774, "⨖"); html5References.addReference( 10775, "⨗"); html5References.addReference( 10786, "⨢"); html5References.addReference( 10787, "⨣"); html5References.addReference( 10788, "⨤"); html5References.addReference( 10789, "⨥"); html5References.addReference( 10790, "⨦"); html5References.addReference( 10791, "⨧"); html5References.addReference( 10793, "⨩"); html5References.addReference( 10794, "⨪"); html5References.addReference( 10797, "⨭"); html5References.addReference( 10798, "⨮"); html5References.addReference( 10799, "⨯"); html5References.addReference( 10800, "⨰"); html5References.addReference( 10801, "⨱"); html5References.addReference( 10803, "⨳"); html5References.addReference( 10804, "⨴"); html5References.addReference( 10805, "⨵"); html5References.addReference( 10806, "⨶"); html5References.addReference( 10807, "⨷"); html5References.addReference( 10808, "⨸"); html5References.addReference( 10809, "⨹"); html5References.addReference( 10810, "⨺"); html5References.addReference( 10811, "⨻"); html5References.addReference( 10812, "⨼"); html5References.addReference( 10812, "⨼"); html5References.addReference( 10815, "⨿"); html5References.addReference( 10816, "⩀"); html5References.addReference( 10818, "⩂"); html5References.addReference( 10819, "⩃"); html5References.addReference( 10820, "⩄"); html5References.addReference( 10821, "⩅"); html5References.addReference( 10822, "⩆"); html5References.addReference( 10823, "⩇"); html5References.addReference( 10824, "⩈"); html5References.addReference( 10825, "⩉"); html5References.addReference( 10826, "⩊"); html5References.addReference( 10827, "⩋"); html5References.addReference( 10828, "⩌"); html5References.addReference( 10829, "⩍"); html5References.addReference( 10832, "⩐"); html5References.addReference( 10835, "⩓"); html5References.addReference( 10836, "⩔"); html5References.addReference( 10837, "⩕"); html5References.addReference( 10838, "⩖"); html5References.addReference( 10839, "⩗"); html5References.addReference( 10840, "⩘"); html5References.addReference( 10842, "⩚"); html5References.addReference( 10843, "⩛"); html5References.addReference( 10844, "⩜"); html5References.addReference( 10845, "⩝"); html5References.addReference( 10847, "⩟"); html5References.addReference( 10854, "⩦"); html5References.addReference( 10858, "⩪"); html5References.addReference( 10861, "⩭"); html5References.addReference( 10861, 824, "⩭̸"); html5References.addReference( 10862, "⩮"); html5References.addReference( 10863, "⩯"); html5References.addReference( 10864, "⩰"); html5References.addReference( 10864, 824, "⩰̸"); html5References.addReference( 10865, "⩱"); html5References.addReference( 10866, "⩲"); html5References.addReference( 10867, "⩳"); html5References.addReference( 10868, "⩴"); html5References.addReference( 10869, "⩵"); html5References.addReference( 10871, "⩷"); html5References.addReference( 10871, "⩷"); html5References.addReference( 10872, "⩸"); html5References.addReference( 10873, "⩹"); html5References.addReference( 10874, "⩺"); html5References.addReference( 10875, "⩻"); html5References.addReference( 10876, "⩼"); html5References.addReference( 10877, "⩽"); html5References.addReference( 10877, "⩽"); html5References.addReference( 10877, "⩽"); html5References.addReference( 10877, 824, "⩽̸"); html5References.addReference( 10877, 824, "⩽̸"); html5References.addReference( 10877, 824, "⩽̸"); html5References.addReference( 10878, "⩾"); html5References.addReference( 10878, "⩾"); html5References.addReference( 10878, "⩾"); html5References.addReference( 10878, 824, "⩾̸"); html5References.addReference( 10878, 824, "⩾̸"); html5References.addReference( 10878, 824, "⩾̸"); html5References.addReference( 10879, "⩿"); html5References.addReference( 10880, "⪀"); html5References.addReference( 10881, "⪁"); html5References.addReference( 10882, "⪂"); html5References.addReference( 10883, "⪃"); html5References.addReference( 10884, "⪄"); html5References.addReference( 10885, "⪅"); html5References.addReference( 10885, "⪅"); html5References.addReference( 10886, "⪆"); html5References.addReference( 10886, "⪆"); html5References.addReference( 10887, "⪇"); html5References.addReference( 10887, "⪇"); html5References.addReference( 10888, "⪈"); html5References.addReference( 10888, "⪈"); html5References.addReference( 10889, "⪉"); html5References.addReference( 10889, "⪉"); html5References.addReference( 10890, "⪊"); html5References.addReference( 10890, "⪊"); html5References.addReference( 10891, "⪋"); html5References.addReference( 10891, "⪋"); html5References.addReference( 10892, "⪌"); html5References.addReference( 10892, "⪌"); html5References.addReference( 10893, "⪍"); html5References.addReference( 10894, "⪎"); html5References.addReference( 10895, "⪏"); html5References.addReference( 10896, "⪐"); html5References.addReference( 10897, "⪑"); html5References.addReference( 10898, "⪒"); html5References.addReference( 10899, "⪓"); html5References.addReference( 10900, "⪔"); html5References.addReference( 10901, "⪕"); html5References.addReference( 10901, "⪕"); html5References.addReference( 10902, "⪖"); html5References.addReference( 10902, "⪖"); html5References.addReference( 10903, "⪗"); html5References.addReference( 10904, "⪘"); html5References.addReference( 10905, "⪙"); html5References.addReference( 10906, "⪚"); html5References.addReference( 10909, "⪝"); html5References.addReference( 10910, "⪞"); html5References.addReference( 10911, "⪟"); html5References.addReference( 10912, "⪠"); html5References.addReference( 10913, "⪡"); html5References.addReference( 10913, 824, "⪡̸"); html5References.addReference( 10914, "⪢"); html5References.addReference( 10914, 824, "⪢̸"); html5References.addReference( 10916, "⪤"); html5References.addReference( 10917, "⪥"); html5References.addReference( 10918, "⪦"); html5References.addReference( 10919, "⪧"); html5References.addReference( 10920, "⪨"); html5References.addReference( 10921, "⪩"); html5References.addReference( 10922, "⪪"); html5References.addReference( 10923, "⪫"); html5References.addReference( 10924, "⪬"); html5References.addReference( 10924, 65024, "⪬︀"); html5References.addReference( 10925, "⪭"); html5References.addReference( 10925, 65024, "⪭︀"); html5References.addReference( 10926, "⪮"); html5References.addReference( 10927, "⪯"); html5References.addReference( 10927, "⪯"); html5References.addReference( 10927, "⪯"); html5References.addReference( 10927, 824, "⪯̸"); html5References.addReference( 10927, 824, "⪯̸"); html5References.addReference( 10927, 824, "⪯̸"); html5References.addReference( 10928, "⪰"); html5References.addReference( 10928, "⪰"); html5References.addReference( 10928, "⪰"); html5References.addReference( 10928, 824, "⪰̸"); html5References.addReference( 10928, 824, "⪰̸"); html5References.addReference( 10928, 824, "⪰̸"); html5References.addReference( 10931, "⪳"); html5References.addReference( 10932, "⪴"); html5References.addReference( 10933, "⪵"); html5References.addReference( 10933, "⪵"); html5References.addReference( 10934, "⪶"); html5References.addReference( 10934, "⪶"); html5References.addReference( 10935, "⪷"); html5References.addReference( 10935, "⪷"); html5References.addReference( 10936, "⪸"); html5References.addReference( 10936, "⪸"); html5References.addReference( 10937, "⪹"); html5References.addReference( 10937, "⪹"); html5References.addReference( 10938, "⪺"); html5References.addReference( 10938, "⪺"); html5References.addReference( 10939, "⪻"); html5References.addReference( 10940, "⪼"); html5References.addReference( 10941, "⪽"); html5References.addReference( 10942, "⪾"); html5References.addReference( 10943, "⪿"); html5References.addReference( 10944, "⫀"); html5References.addReference( 10945, "⫁"); html5References.addReference( 10946, "⫂"); html5References.addReference( 10947, "⫃"); html5References.addReference( 10948, "⫄"); html5References.addReference( 10949, "⫅"); html5References.addReference( 10949, "⫅"); html5References.addReference( 10949, 824, "⫅̸"); html5References.addReference( 10949, 824, "⫅̸"); html5References.addReference( 10950, "⫆"); html5References.addReference( 10950, "⫆"); html5References.addReference( 10950, 824, "⫆̸"); html5References.addReference( 10950, 824, "⫆̸"); html5References.addReference( 10951, "⫇"); html5References.addReference( 10952, "⫈"); html5References.addReference( 10955, "⫋"); html5References.addReference( 10955, "⫋"); html5References.addReference( 10955, 65024, "⫋︀"); html5References.addReference( 10955, 65024, "⫋︀"); html5References.addReference( 10956, "⫌"); html5References.addReference( 10956, "⫌"); html5References.addReference( 10956, 65024, "⫌︀"); html5References.addReference( 10956, 65024, "⫌︀"); html5References.addReference( 10959, "⫏"); html5References.addReference( 10960, "⫐"); html5References.addReference( 10961, "⫑"); html5References.addReference( 10962, "⫒"); html5References.addReference( 10963, "⫓"); html5References.addReference( 10964, "⫔"); html5References.addReference( 10965, "⫕"); html5References.addReference( 10966, "⫖"); html5References.addReference( 10967, "⫗"); html5References.addReference( 10968, "⫘"); html5References.addReference( 10969, "⫙"); html5References.addReference( 10970, "⫚"); html5References.addReference( 10971, "⫛"); html5References.addReference( 10980, "⫤"); html5References.addReference( 10980, "⫤"); html5References.addReference( 10982, "⫦"); html5References.addReference( 10983, "⫧"); html5References.addReference( 10984, "⫨"); html5References.addReference( 10985, "⫩"); html5References.addReference( 10987, "⫫"); html5References.addReference( 10988, "⫬"); html5References.addReference( 10989, "⫭"); html5References.addReference( 10990, "⫮"); html5References.addReference( 10991, "⫯"); html5References.addReference( 10992, "⫰"); html5References.addReference( 10993, "⫱"); html5References.addReference( 10994, "⫲"); html5References.addReference( 10995, "⫳"); html5References.addReference( 11005, "⫽"); html5References.addReference( 11005, 8421, "⫽⃥"); html5References.addReference( 64256, "ff"); html5References.addReference( 64257, "fi"); html5References.addReference( 64258, "fl"); html5References.addReference( 64259, "ffi"); html5References.addReference( 64260, "ffl"); html5References.addReference(119964, "𝒜"); html5References.addReference(119966, "𝒞"); html5References.addReference(119967, "𝒟"); html5References.addReference(119970, "𝒢"); html5References.addReference(119973, "𝒥"); html5References.addReference(119974, "𝒦"); html5References.addReference(119977, "𝒩"); html5References.addReference(119978, "𝒪"); html5References.addReference(119979, "𝒫"); html5References.addReference(119980, "𝒬"); html5References.addReference(119982, "𝒮"); html5References.addReference(119983, "𝒯"); html5References.addReference(119984, "𝒰"); html5References.addReference(119985, "𝒱"); html5References.addReference(119986, "𝒲"); html5References.addReference(119987, "𝒳"); html5References.addReference(119988, "𝒴"); html5References.addReference(119989, "𝒵"); html5References.addReference(119990, "𝒶"); html5References.addReference(119991, "𝒷"); html5References.addReference(119992, "𝒸"); html5References.addReference(119993, "𝒹"); html5References.addReference(119995, "𝒻"); html5References.addReference(119997, "𝒽"); html5References.addReference(119998, "𝒾"); html5References.addReference(119999, "𝒿"); html5References.addReference(120000, "𝓀"); html5References.addReference(120001, "𝓁"); html5References.addReference(120002, "𝓂"); html5References.addReference(120003, "𝓃"); html5References.addReference(120005, "𝓅"); html5References.addReference(120006, "𝓆"); html5References.addReference(120007, "𝓇"); html5References.addReference(120008, "𝓈"); html5References.addReference(120009, "𝓉"); html5References.addReference(120010, "𝓊"); html5References.addReference(120011, "𝓋"); html5References.addReference(120012, "𝓌"); html5References.addReference(120013, "𝓍"); html5References.addReference(120014, "𝓎"); html5References.addReference(120015, "𝓏"); html5References.addReference(120068, "𝔄"); html5References.addReference(120069, "𝔅"); html5References.addReference(120071, "𝔇"); html5References.addReference(120072, "𝔈"); html5References.addReference(120073, "𝔉"); html5References.addReference(120074, "𝔊"); html5References.addReference(120077, "𝔍"); html5References.addReference(120078, "𝔎"); html5References.addReference(120079, "𝔏"); html5References.addReference(120080, "𝔐"); html5References.addReference(120081, "𝔑"); html5References.addReference(120082, "𝔒"); html5References.addReference(120083, "𝔓"); html5References.addReference(120084, "𝔔"); html5References.addReference(120086, "𝔖"); html5References.addReference(120087, "𝔗"); html5References.addReference(120088, "𝔘"); html5References.addReference(120089, "𝔙"); html5References.addReference(120090, "𝔚"); html5References.addReference(120091, "𝔛"); html5References.addReference(120092, "𝔜"); html5References.addReference(120094, "𝔞"); html5References.addReference(120095, "𝔟"); html5References.addReference(120096, "𝔠"); html5References.addReference(120097, "𝔡"); html5References.addReference(120098, "𝔢"); html5References.addReference(120099, "𝔣"); html5References.addReference(120100, "𝔤"); html5References.addReference(120101, "𝔥"); html5References.addReference(120102, "𝔦"); html5References.addReference(120103, "𝔧"); html5References.addReference(120104, "𝔨"); html5References.addReference(120105, "𝔩"); html5References.addReference(120106, "𝔪"); html5References.addReference(120107, "𝔫"); html5References.addReference(120108, "𝔬"); html5References.addReference(120109, "𝔭"); html5References.addReference(120110, "𝔮"); html5References.addReference(120111, "𝔯"); html5References.addReference(120112, "𝔰"); html5References.addReference(120113, "𝔱"); html5References.addReference(120114, "𝔲"); html5References.addReference(120115, "𝔳"); html5References.addReference(120116, "𝔴"); html5References.addReference(120117, "𝔵"); html5References.addReference(120118, "𝔶"); html5References.addReference(120119, "𝔷"); html5References.addReference(120120, "𝔸"); html5References.addReference(120121, "𝔹"); html5References.addReference(120123, "𝔻"); html5References.addReference(120124, "𝔼"); html5References.addReference(120125, "𝔽"); html5References.addReference(120126, "𝔾"); html5References.addReference(120128, "𝕀"); html5References.addReference(120129, "𝕁"); html5References.addReference(120130, "𝕂"); html5References.addReference(120131, "𝕃"); html5References.addReference(120132, "𝕄"); html5References.addReference(120134, "𝕆"); html5References.addReference(120138, "𝕊"); html5References.addReference(120139, "𝕋"); html5References.addReference(120140, "𝕌"); html5References.addReference(120141, "𝕍"); html5References.addReference(120142, "𝕎"); html5References.addReference(120143, "𝕏"); html5References.addReference(120144, "𝕐"); html5References.addReference(120146, "𝕒"); html5References.addReference(120147, "𝕓"); html5References.addReference(120148, "𝕔"); html5References.addReference(120149, "𝕕"); html5References.addReference(120150, "𝕖"); html5References.addReference(120151, "𝕗"); html5References.addReference(120152, "𝕘"); html5References.addReference(120153, "𝕙"); html5References.addReference(120154, "𝕚"); html5References.addReference(120155, "𝕛"); html5References.addReference(120156, "𝕜"); html5References.addReference(120157, "𝕝"); html5References.addReference(120158, "𝕞"); html5References.addReference(120159, "𝕟"); html5References.addReference(120160, "𝕠"); html5References.addReference(120161, "𝕡"); html5References.addReference(120162, "𝕢"); html5References.addReference(120163, "𝕣"); html5References.addReference(120164, "𝕤"); html5References.addReference(120165, "𝕥"); html5References.addReference(120166, "𝕦"); html5References.addReference(120167, "𝕧"); html5References.addReference(120168, "𝕨"); html5References.addReference(120169, "𝕩"); html5References.addReference(120170, "𝕪"); html5References.addReference(120171, "𝕫"); /* * Initialization of escape levels. * Defined levels : * * - Level 0 : Only markup-significant characters except the apostrophe (') * - Level 1 : Only markup-significant characters (including the apostrophe) * - Level 2 : Markup-significant characters plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters */ final byte[] escapeLevels = new byte[0x7f + 2]; Arrays.fill(escapeLevels, (byte)3); for (char c = 'A'; c <= 'Z'; c++) { escapeLevels[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { escapeLevels[c] = 4; } for (char c = '0'; c <= '9'; c++) { escapeLevels[c] = 4; } escapeLevels['\''] = 1; escapeLevels['"'] = 0; escapeLevels['<'] = 0; escapeLevels['>'] = 0; escapeLevels['&'] = 0; escapeLevels[0x7f + 1] = 2; return new HtmlEscapeSymbols(html5References, escapeLevels); } private Html5EscapeSymbolsInitializer() { super(); } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/HtmlEscape.java000066400000000000000000001561421311410233600275340ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.html; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing HTML escape/unescape operations. *

* * Configuration of escape/unescape operations * *

* Escape operations can be (optionally) configured by means of: *

*
    *
  • Level, which defines how deep the escape operation must be (what * chars are to be considered eligible for escaping, depending on the specific * needs of the scenario). Its values are defined by the {@link org.unbescape.html.HtmlEscapeLevel} * enum.
  • *
  • Type, which defines whether escaping should be performed by means of NCRs * (Named Character References), by means of decimal/hexadecimal numerical references, * using the HTML5 or the HTML 4 NCR set, etc. Its values are defined by the * {@link org.unbescape.html.HtmlEscapeType} enum.
  • *
*

* Unescape operations need no configuration parameters. Unescape operations * will always perform complete unescape of NCRs (whole HTML5 set supported), decimal * and hexadecimal references. *

* * Features * *

* Specific features of the HTML escape/unescape operations performed by means of this class: *

*
    *
  • Whole HTML5 NCR (Named Character Reference) set supported, if required: * &rsqb;,&NewLine;, etc. (HTML 4 set available too).
  • *
  • Mixed named and numerical (decimal or hexa) character references supported.
  • *
  • Ability to default to numerical (decimal or hexa) references when an applicable NCR does not exist * (depending on the selected operation level).
  • *
  • Support for the whole Unicode character set: \u0000 to \u10FFFF, including * characters not representable by only one char in Java (>\uFFFF).
  • *
  • Support for unescape of double-char NCRs in HTML5: '&fjlig;''fj'.
  • *
  • Support for a set of HTML5 unescape tweaks included in the HTML5 specification: *
      *
    • Unescape of numerical character references not ending in semi-colon * (e.g. '&#x23ac').
    • *
    • Unescape of specific NCRs not ending in semi-colon (e.g. '&aacute').
    • *
    • Unescape of specific numerical character references wrongly specified by their Windows-1252 * codepage code instead of the Unicode one (e.g. '&#x80;' for '€' * ('&euro;') instead of '&#x20ac;').
    • *
    *
  • *
* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
NCR
*
Named Character Reference or Character Entity Reference: textual * representation of an Unicode codepoint: &aacute;
*
DCR
*
Decimal Character Reference: base-10 numerical representation of an Unicode codepoint: * &#225;
*
HCR
*
Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: * &#xE1;
*
Unicode Codepoint
*
Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the * first char is a high surrogate (\uD800 to \uDBFF) and the * second is a low surrogate (\uDC00 to \uDFFF).
*
* * References * *

* The following references apply: *

* * * * @author Daniel Fernández * * @since 1.0.0 * */ public final class HtmlEscape { /** *

* Perform an HTML5 level 2 (result is ASCII) escape operation on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeHtml5(final String text) { return escapeHtml(text, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML5 level 1 (XML-style) escape operation on a String input. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as {@link #escapeHtml4Xml(String)} because * it will escape the apostrophe as &apos;, whereas in HTML 4 such NCR does not exist * (the decimal numeric reference &#39; is used instead). *

*

* This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeHtml5Xml(final String text) { return escapeHtml(text, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 2 (result is ASCII) escape operation on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeHtml4(final String text) { return escapeHtml(text, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 1 (XML-style) escape operation on a String input. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as {@link #escapeHtml5Xml(String)} because * it will escape the apostrophe as &#39;, whereas in HTML5 there is a specific NCR for * such character (&apos;). *

*

* This method calls {@link #escapeHtml(String, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeHtml4Xml(final String text) { return escapeHtml(text, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) HTML escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel} * argument values. *

*

* All other String-based escapeHtml*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeHtml(final String text, final HtmlEscapeType type, final HtmlEscapeLevel level) { if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return HtmlEscapeUtil.escape(text, type, level); } /** *

* Perform an HTML5 level 2 (result is ASCII) escape operation on a String input, * writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml5(final String text, final Writer writer) throws IOException { escapeHtml(text, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML5 level 1 (XML-style) escape operation on a String input, * writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as {@link #escapeHtml4Xml(String, Writer)} because * it will escape the apostrophe as &apos;, whereas in HTML 4 such NCR does not exist * (the decimal numeric reference &#39; is used instead). *

*

* This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml5Xml(final String text, final Writer writer) throws IOException { escapeHtml(text, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 2 (result is ASCII) escape operation on a String input, * writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml4(final String text, final Writer writer) throws IOException { escapeHtml(text, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 1 (XML-style) escape operation on a String input, * writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as {@link #escapeHtml5Xml(String, Writer)} because * it will escape the apostrophe as &#39;, whereas in HTML5 there is a specific NCR for * such character (&apos;). *

*

* This method calls {@link #escapeHtml(String, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml4Xml(final String text, final Writer writer) throws IOException { escapeHtml(text, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) HTML escape operation on a String input, writing * results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel} * argument values. *

*

* All other String/Writer-based escapeHtml*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml(final String text, final Writer writer, final HtmlEscapeType type, final HtmlEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } HtmlEscapeUtil.escape(new InternalStringReader(text), writer, type, level); } /** *

* Perform an HTML5 level 2 (result is ASCII) escape operation on a Reader input, * writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml5(final Reader reader, final Writer writer) throws IOException { escapeHtml(reader, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML5 level 1 (XML-style) escape operation on a Reader input, * writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as {@link #escapeHtml4Xml(Reader, Writer)} because * it will escape the apostrophe as &apos;, whereas in HTML 4 such NCR does not exist * (the decimal numeric reference &#39; is used instead). *

*

* This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml5Xml(final Reader reader, final Writer writer) throws IOException { escapeHtml(reader, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 2 (result is ASCII) escape operation on a Reader input, * writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml4(final Reader reader, final Writer writer) throws IOException { escapeHtml(reader, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 1 (XML-style) escape operation on a Reader input, * writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as {@link #escapeHtml5Xml(Reader, Writer)} because * it will escape the apostrophe as &#39;, whereas in HTML5 there is a specific NCR for * such character (&apos;). *

*

* This method calls {@link #escapeHtml(Reader, Writer, HtmlEscapeType, HtmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml4Xml(final Reader reader, final Writer writer) throws IOException { escapeHtml(reader, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) HTML escape operation on a Reader input, writing * results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel} * argument values. *

*

* All other Reader/Writer-based escapeHtml*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeHtml(final Reader reader, final Writer writer, final HtmlEscapeType type, final HtmlEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } HtmlEscapeUtil.escape(reader, writer, type, level); } /** *

* Perform an HTML5 level 2 (result is ASCII) escape operation on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML5 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(char[], int, int, java.io.Writer, HtmlEscapeType, HtmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeHtml5(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML5 level 1 (XML-style) escape operation on a char[] input. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as * {@link #escapeHtml4Xml(char[], int, int, java.io.Writer)} because * it will escape the apostrophe as &apos;, whereas in HTML 4 such NCR does not exist * (the decimal numeric reference &#39; is used instead). *

*

* This method calls {@link #escapeHtml(char[], int, int, java.io.Writer, HtmlEscapeType, HtmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeHtml5Xml(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 2 (result is ASCII) escape operation on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding HTML 4 Named Character References * (e.g. '&acute;') when such NCR exists for the replaced character, and replacing by a decimal * character reference (e.g. '&#8345;') when there there is no NCR for the replaced character. *

*

* This method calls {@link #escapeHtml(char[], int, int, java.io.Writer, HtmlEscapeType, HtmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeHtml4(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an HTML 4 level 1 (XML-style) escape operation on a char[] input. *

*

* Level 1 means this method will only escape the five markup-significant characters: * <, >, &, " and '. It is called * XML-style in order to link it with JSP's escapeXml attribute in JSTL's * <c:out ... /> tags. *

*

* Note this method may not produce the same results as * {@link #escapeHtml5Xml(char[], int, int, java.io.Writer)} because it will escape the apostrophe as * &#39;, whereas in HTML5 there is a specific NCR for such character (&apos;). *

*

* This method calls {@link #escapeHtml(char[], int, int, java.io.Writer, HtmlEscapeType, HtmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.html.HtmlEscapeType#HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL}
  • *
  • level: * {@link org.unbescape.html.HtmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeHtml4Xml(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeHtml(text, offset, len, writer, HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL, HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) HTML escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.html.HtmlEscapeType} and {@link org.unbescape.html.HtmlEscapeLevel} * argument values. *

*

* All other char[]-based escapeHtml*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.html.HtmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.html.HtmlEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeHtml(final char[] text, final int offset, final int len, final Writer writer, final HtmlEscapeType type, final HtmlEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } HtmlEscapeUtil.escape(text, offset, len, writer, type, level); } /** *

* Perform an HTML unescape operation on a String input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete unescape of NCRs (whole HTML5 set supported), decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeHtml(final String text) { if (text == null) { return null; } if (text.indexOf('&') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed return text; } return HtmlEscapeUtil.unescape(text); } /** *

* Perform an HTML unescape operation on a String input, writing results to * a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete unescape of NCRs (whole HTML5 set supported), decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeHtml(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (text == null) { return; } if (text.indexOf('&') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed writer.write(text); return; } HtmlEscapeUtil.unescape(new InternalStringReader(text), writer); } /** *

* Perform an HTML unescape operation on a Reader input, writing results to * a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete unescape of NCRs (whole HTML5 set supported), decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeHtml(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } HtmlEscapeUtil.unescape(reader, writer); } /** *

* Perform an HTML unescape operation on a char[] input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete unescape of NCRs (whole HTML5 set supported), decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeHtml(final char[] text, final int offset, final int len, final Writer writer) throws IOException{ if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } HtmlEscapeUtil.unescape(text, offset, len, writer); } private HtmlEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/HtmlEscapeLevel.java000066400000000000000000000137351311410233600305240ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.html; /** *

* Levels defined for HTML escape/unescape operations: *

* *
    *
  • Level 0: Escape only markup-significant characters, excluding the apostrophe. Therefore * <, >, & and " will be escaped. This level can be * used for escaping texts and also tag attributes that are always surrounded by double quotes, whenever the * apostrophe (') is considered a safe character and the user prefers it not to be * escaped for legibility reasons (e.g. might denote literals in expression languages like OGNL). * Note the result of a level-0 escape operation might still contain non-ASCII characters if they existed * in input, and therefore you will still need to correctly manage your input/output character * encoding settings.
  • *
  • Level 1: Escape only markup-significant characters (including the apostrophe). Therefore * <, >, &, " and ' will be escaped. * This level is sometimes called XML escape or XML-style escape, though it * is not exactly equivalent to XML due to some HTML specificities. It is equivalent to the JSP escape * configured by the escapeXml attribute in JSTL's <c:out ... /> tags, and safe * for use in texts and also tag attributes that are always quoted —be it with single (apostrophe) or * double quotes. Note the result of a level-1 escape operation might still contain non-ASCII characters if they * existed in input, and therefore you will still need to correctly manage your input/output character * encoding settings.
  • *
  • Level 2: Escape all markup-significant characters (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings. This level can be used * for escaping texts and also tag attributes that are always quoted —be it with single (apostrophe) or * double quotes.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for escaping texts and also tag attributes, even when these tag attributes are * unquoted.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.html.HtmlEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum HtmlEscapeLevel { /** * Level 0 escape: escape only markup-significant characters, excluding the apostrophe: * <, >, & and " */ LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS(0), /** * Level 1 escape (XML-style): escape only markup-significant characters (including the apostrophe): * <, >, &, " and ' */ LEVEL_1_ONLY_MARKUP_SIGNIFICANT(1), /** * Level 2 escape: escape markup-significant characters plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static HtmlEscapeLevel forLevel(final int level) { switch (level) { case 0: return LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS; case 1: return LEVEL_1_ONLY_MARKUP_SIGNIFICANT; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } HtmlEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/HtmlEscapeSymbols.java000066400000000000000000000535451311410233600311100ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.html; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; /** *

* Instances of this class group all the complex data structures needed to support full escape and unescape * operations for HTML. *

*

* Most of the fields in objects of this class are package-accessible, as the class itself is, in order to allow * them (the fields) to be directly accessed from the classes doing the real escape/unescape (basically, * the {@link HtmlEscapeUtil} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class HtmlEscapeSymbols { /* * GLOSSARY * ------------------------ * * NCR * Named Character Reference or Character Entity Reference: textual * representation of an Unicode codepoint: á * * DCR * Decimal Character Reference: base-10 numerical representation of an Unicode codepoint: á * * HCR * Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: á * * Unicode Codepoint * Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the first char is a high * surrogate (\uD800 to \uDBFF) and the second is a low surrogate (\uDC00 to \uDFFF). * See: http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html * */ /* * Length of the array used for holding the 'base' NCRS indexed by the codepoints themselves. This size * (0x2fff - 12287) is considered enough to hold most of the NCRS that should be needed (HTML4 has 252 * NCRs with a maximum codepoint of 0x2666 - HTML5 has 2125 NCRs with a maximum codepoint of 120171, but * only 138 scarcely used NCRs live above codepoint 0x2fff so an overflow map should be enough for * those 138 cases). */ static final int NCRS_BY_CODEPOINT_LEN = 0x2fff; /* * This array will contain the NCRs for the first NCRS_BY_CODEPOINT_LEN (0x2fff) codepoints, indexed by * the codepoints themselves so that they (even in the form of mere char's) can be used for array random access. * - Values are short in order to index values at the SORTED_NCRS array. This avoids the need for this * array to hold String pointers, which would be 4 bytes in size each (compared to shorts, which are 2 bytes). * - Chars themselves or int codepoints can (will, in fact) be used as indexes. * - Given values are short, the maximum amount of total references this class can handle is 0x7fff = 32767 * (which is safe, because HTML5 has 2125). * - All XML and HTML4 NCRs will fit in this array. In the case of HTML5 NCRs, only 138 of the 2125 will * not fit here (NCRs assigned to codepoints > 0x2fff), and an overflow map will be provided for them. * - Approximate size will be 16 (header) + 12287 * 2 = 24590 bytes. */ final short[] NCRS_BY_CODEPOINT = new short[NCRS_BY_CODEPOINT_LEN]; /* * This map will work as an overflow of the NCRS_BY_CODEPOINT array, so that the codepoint-to-NCR relation is * stored here (with hash-based access) for codepoints >= NCRS_BY_CODEPOINT_LEN (0x2fff). * - The use of a Map here still allows for reasonabily fast access for those rare cases in which codepoints above * 0x2fff are used. * - In the real world, this map will contain the 138 values needed by HTML5 for codepoints >= 0x2fff. * - Approximate max size will be (being a complex object like a Map, it's a rough approximation): * 16 (header) + 138 * (16 (entry header) + 16*2 (key, value headers) + 4 (key) + 2 (value)) = 7468 bytes */ final Map NCRS_BY_CODEPOINT_OVERFLOW;// No need to instantiate it until we know it's needed /* * Maximum char value inside the ASCII plane */ static final char MAX_ASCII_CHAR = 0x7f; /* * This array will hold the 'escape level' assigned to each ASCII character (codepoint), 0x0 to 0x7f and also * a level for the rest of non-ASCII characters. * - These levels are used to configure how (and if) escape operations should ignore ASCII or non-ASCII * characters, or escape them somehow if required. * - Each HtmlEscapeSymbols structure will define a different set of levels for ASCII chars, according to their needs. * - Position 0x7f + 1 represents all the non-ASCII characters. The specified value will determine whether * all non-ASCII characters have to be escaped or not. */ final byte[] ESCAPE_LEVELS = new byte[MAX_ASCII_CHAR + 2]; /* * This array will contain all the NCRs, alphabetically ordered. * - Positions in this array will correspond to positions in the SORTED_CODEPOINTS array, so that one array * (this one) holds the NCRs while the other one holds the codepoint(s) such NCRs refer to. * - Gives the opportunity to store all NCRs in alphabetical order and therefore be able to perform * binary search operations in order to quickly find NCRs (and translate to codepoints) when unescaping. * - Note this array will contain: * * All NCRs referenced from NCRS_BY_CODEPOINT * * NCRs whose codepoint is >= 0x2fff and therefore live in NCRS_BY_CODEPOINT_OVERFLOW * * NCRs which are not referenced in any of the above because they are a shortcut for (and completely * equivalent to) a sequence of two codepoints. These NCRs will only be unescaped, but never escaped. * - Max size in real world, when populated for HTML5: 2125 NCRs * 4 bytes/objref -> 8500 bytes, plus the texts. */ final char[][] SORTED_NCRS; /* * This array contains all the codepoints corresponding to the NCRs stored in SORTED_NCRS. This array is ordered * so that each index in SORTED_NCRS can also be used to retrieve the corresponding CODEPOINT when used on this array. * - Values in this array can be positive (= single codepoint) or negative (= double codepoint, will need further * resolution by means of the DOUBLE_CODEPOINTS array) * - Max size in real world, when populated for HTML5: 2125 NCRs * 4 bytes/objref -> 8500 bytes. */ final int[] SORTED_CODEPOINTS; /* * This array stores the sequences of two codepoints that are escaped as a single NCR. The indexes of this array are * referenced as negative numbers at the SORTED_CODEPOINTS array, and the values are int[2], containing the * sequence of codepoints. HTML4 has no NCRs like this, HTML5 has 93. * - Note this array is only used in UNESCAPE operations. Double-codepoint NCR escape is not performed because * the resulting characters are exactly equivalent to the escape of the two codepoints separately. * - Max size in real world, when populated for HTML5 (rough approximate): 93 * (4 (ref) + 16 + 2 * 4) = 2604 bytes */ final int[][] DOUBLE_CODEPOINTS; /* * This constant will be used at the NCRS_BY_CODEPOINT array to specify there is no NCR associated with a * codepoint. */ static final short NO_NCR = (short) 0; /* * Constants holding the definition of all the HtmlEscapeSymbols for HTML4 and HTML5, to be used in escape and * unescape operations. */ static final HtmlEscapeSymbols HTML4_SYMBOLS; static final HtmlEscapeSymbols HTML5_SYMBOLS; static { HTML4_SYMBOLS = Html4EscapeSymbolsInitializer.initializeHtml4(); HTML5_SYMBOLS = Html5EscapeSymbolsInitializer.initializeHtml5(); } /* * Create a new HtmlEscapeSymbols structure. This will initialize all the structures needed to cover the * specified references and escape levels, including sorted arrays, overflow maps, etc. */ HtmlEscapeSymbols(final References references, final byte[] escapeLevels) { super(); // Initialize ASCII escape levels: just copy the array System.arraycopy(escapeLevels, 0, ESCAPE_LEVELS, 0, (0x7f + 2)); // Initialize some auxiliary structures final List ncrs = new ArrayList(references.references.size() + 5); final List codepoints = new ArrayList(references.references.size() + 5); final List doubleCodepoints = new ArrayList(100); final Map ncrsByCodepointOverflow = new HashMap(20); // For each reference, initialize its corresponding codepoint -> ncr and ncr -> codepoint structures for (final Reference reference : references.references) { final char[] referenceNcr = reference.ncr; final int[] referenceCodepoints = reference.codepoints; ncrs.add(referenceNcr); if (referenceCodepoints.length == 1) { // Only one codepoint (might be > 1 chars, though), this is the normal case final int referenceCodepoint = referenceCodepoints[0]; codepoints.add(Integer.valueOf(referenceCodepoint)); } else if (referenceCodepoints.length == 2) { // Two codepoints, therefore this NCR will translate when unescaping into a two-codepoint // (probably two-char, too) sequence. We will use a negative codepoint value to signal this. doubleCodepoints.add(referenceCodepoints); // Will need to subtract one from its index when unescaping (codepoint = -1 -> position 0) codepoints.add(Integer.valueOf((-1) * doubleCodepoints.size())); } else { throw new RuntimeException( "Unsupported codepoints #: " + referenceCodepoints.length + " for " + new String(referenceNcr)); } } // We hadn't touched this array before. First thing to do is initialize it, as it will have a huge // amount of "empty" (i.e. non-assigned) values. Arrays.fill(NCRS_BY_CODEPOINT, NO_NCR); // We can initialize now these arrays that will hold the NCR-to-codepoint correspondence, but we cannot copy // them directly from our auxiliary structures because we need to order the NCRs alphabetically first. SORTED_NCRS = new char[ncrs.size()][]; SORTED_CODEPOINTS = new int[codepoints.size()]; final List ncrsOrdered = new ArrayList(ncrs); Collections.sort(ncrsOrdered, new Comparator() { public int compare(final char[] o1, final char[] o2) { return HtmlEscapeSymbols.compare(o1, o2, 0, o2.length); } }); for (short i = 0; i < SORTED_NCRS.length; i++) { final char[] ncr = ncrsOrdered.get(i); SORTED_NCRS[i] = ncr; for (short j = 0; j < SORTED_NCRS.length; j++) { if (Arrays.equals(ncr,ncrs.get(j))) { final int cp = codepoints.get(j); SORTED_CODEPOINTS[i] = cp; if (cp > 0) { // Not negative (i.e. not double-codepoint) if (cp < NCRS_BY_CODEPOINT_LEN) { // Not overflown if (NCRS_BY_CODEPOINT[cp] == NO_NCR) { // Only the first NCR for each codepoint will be used for escaping. NCRS_BY_CODEPOINT[cp] = i; } else { final int positionOfCurrent = positionInList(ncrs, SORTED_NCRS[NCRS_BY_CODEPOINT[cp]]); final int positionOfNew = positionInList(ncrs, ncr); if (positionOfNew < positionOfCurrent) { // The order in which NCRs were originally specified in the references argument // marks which NCR should be used for escaping (the first one), if several NCRs // have the same codepoint. NCRS_BY_CODEPOINT[cp] = i; } } } else { // Codepoint should be overflown ncrsByCodepointOverflow.put(Integer.valueOf(cp), Short.valueOf(i)); } } break; } } } // Only create the overflow map if it is really needed. if (ncrsByCodepointOverflow.size() > 0) { NCRS_BY_CODEPOINT_OVERFLOW = ncrsByCodepointOverflow; } else { NCRS_BY_CODEPOINT_OVERFLOW = null; } // Finally, the double-codepoints structure can be initialized, if really needed. if (doubleCodepoints.size() > 0) { DOUBLE_CODEPOINTS = new int[doubleCodepoints.size()][]; for (int i = 0; i < DOUBLE_CODEPOINTS.length; i++) { DOUBLE_CODEPOINTS[i] = doubleCodepoints.get(i); } } else { DOUBLE_CODEPOINTS = null; } } /* * Utility method, used for determining which of the different NCRs for the same * codepoint (when there are many) was specified first, because that is the one * we should be using for escaping. * (Note all of the NCRs will be available for unescaping, obviously) */ private static int positionInList(final List list, final char[] element) { int i = 0; for (final char[] e : list) { if (Arrays.equals(e, element)) { return i; } i++; } return -1; } /* * These two methods (two versions: for String and for char[]) compare each of the candidate * text fragments with an NCR coming from the SORTED_NCRs array, during binary search operations. * * Note these methods not only perform a normal comparison (returning -1, 0 or 1), but will also * return a negative number < -10 when a partial match is possible, this is, when the specified text * fragment contains a complete NCR at its first chars but contains more chars afterwards. This is * useful for matching HTML5 NCRs which do not end in ; (like 'á'), which will come in bigger fragments * because the unescape method will have no way of differentiating the chars after the NCR from chars that * could be in fact part of the NCR. Also note that, in the case of a partial match, (-1) * (returnValue + 10) * will specify the number of matched chars. * * Note we will willingly alter order so that ';' goes always first (even before no-char). This will allow * proper functioning of the partial-matching mechanism for NCRs that can appear both with and without * a ';' suffix. */ private static int compare(final char[] ncr, final String text, final int start, final int end) { final int textLen = end - start; final int maxCommon = Math.min(ncr.length, textLen); int i; // char 0 is discarded, will be & in both cases for (i = 1; i < maxCommon; i++) { final char tc = text.charAt(start + i); if (ncr[i] < tc) { if (tc == ';') { return 1; } return -1; } else if (ncr[i] > tc) { if (ncr[i] == ';') { return -1; } return 1; } } if (ncr.length > i) { if (ncr[i] == ';') { return -1; } return 1; } if (textLen > i) { if (text.charAt(start + i) == ';') { return 1; } // We have a partial match. Can be an NCR not finishing in a semicolon return - ((textLen - i) + 10); } return 0; } private static int compare(final char[] ncr, final char[] text, final int start, final int end) { final int textLen = end - start; final int maxCommon = Math.min(ncr.length, textLen); int i; // char 0 is discarded, will be & in both cases for (i = 1; i < maxCommon; i++) { final char tc = text[start + i]; if (ncr[i] < tc) { if (tc == ';') { return 1; } return -1; } else if (ncr[i] > tc) { if (ncr[i] == ';') { return -1; } return 1; } } if (ncr.length > i) { if (ncr[i] == ';') { return -1; } return 1; } if (textLen > i) { if (text[start + i] == ';') { return 1; } // We have a partial match. Can be an NCR not finishing in a semicolon return - ((textLen - i) + 10); } return 0; } /* * These two methods (two versions: for String and for char[]) are used during unescape at the * {@link HtmlEscapeUtil} class in order to quickly find the NCR corresponding to a preselected fragment * of text (if there is such NCR). * * Note this operation supports partial matching (based on the above 'compare(...)' methods). That way, * if an exact match is not found but a partial match exists, the partial match will be returned. */ static int binarySearch(final char[][] values, final String text, final int start, final int end) { int low = 0; int high = values.length - 1; int partialIndex = Integer.MIN_VALUE; int partialValue = Integer.MIN_VALUE; while (low <= high) { final int mid = (low + high) >>> 1; final char[] midVal = values[mid]; final int cmp = compare(midVal, text, start, end); if (cmp == -1) { low = mid + 1; } else if (cmp == 1) { high = mid - 1; } else if (cmp < -10) { // Partial match low = mid + 1; if (partialIndex == Integer.MIN_VALUE || partialValue < cmp) { partialIndex = mid; partialValue = cmp; // partial will always be negative, and -10. We look for the smallest partial } } else { // Found!! return mid; } } if (partialIndex != Integer.MIN_VALUE) { // We have a partial result. We return the closest result index as negative + (-10) return (-1) * (partialIndex + 10); } return Integer.MIN_VALUE; // Not found! } static int binarySearch(final char[][] values, final char[] text, final int start, final int end) { int low = 0; int high = values.length - 1; int partialIndex = Integer.MIN_VALUE; int partialValue = Integer.MIN_VALUE; while (low <= high) { final int mid = (low + high) >>> 1; final char[] midVal = values[mid]; final int cmp = compare(midVal, text, start, end); if (cmp == -1) { low = mid + 1; } else if (cmp == 1) { high = mid - 1; } else if (cmp < -10) { // Partial match low = mid + 1; if (partialIndex == Integer.MIN_VALUE || partialValue < cmp) { partialIndex = mid; partialValue = cmp; // partial will always be negative, and -10. We look for the smallest partial } } else { // Found!! return mid; } } if (partialIndex != Integer.MIN_VALUE) { // We have a partial result. We return the closest result index as negative + (-10) return (-1) * (partialIndex + 10); } return Integer.MIN_VALUE; // Not found! } /* * Inner utility classes that model the named character references to be included in an initialized * instance of the HtmlEscapeSymbols class. */ static final class References { private final List references = new ArrayList(200); References() { super(); } void addReference(final int codepoint, final String ncr) { this.references.add(new Reference(ncr, new int[]{codepoint})); } void addReference(final int codepoint0, final int codepoint1, final String ncr) { this.references.add(new Reference(ncr, new int[] { codepoint0, codepoint1 })); } } private static final class Reference { private final char[] ncr; private final int[] codepoints; private Reference(final String ncr, final int[] codepoints) { super(); this.ncr = ncr.toCharArray(); this.codepoints = codepoints; } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/HtmlEscapeType.java000066400000000000000000000111611311410233600303650ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.html; /** *

* Types of escape operations to be performed on HTML text: *

* *
    *
  • HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL: Replace escaped characters * with HTML 4 Named Character References (Character Entity References) whenever * possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to * using Decimal Character References for escaped characters that do not have an associated * NCR.
  • *
  • HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA: Replace escaped characters * with HTML 4 Named Character References (Character Entity References) whenever * possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to * using Hexadecimal Character References for escaped characters that do not have an associated * NCR.
  • *
  • HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL: Replace escaped characters * with HTML5 Named Character References whenever * possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to * using Decimal Character References for escaped characters that do not have an associated * NCR.
  • *
  • HTML5_NAMED_REFERENCES_DEFAULT_TO_HEXA: Replace escaped characters * with HTML5 Named Character References whenever * possible (depending on the specified {@link org.unbescape.html.HtmlEscapeLevel}), and default to * using Hexadecimal Character References for escaped characters that do not have an associated * NCR.
  • *
  • DECIMAL_REFERENCES: Replace escaped characters with * Decimal Character References (will never use NCRs).
  • *
  • HEXADECIMAL_REFERENCES: Replace escaped characters with * Hexadecimal Character References (will never use NCRs).
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.html.HtmlEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum HtmlEscapeType { /** * Use HTML 4 NCRs if possible, default to Decimal Character References. */ HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL(true, false, false), /** * Use HTML 4 NCRs if possible, default to Hexadecimal Character References. */ HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA(true, true, false), /** * Use HTML5 NCRs if possible, default to Decimal Character References. */ HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL(true, false, true), /** * Use HTML5 NCRs if possible, default to Hexadecimal Character References. */ HTML5_NAMED_REFERENCES_DEFAULT_TO_HEXA(true, true, true), /** * Always use Decimal Character References (no NCRs will be used). */ DECIMAL_REFERENCES(false, false, false), /** * Always use Hexadecimal Character References (no NCRs will be used). */ HEXADECIMAL_REFERENCES(false, true, false); private final boolean useNCRs; private final boolean useHexa; private final boolean useHtml5; HtmlEscapeType(final boolean useNCRs, final boolean useHexa, final boolean useHtml5) { this.useNCRs = useNCRs; this.useHexa = useHexa; this.useHtml5 = useHtml5; } boolean getUseNCRs() { return this.useNCRs; } boolean getUseHexa() { return this.useHexa; } boolean getUseHtml5() { return this.useHtml5; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/html/HtmlEscapeUtil.java000066400000000000000000001375311311410233600303730ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.html; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class HtmlEscapeUtil { /* * GLOSSARY * ------------------------ * * NCR * Named Character Reference or Character Entity Reference: textual * representation of an Unicode codepoint: á * * DCR * Decimal Character Reference: base-10 numerical representation of an Unicode codepoint: á * * HCR * Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: á * * Unicode Codepoint * Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the first char is a high * surrogate (\uD800 to \uDBFF) and the second is a low surrogate (\uDC00 to \uDFFF). * See: http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html * */ /* * Prefixes and suffix defined for use in decimal/hexa escape and unescape. */ private static final char REFERENCE_PREFIX = '&'; private static final char REFERENCE_NUMERIC_PREFIX2 = '#'; private static final char REFERENCE_HEXA_PREFIX3_UPPER = 'X'; private static final char REFERENCE_HEXA_PREFIX3_LOWER = 'x'; private static final char[] REFERENCE_DECIMAL_PREFIX = "&#".toCharArray(); private static final char[] REFERENCE_HEXA_PREFIX = "&#x".toCharArray(); private static final char REFERENCE_SUFFIX = ';'; /* * Small utility char arrays for hexadecimal conversion */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); private HtmlEscapeUtil() { super(); } /* * Perform an escape operation, based on String, according to the specified level and type. */ static String escape(final String text, final HtmlEscapeType escapeType, final HtmlEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); final boolean useHtml5 = escapeType.getUseHtml5(); final boolean useNCRs = escapeType.getUseNCRs(); final boolean useHexa = escapeType.getUseHexa(); final HtmlEscapeSymbols symbols = (useHtml5? HtmlEscapeSymbols.HTML5_SYMBOLS : HtmlEscapeSymbols.HTML4_SYMBOLS); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (c <= HtmlEscapeSymbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[c]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (c > HtmlEscapeSymbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[HtmlEscapeSymbols.MAX_ASCII_CHAR + 1]) { continue; } /* * Compute the codepoint. This will be used instead of the char for the rest of the process. */ final int codepoint = Character.codePointAt(text, i); /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs. * * ----------------------------------------------------------------------------------------- */ if (useNCRs) { // We will try to use an NCR if (codepoint < symbols.NCRS_BY_CODEPOINT_LEN) { // codepoint < 0x2fff - all HTML4, most HTML5 final short ncrIndex = symbols.NCRS_BY_CODEPOINT[codepoint]; if (ncrIndex != symbols.NO_NCR) { // There is an NCR for this codepoint! strBuilder.append(symbols.SORTED_NCRS[ncrIndex]); continue; } // else, just let it exit the block and let decimal/hexa escape do its job } else if (symbols.NCRS_BY_CODEPOINT_OVERFLOW != null) { // codepoint >= 0x2fff. NCR, if exists, will live at the overflow map (if there is one). final Short ncrIndex = symbols.NCRS_BY_CODEPOINT_OVERFLOW.get(Integer.valueOf(codepoint)); if (ncrIndex != null) { strBuilder.append(symbols.SORTED_NCRS[ncrIndex.shortValue()]); continue; } // else, just let it exit the block and let decimal/hexa escape do its job } } /* * No NCR-escape was possible (or allowed), so we need decimal/hexa escape. */ if (useHexa) { strBuilder.append(REFERENCE_HEXA_PREFIX); strBuilder.append(Integer.toHexString(codepoint)); } else { strBuilder.append(REFERENCE_DECIMAL_PREFIX); strBuilder.append(String.valueOf(codepoint)); } strBuilder.append(REFERENCE_SUFFIX); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final HtmlEscapeType escapeType, final HtmlEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useHtml5 = escapeType.getUseHtml5(); final boolean useNCRs = escapeType.getUseNCRs(); final boolean useHexa = escapeType.getUseHexa(); final HtmlEscapeSymbols symbols = (useHtml5? HtmlEscapeSymbols.HTML5_SYMBOLS : HtmlEscapeSymbols.HTML4_SYMBOLS); int c1, c2; // c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (c1 <= HtmlEscapeSymbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[c1]) { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (c1 > HtmlEscapeSymbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[HtmlEscapeSymbols.MAX_ASCII_CHAR + 1]) { writer.write(c1); continue; } /* * Compute the codepoint. This will be used instead of the char for the rest of the process. */ final int codepoint = codePointAt((char)c1, (char)c2); /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c1 = c2; c2 = reader.read(); } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs. * * ----------------------------------------------------------------------------------------- */ if (useNCRs) { // We will try to use an NCR if (codepoint < symbols.NCRS_BY_CODEPOINT_LEN) { // codepoint < 0x2fff - all HTML4, most HTML5 final short ncrIndex = symbols.NCRS_BY_CODEPOINT[codepoint]; if (ncrIndex != symbols.NO_NCR) { // There is an NCR for this codepoint! writer.write(symbols.SORTED_NCRS[ncrIndex]); continue; } // else, just let it exit the block and let decimal/hexa escape do its job } else if (symbols.NCRS_BY_CODEPOINT_OVERFLOW != null) { // codepoint >= 0x2fff. NCR, if exists, will live at the overflow map (if there is one). final Short ncrIndex = symbols.NCRS_BY_CODEPOINT_OVERFLOW.get(Integer.valueOf(codepoint)); if (ncrIndex != null) { writer.write(symbols.SORTED_NCRS[ncrIndex.shortValue()]); continue; } // else, just let it exit the block and let decimal/hexa escape do its job } } /* * No NCR-escape was possible (or allowed), so we need decimal/hexa escape. */ if (useHexa) { writer.write(REFERENCE_HEXA_PREFIX); writer.write(Integer.toHexString(codepoint)); } else { writer.write(REFERENCE_DECIMAL_PREFIX); writer.write(String.valueOf(codepoint)); } writer.write(REFERENCE_SUFFIX); } } /* * Perform an escape operation, based on char[], according to the specified level and type. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final HtmlEscapeType escapeType, final HtmlEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useHtml5 = escapeType.getUseHtml5(); final boolean useNCRs = escapeType.getUseNCRs(); final boolean useHexa = escapeType.getUseHexa(); final HtmlEscapeSymbols symbols = (useHtml5? HtmlEscapeSymbols.HTML5_SYMBOLS : HtmlEscapeSymbols.HTML4_SYMBOLS); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (c <= symbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[c]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (c > symbols.MAX_ASCII_CHAR && level < symbols.ESCAPE_LEVELS[symbols.MAX_ASCII_CHAR + 1]) { continue; } /* * Compute the codepoint. This will be used instead of the char for the rest of the process. */ final int codepoint = Character.codePointAt(text, i); /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs. * * ----------------------------------------------------------------------------------------- */ if (useNCRs) { // We will try to use an NCR if (codepoint < symbols.NCRS_BY_CODEPOINT_LEN) { // codepoint < 0x2fff - all HTML4, most HTML5 final short ncrIndex = symbols.NCRS_BY_CODEPOINT[codepoint]; if (ncrIndex != symbols.NO_NCR) { // There is an NCR for this codepoint! writer.write(symbols.SORTED_NCRS[ncrIndex]); continue; } // else, just let it exit the block and let decimal/hexa escape do its job } else if (symbols.NCRS_BY_CODEPOINT_OVERFLOW != null) { // codepoint >= 0x2fff. NCR, if exists, will live at the overflow map (if there is one). final Short ncrIndex = symbols.NCRS_BY_CODEPOINT_OVERFLOW.get(Integer.valueOf(codepoint)); if (ncrIndex != null) { writer.write(symbols.SORTED_NCRS[ncrIndex.shortValue()]); continue; } // else, just let it exit the block and let decimal/hexa escape do its job } } /* * No NCR-escape was possible (or allowed), so we need decimal/hexa escape. */ if (useHexa) { writer.write(REFERENCE_HEXA_PREFIX); writer.write(Integer.toHexString(codepoint)); } else { writer.write(REFERENCE_DECIMAL_PREFIX); writer.write(String.valueOf(codepoint)); } writer.write(REFERENCE_SUFFIX); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the writer and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } /* * This translation is needed during unescape to support ill-formed escape codes for Windows 1252 codes * instead of the correct unicode ones (for example, € for the euro symbol instead of €). This is * something browsers do support, and included in the HTML5 spec for consuming character references. * See http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference */ static int translateIllFormedCodepoint(final int codepoint) { switch (codepoint) { case 0x00: return 0xFFFD; case 0x80: return 0x20AC; case 0x82: return 0x201A; case 0x83: return 0x0192; case 0x84: return 0x201E; case 0x85: return 0x2026; case 0x86: return 0x2020; case 0x87: return 0x2021; case 0x88: return 0x02C6; case 0x89: return 0x2030; case 0x8A: return 0x0160; case 0x8B: return 0x2039; case 0x8C: return 0x0152; case 0x8E: return 0x017D; case 0x91: return 0x2018; case 0x92: return 0x2019; case 0x93: return 0x201C; case 0x94: return 0x201D; case 0x95: return 0x2022; case 0x96: return 0x2013; case 0x97: return 0x2014; case 0x98: return 0x02DC; case 0x99: return 0x2122; case 0x9A: return 0x0161; case 0x9B: return 0x203A; case 0x9C: return 0x0153; case 0x9E: return 0x017E; case 0x9F: return 0x0178; default: break; } if (codepoint >= 0xD800 && codepoint <= 0xDFFF) { return 0xFFFD; } else if (codepoint > 0x10FFFF) { return 0xFFFD; } else { return codepoint; } } /* * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need * to create substrings of the text being unescaped to feed such method. * - No need to check all chars are within the radix limits - reference parsing code will already have done so. */ static int parseIntFromReference(final String text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text.charAt(i); int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result *= radix; if (result < 0) { return 0xFFFD; } result += n; if (result < 0) { return 0xFFFD; } } return result; } static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result *= radix; if (result < 0) { return 0xFFFD; } result += n; if (result < 0) { return 0xFFFD; } } return result; } /* * Perform an unescape operation based on String. Unescape operations are always based on the HTML5 symbol set. * Unescape operations will be performed in the most similar way possible to the process a browser follows for * showing HTML5 escaped code. See: http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference */ static String unescape(final String text) { if (text == null) { return null; } // Unescape will always cover the full HTML5 spectrum. final HtmlEscapeSymbols symbols = HtmlEscapeSymbols.HTML5_SYMBOLS; StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != REFERENCE_PREFIX || (i + 1) >= max) { continue; } int codepoint = 0; if (c == REFERENCE_PREFIX) { final char c1 = text.charAt(i + 1); if (c1 == '\u0020' || // SPACE c1 == '\n' || // LF c1 == '\u0009' || // TAB c1 == '\u000C' || // FF c1 == '\u003C' || // LES-THAN SIGN c1 == '\u0026') { // AMPERSAND // Not a character references. No characters are consumed, and nothing is returned. continue; } else if (c1 == REFERENCE_NUMERIC_PREFIX2) { if (i + 2 >= max) { // No reference possible continue; } final char c2 = text.charAt(i + 2); if ((c2 == REFERENCE_HEXA_PREFIX3_LOWER || c2 == REFERENCE_HEXA_PREFIX3_UPPER) && (i + 3) < max) { // This is a hexadecimal reference int f = i + 3; while (f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 3)) <= 0) { // We weren't able to consume any hexa chars continue; } codepoint = parseIntFromReference(text, i + 3, f, 16); referenceOffset = f - 1; if ((f < max) && text.charAt(f) == REFERENCE_SUFFIX) { referenceOffset++; } codepoint = translateIllFormedCodepoint(codepoint); // Don't continue here, just let the unescape code below do its job } else if (c2 >= '0' && c2 <= '9') { // This is a decimal reference int f = i + 2; while (f < max) { final char cf = text.charAt(f); if (!(cf >= '0' && cf <= '9')) { break; } f++; } if ((f - (i + 2)) <= 0) { // We weren't able to consume any decimal chars continue; } codepoint = parseIntFromReference(text, i + 2, f, 10); referenceOffset = f - 1; if ((f < max) && text.charAt(f) == REFERENCE_SUFFIX) { referenceOffset++; } codepoint = translateIllFormedCodepoint(codepoint); // Don't continue here, just let the unescape code below do its job } else { // This is not a valid reference, just discard continue; } } else { // This is a named reference, must be comprised only of ALPHABETIC chars int f = i + 1; while (f < max) { final char cf = text.charAt(f); if (!((cf >= 'a' && cf <= 'z') || (cf >= 'A' && cf <= 'Z') || (cf >= '0' && cf <= '9'))) { break; } f++; } if ((f - (i + 1)) <= 0) { // We weren't able to consume any alphanumeric continue; } if ((f < max) && text.charAt(f) == REFERENCE_SUFFIX) { f++; } final int ncrPosition = HtmlEscapeSymbols.binarySearch(symbols.SORTED_NCRS, text, i, f); if (ncrPosition >= 0) { codepoint = symbols.SORTED_CODEPOINTS[ncrPosition]; } else if (ncrPosition == Integer.MIN_VALUE) { // Not found! Just ignore our efforts to find a match. continue; } else if (ncrPosition < -10) { // Found but partial! final int partialIndex = (-1) * (ncrPosition + 10); final char[] partialMatch = symbols.SORTED_NCRS[partialIndex]; codepoint = symbols.SORTED_CODEPOINTS[partialIndex]; f -= ((f - i) - partialMatch.length); // un-consume the chars remaining from the partial match } else { // Should never happen! throw new RuntimeException("Invalid unescape codepoint after search: " + ncrPosition); } referenceOffset = f - 1; } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else if (codepoint < 0) { // This is a double-codepoint unescape operation final int[] codepoints = symbols.DOUBLE_CODEPOINTS[((-1) * codepoint) - 1]; if (codepoints[0] > '\uFFFF') { strBuilder.append(Character.toChars(codepoints[0])); } else { strBuilder.append((char) codepoints[0]); } if (codepoints[1] > '\uFFFF') { strBuilder.append(Character.toChars(codepoints[1])); } else { strBuilder.append((char) codepoints[1]); } } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a Writer. Unescape operations are * always based on the HTML5 symbol set. Unescape operations will be performed in the most similar way * possible to the process a browser follows for showing HTML5 escaped code. * See: http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } // Unescape will always cover the full HTML5 spectrum. final HtmlEscapeSymbols symbols = HtmlEscapeSymbols.HTML5_SYMBOLS; char[] escapes = new char[10]; int escapei = 0; int c1, c2, ce; // c1: current char, c2: next char, ce: current escaped char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); escapei = 0; /* * Check the need for an unescape operation at this point */ if (c1 != REFERENCE_PREFIX || c2 < 0) { writer.write(c1); continue; } int codepoint = 0; if (c1 == REFERENCE_PREFIX) { if (c2 == '\u0020' || // SPACE c2 == '\n' || // LF c2 == '\u0009' || // TAB c2 == '\u000C' || // FF c2 == '\u003C' || // LES-THAN SIGN c2 == '\u0026') { // AMPERSAND // Not a character references. No characters are consumed, and nothing is returned. writer.write(c1); continue; } else if (c2 == REFERENCE_NUMERIC_PREFIX2) { final int c3 = reader.read(); if (c3 < 0) { // No reference possible writer.write(c1); writer.write(c2); c1 = c2; c2 = c3; continue; } if ((c3 == REFERENCE_HEXA_PREFIX3_LOWER || c3 == REFERENCE_HEXA_PREFIX3_UPPER)) { // This is a hexadecimal reference ce = reader.read(); while (ce >= 0) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) { break; } if (escapei == escapes.length) { // too many escape chars for our array: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei == 0) { // We weren't able to consume any hexa chars writer.write(c1); writer.write(c2); writer.write(c3); c1 = c3; c2 = ce; continue; } c1 = escapes[escapei - 1]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, escapei, 16); if (c2 == REFERENCE_SUFFIX) { // If the reference ends in a ';', just consume it c1 = c2; c2 = reader.read(); } codepoint = translateIllFormedCodepoint(codepoint); escapei = 0; // Don't continue here, just let the unescape code below do its job } else if (c3 >= '0' && c3 <= '9') { // This is a decimal reference ce = c3; while (ce >= 0) { if (!(ce >= '0' && ce <= '9')) { break; } if (escapei == escapes.length) { // too many escape chars for our array: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei == 0) { // We weren't able to consume any decimal chars writer.write(c1); writer.write(c2); c1 = c2; c2 = c3; continue; } c1 = escapes[escapei - 1]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, escapei, 10); if (c2 == REFERENCE_SUFFIX) { // If the reference ends in a ';', just consume it c1 = c2; c2 = reader.read(); } codepoint = translateIllFormedCodepoint(codepoint); escapei = 0; // Don't continue here, just let the unescape code below do its job } else { // This is not a valid reference, just discard writer.write(c1); writer.write(c2); c1 = c2; c2 = c3; continue; } } else { // This is a named reference, must be comprised only of ALPHABETIC chars ce = c2; while (ce >= 0) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'Z') || (ce >= 'a' && ce <= 'z'))) { break; } if (escapei == escapes.length) { // too many escape chars for our array: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei == 0) { // We weren't able to consume any decimal chars writer.write(c1); continue; } if (escapei + 2 >= escapes.length) { // the entire escape sequence does not fit: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } System.arraycopy(escapes, 0, escapes, 1, escapei); escapes[0] = (char) c1; escapei++; if (ce == REFERENCE_SUFFIX) { // If the reference ends in a ';', just consume it escapes[escapei++] = (char) ce; ce = reader.read(); } c1 = escapes[escapei - 1]; c2 = ce; final int ncrPosition = HtmlEscapeSymbols.binarySearch(symbols.SORTED_NCRS, escapes, 0, escapei); if (ncrPosition >= 0) { codepoint = symbols.SORTED_CODEPOINTS[ncrPosition]; escapei = 0; } else if (ncrPosition == Integer.MIN_VALUE) { // Not found! Just ignore our efforts to find a match. writer.write(escapes, 0, escapei); continue; } else if (ncrPosition < -10) { // Found but partial! final int partialIndex = (-1) * (ncrPosition + 10); final char[] partialMatch = symbols.SORTED_NCRS[partialIndex]; codepoint = symbols.SORTED_CODEPOINTS[partialIndex]; System.arraycopy(escapes, partialMatch.length, escapes, 0, (escapei - partialMatch.length)); escapei -= partialMatch.length; // so that we know we have to output the rest of 'escapes' } else { // Should never happen! throw new RuntimeException("Invalid unescape codepoint after search: " + ncrPosition); } } } /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else if (codepoint < 0) { // This is a double-codepoint unescape operation final int[] codepoints = symbols.DOUBLE_CODEPOINTS[((-1) * codepoint) - 1]; if (codepoints[0] > '\uFFFF') { writer.write(Character.toChars(codepoints[0])); } else { writer.write((char) codepoints[0]); } if (codepoints[1] > '\uFFFF') { writer.write(Character.toChars(codepoints[1])); } else { writer.write((char) codepoints[1]); } } else { writer.write((char)codepoint); } /* * ---------------------------------------- * Cleanup, in case we had a partial match * ---------------------------------------- */ if (escapei > 0) { writer.write(escapes, 0, escapei); escapei = 0; } } } /* * Perform an unescape operation based on char[]. Unescape operations are always based on the HTML5 symbol set. * Unescape operations will be performed in the most similar way possible to the process a browser follows for * showing HTML5 escaped code. See: http://www.w3.org/TR/html5/syntax.html#consume-a-character-reference */ static void unescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } final HtmlEscapeSymbols symbols = HtmlEscapeSymbols.HTML5_SYMBOLS; final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != REFERENCE_PREFIX || (i + 1) >= max) { continue; } int codepoint = 0; if (c == REFERENCE_PREFIX) { final char c1 = text[i + 1]; if (c1 == '\u0020' || // SPACE c1 == '\n' || // LF c1 == '\u0009' || // TAB c1 == '\u000C' || // FF c1 == '\u003C' || // LES-THAN SIGN c1 == '\u0026') { // AMPERSAND // Not a character references. No characters are consumed, and nothing is returned. continue; } else if (c1 == REFERENCE_NUMERIC_PREFIX2) { if (i + 2 >= max) { // No reference possible continue; } final char c2 = text[i + 2]; if ((c2 == REFERENCE_HEXA_PREFIX3_LOWER || c2 == REFERENCE_HEXA_PREFIX3_UPPER) && (i + 3) < max) { // This is a hexadecimal reference int f = i + 3; while (f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 3)) <= 0) { // We weren't able to consume any hexa chars continue; } codepoint = parseIntFromReference(text, i + 3, f, 16); referenceOffset = f - 1; if ((f < max) && text[f] == REFERENCE_SUFFIX) { referenceOffset++; } codepoint = translateIllFormedCodepoint(codepoint); // Don't continue here, just let the unescape code below do its job } else if (c2 >= '0' && c2 <= '9') { // This is a decimal reference int f = i + 2; while (f < max) { final char cf = text[f]; if (!(cf >= '0' && cf <= '9')) { break; } f++; } if ((f - (i + 2)) <= 0) { // We weren't able to consume any decimal chars continue; } codepoint = parseIntFromReference(text, i + 2, f, 10); referenceOffset = f - 1; if ((f < max) && text[f] == REFERENCE_SUFFIX) { referenceOffset++; } codepoint = translateIllFormedCodepoint(codepoint); // Don't continue here, just let the unescape code below do its job } else { // This is not a valid reference, just discard continue; } } else { // This is a named reference, must be comprised only of ALPHABETIC chars int f = i + 1; while (f < max) { final char cf = text[f]; if (!((cf >= 'a' && cf <= 'z') || (cf >= 'A' && cf <= 'Z') || (cf >= '0' && cf <= '9'))) { break; } f++; } if ((f - (i + 1)) <= 0) { // We weren't able to consume any alphanumeric continue; } if ((f < max) && text[f] == REFERENCE_SUFFIX) { f++; } final int ncrPosition = HtmlEscapeSymbols.binarySearch(symbols.SORTED_NCRS, text, i, f); if (ncrPosition >= 0) { codepoint = symbols.SORTED_CODEPOINTS[ncrPosition]; } else if (ncrPosition == Integer.MIN_VALUE) { // Not found! Just ignore our efforts to find a match. continue; } else if (ncrPosition < -10) { // Found but partial! final int partialIndex = (-1) * (ncrPosition + 10); final char[] partialMatch = symbols.SORTED_NCRS[partialIndex]; codepoint = symbols.SORTED_CODEPOINTS[partialIndex]; f -= ((f - i) - partialMatch.length); // un-consume the chars remaining from the partial match } else { // Should never happen! throw new RuntimeException("Invalid unescape codepoint after search: " + ncrPosition); } referenceOffset = f - 1; } } /* * At this point we know for sure we will need some kind of unescape, so we * write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else if (codepoint < 0) { // This is a double-codepoint unescape operation final int[] codepoints = symbols.DOUBLE_CODEPOINTS[((-1) * codepoint) - 1]; if (codepoints[0] > '\uFFFF') { writer.write(Character.toChars(codepoints[0])); } else { writer.write((char) codepoints[0]); } if (codepoints[1] > '\uFFFF') { writer.write(Character.toChars(codepoints[1])); } else { writer.write((char) codepoints[1]); } } else { writer.write((char) codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: writer the remaining escaped text and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/java/000077500000000000000000000000001311410233600246105ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/java/JavaEscape.java000066400000000000000000001254341311410233600274660ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.java; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing Java escape/unescape operations. *

* * Configuration of escape/unescape operations * *

* Escape operations can be (optionally) configured by means of: *

*
    *
  • Level, which defines how deep the escape operation must be (what * chars are to be considered eligible for escaping, depending on the specific * needs of the scenario). Its values are defined by the {@link JavaEscapeLevel} * enum.
  • *
*

* Unbescape does not define a 'type' for Java escaping (just a level) because, * given the way Unicode Escapes work in Java, there is no possibility to choose whether we want to escape, for * example, a tab character (U+0009) as a Single Escape Char (\t) or as a Unicode Escape * (\u0009). Given Unicode Escapes are processed by the compiler and not the runtime, using * \u0009 instead of \t would really insert a tab character inside our source * code before compiling, which is not equivalent to inserting "\t" in a String literal. *

*

* Unescape operations need no configuration parameters. Unescape operations * will always perform complete unescape of SECs (\n), * u-based (\u00E1) and octal (\341) escapes. *

* * Features * *

* Specific features of the Java escape/unescape operations performed by means of this class: *

*
    *
  • The Java basic escape set is supported. This basic set consists of: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • U-based hexadecimal escapes (a.k.a. unicode escapes) are supported both in escape * and unescape operations: \u00E1.
  • *
  • Octal escapes are supported, though only in unescape operations: \071. These are not supported * in escape operations because the use of octal escapes is not recommended by the Java Language Specification * (it's usage is allowed mainly for C compatibility reasons).
  • *
  • Support for the whole Unicode character set: \u0000 to \u10FFFF, including * characters not representable by only one char in Java (>\uFFFF).
  • *
* * Specific features of Unicode Escapes in Java * *

* The way Unicode Escapes work in Java is different to other languages like e.g. JavaScript. In Java, * these UHEXA escapes are processed by the compiler itself, and therefore resolved before any other * type of escapes. Besides, UHEXA escapes can appear anywhere in the code, not only String literals. * This means that, while in JavaScript 'a\u005Cna' would be displayed as a\na, * in Java "a\u005Cna" would in fact be displayed in two lines: * a+<LF>+a. *

*

* Going even further, this is perfectly valid Java code: *

* * final String hello = \u0022Hello, World!\u0022; * *

* Also, Java allows to write any number of 'u' characters in this type of escapes, like * \uu00E1 or even \uuuuuuuuu00E1. This is so in order to enable legacy * compatibility with older code-processing tools that didn't support Unicode processing at all, which * would fail when finding an Unicode escape like \u00E1, but not \uu00E1 * (because they would consider \u as the escape). So this is valid Java code too: *

* * final String hello = \uuuuuuuu0022Hello, World!\u0022; * *

* In order to correctly unescape Java UHEXA escapes like "a\u005Cna", Unbescape will * perform a two-pass process so that all unicode escapes are processed in the first pass, and then * the single escape characters and octal escapes in the second pass. *

* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
SEC
*
Single Escape Character: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
*
UHEXA escapes
*
Also called u-based hexadecimal escapes or simply unicode escapes: * complete representation of unicode codepoints up to U+FFFF, with \u * followed by exactly four hexadecimal figures: \u00E1. Unicode codepoints > * U+FFFF can be represented in Java by mean of two UHEXA escapes (a * surrogate pair).
*
Octal escapes
*
Octal representation of unicode codepoints up to U+00FF, with \ * followed by up to three octal figures: \071. Though up to three octal figures * are allowed, octal numbers > 377 (0xFF) are not supported. These are not supported * in escape operations because the use of octal escapes is not recommended by the Java Language Specification * (it's usage is allowed mainly for C compatibility reasons).
*
Unicode Codepoint
*
Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the * first char is a high surrogate (\uD800 to \uDBFF) and the * second is a low surrogate (\uDC00 to \uDFFF).
*
* * References * *

* The following references apply: *

* * * @author Daniel Fernández * * @since 1.0.0 * */ public final class JavaEscape { /** *

* Perform a Java level 1 (only basic set) escape operation * on a String input. *

*

* Level 1 means this method will only escape the Java basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapeJava(String, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJavaMinimal(final String text) { return escapeJava(text, JavaEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java level 2 (basic set and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeJava(String, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJava(final String text) { return escapeJava(text, JavaEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.java.JavaEscapeLevel} argument value. *

*

* All other String-based escapeJava*(...) methods call this one with preconfigured * level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param level the escape level to be applied, see {@link org.unbescape.java.JavaEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJava(final String text, final JavaEscapeLevel level) { if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return JavaEscapeUtil.escape(text, level); } /** *

* Perform a Java level 1 (only basic set) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the Java basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapeJava(String, Writer, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaMinimal(final String text, final Writer writer) throws IOException { escapeJava(text, writer, JavaEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java level 2 (basic set and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeJava(String, Writer, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJava(final String text, final Writer writer) throws IOException { escapeJava(text, writer, JavaEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.java.JavaEscapeLevel} argument value. *

*

* All other String/Writer-based escapeJava*(...) methods call this one with preconfigured * level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.java.JavaEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJava(final String text, final Writer writer, final JavaEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } JavaEscapeUtil.escape(new InternalStringReader(text), writer, level); } /** *

* Perform a Java level 1 (only basic set) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the Java basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapeJava(Reader, Writer, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaMinimal(final Reader reader, final Writer writer) throws IOException { escapeJava(reader, writer, JavaEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java level 2 (basic set and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeJava(Reader, Writer, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJava(final Reader reader, final Writer writer) throws IOException { escapeJava(reader, writer, JavaEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.java.JavaEscapeLevel} argument value. *

*

* All other String/Writer-based escapeJava*(...) methods call this one with preconfigured * level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.java.JavaEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJava(final Reader reader, final Writer writer, final JavaEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } JavaEscapeUtil.escape(reader, writer, level); } /** *

* Perform a Java level 1 (only basic set) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the Java basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapeJava(char[], int, int, java.io.Writer, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeJavaMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeJava(text, offset, len, writer, JavaEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java level 2 (basic set and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027) and * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeJava(char[], int, int, java.io.Writer, JavaEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link JavaEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeJava(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeJava(text, offset, len, writer, JavaEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.java.JavaEscapeLevel} argument value. *

*

* All other char[]-based escapeJava*(...) methods call this one with preconfigured * level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.java.JavaEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeJava(final char[] text, final int offset, final int len, final Writer writer, final JavaEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } JavaEscapeUtil.escape(text, offset, len, writer, level); } /** *

* Perform a Java unescape operation on a String input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java unescape of SECs, u-based and octal escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeJava(final String text) { if (text == null) { return null; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed return text; } return JavaEscapeUtil.unescape(text); } /** *

* Perform a Java unescape operation on a String input, writing results * to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java unescape of SECs, u-based and octal escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeJava(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (text == null) { return; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed writer.write(text); return; } JavaEscapeUtil.unescape(new InternalStringReader(text), writer); } /** *

* Perform a Java unescape operation on a Reader input, writing results * to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java unescape of SECs, u-based and octal escapes. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeJava(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } JavaEscapeUtil.unescape(reader, writer); } /** *

* Perform a Java unescape operation on a char[] input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java unescape of SECs, u-based and octal escapes. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeJava(final char[] text, final int offset, final int len, final Writer writer) throws IOException{ if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } JavaEscapeUtil.unescape(text, offset, len, writer); } private JavaEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/java/JavaEscapeLevel.java000066400000000000000000000120261311410233600304460ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.java; /** *

* Levels defined for Java escape/unescape operations: *

* *
    *
  • Level 1: Escape only the basic escape set. Note the result of a level-1 escape * operation might still contain non-ASCII characters if they existed in input, and therefore you * will still need to correctly manage your input/output character encoding settings. Such * basic set consists of: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C). Note \' is not really needed in * String literals (only in Character literals), so it won't be used until escape level 3. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • Level 2: Escape the basic escape set (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.java.JavaEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum JavaEscapeLevel { /** * Level 1 escape: escape only the basic escape set: Single Escape Chars plus non-displayable control chars. */ LEVEL_1_BASIC_ESCAPE_SET(1), /** * Level 2 escape: escape the basic escape set plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static JavaEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_BASIC_ESCAPE_SET; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } JavaEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/java/JavaEscapeUtil.java000066400000000000000000001320361311410233600303200ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.java; import java.io.CharArrayWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class JavaEscapeUtil { /* * JAVA ESCAPE/UNESCAPE OPERATIONS * ------------------------------- * * See: http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html * http://arity23.blogspot.com.es/2013/04/secrets-of-scala-lexer-1-uuuuunicode.html * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - SINGLE ESCAPE CHARACTERS (SECs): * U+0008 -> %b * U+0009 -> %t * U+000A -> %n * U+000C -> %f * U+000D -> %r * U+0022 -> %" * U+0027 -> %' [ NOT USED IN ESCAPE OF STRINGS IF LEVEL < 3 ] * U+005C -> %% * - UNICODE ESCAPE [UHEXA] * Characters <= U+FFFF: %u???? * Characters > U+FFFF : %u????%u???? (surrogate character pair) * - OCTAL ESCAPE: %377 [NOT USED IN ESCAPE - Use is not recommended by the JLS, exists for C compatibility] * * * ------------------------ * * NOTE: The way Unicode Escapes work in Java is different to other languages like e.g. JavaScript. In Java, * these UHEXA escapes are processed by the compiler itself, and therefore resolved before any other * type of escapes. Besides, UHEXA escapes can appear anywhere in the code, not only String literals. * This means that, while in JavaScript 'a\u005Cna' would be displayed as 'a\na', in Java "a\u005Cna" * would in fact be displayed in two lines: 'a'+LF+'a'. * Going even further, this is perfectly valid Java code: * * final String hello = \u0022Hello, World!\u0022; * * Also, Java allows to write any number of 'u' characters in this type of escapes, like \uu00E1 or even * \uuuuuuuuu00E1. This is so in order to enable legacy compatibility with older code-processing tools * that didn't support Unicode processing at all, which would fail when finding an Unicode escape * like \u00E1, but not \uu00E1 (because they would consider backslash+'u' as the escape). * So yes, this is valid Java code too: * * final String hello = \uuuuuuuu0022Hello, World!\u0022; * * In order to correctly unescape Java UHEXA escapes like "a\u005Cna", Unbescape will perform a two-pass * process so that all unicode escapes are processed in the first pass, and then the single escape * characters and octal escapes in the second pass. * * ------------------------ * * NOTE: Unbescape does not define a 'type' for Java escaping (just a level) because, given what's explained * above about Unicode Escapes, there is not the possibility to choose whether we want to escape, for * example, '\t' (U+0009) as a SEC ('\t') or as a Unicode Escape ('\u0009'). Given Unicode Escapes are * processed by the compiler, using it instead of the SEC would really insert a tab character inside our * source code, which is not equivalent to the '\t' syntax (and might be actually invalid). * * ------------------------ * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; private static final char ESCAPE_UHEXA_PREFIX2 = 'u'; private static final char[] ESCAPE_UHEXA_PREFIX = "\\u".toCharArray(); /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); /* * Structures for holding the Single Escape Characters */ private static int SEC_CHARS_LEN = '\\' + 1; // 0x5C + 1 = 0x5D private static char SEC_CHARS_NO_SEC = '*'; private static char[] SEC_CHARS; /* * Structured for holding the 'escape level' assigned to chars (not codepoints) up to ESCAPE_LEVELS_LEN. * - The last position of the ESCAPE_LEVELS array will be used for determining the level of all * codepoints >= (ESCAPE_LEVELS_LEN - 1) */ private static final char ESCAPE_LEVELS_LEN = 0x9f + 2; // Last relevant char to be indexed is 0x9f private static final byte[] ESCAPE_LEVELS; static { /* * Initialize Single Escape Characters */ SEC_CHARS = new char[SEC_CHARS_LEN]; Arrays.fill(SEC_CHARS,SEC_CHARS_NO_SEC); SEC_CHARS[0x08] = 'b'; SEC_CHARS[0x09] = 't'; SEC_CHARS[0x0A] = 'n'; SEC_CHARS[0x0C] = 'f'; SEC_CHARS[0x0D] = 'r'; SEC_CHARS[0x22] = '"'; // Escaping the apostrophe is only required in character literals, but we are escaping // string literals, so we don't really need this escape if level < 3 SEC_CHARS[0x27] = '\''; SEC_CHARS[0x5C] = '\\'; /* * Initialization of escape levels. * Defined levels : * * - Level 1 : Basic escape set * - Level 2 : Basic escape set plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters * */ ESCAPE_LEVELS = new byte[ESCAPE_LEVELS_LEN]; /* * Everything is level 3 unless contrary indication. */ Arrays.fill(ESCAPE_LEVELS, (byte)3); /* * Everything non-ASCII is level 2 unless contrary indication. */ for (char c = 0x80; c < ESCAPE_LEVELS_LEN; c++) { ESCAPE_LEVELS[c] = 2; } /* * Alphanumeric characters are level 4. */ for (char c = 'A'; c <= 'Z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = '0'; c <= '9'; c++) { ESCAPE_LEVELS[c] = 4; } /* * Simple Escape Character will be level 1 (always escaped) */ ESCAPE_LEVELS[0x08] = 1; ESCAPE_LEVELS[0x09] = 1; ESCAPE_LEVELS[0x0A] = 1; ESCAPE_LEVELS[0x0C] = 1; ESCAPE_LEVELS[0x0D] = 1; ESCAPE_LEVELS[0x22] = 1; // Escaping the apostrophe is only required in character literals, but we are escaping // string literals, so we don't really need this escape if level < 3 ESCAPE_LEVELS[0x27] = 3; ESCAPE_LEVELS[0x5C] = 1; /* * Java defines one ranges of non-displayable, control characters: U+0000 to U+001F. * Additionally, the U+007F to U+009F range is also escaped (which is allowed). */ for (char c = 0x00; c <= 0x1F; c++) { ESCAPE_LEVELS[c] = 1; } for (char c = 0x7F; c <= 0x9F; c++) { ESCAPE_LEVELS[c] = 1; } } private JavaEscapeUtil() { super(); } static char[] toUHexa(final int codepoint) { final char[] result = new char[4]; result[3] = HEXA_CHARS_UPPER[codepoint % 0x10]; result[2] = HEXA_CHARS_UPPER[(codepoint >>> 4) % 0x10]; result[1] = HEXA_CHARS_UPPER[(codepoint >>> 8) % 0x10]; result[0] = HEXA_CHARS_UPPER[(codepoint >>> 12) % 0x10]; return result; } /* * Perform an escape operation, based on String, according to the specified level. */ static String escape(final String text, final JavaEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char strBuilder.append(ESCAPE_PREFIX); strBuilder.append(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[0])); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[1])); continue; } strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and writing the result * to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape(final Reader reader, final Writer writer, final JavaEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); int c1, c2; // c0: last char, c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c1 = c2; c2 = reader.read(); } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } } /* * Perform an escape operation, based on char[], according to the specified level. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final JavaEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } /* * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need * to create substrings of the text being unescaped to feed such method. * - No need to check all chars are within the radix limits - reference parsing code will already have done so. */ static int parseIntFromReference(final String text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text.charAt(i); int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static boolean isOctalEscape(final String text, final int start, final int end) { if (start >= end) { return false; } final char c1 = text.charAt(start); if (c1 < '0' || c1 > '7') { return false; } if (start + 1 >= end) { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } final char c2 = text.charAt(start + 1); if (c2 < '0' || c2 > '7') { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } if (start + 2 >= end) { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } final char c3 = text.charAt(start + 2); if (c3 < '0' || c3 > '7') { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } return (c1 != '0' || c2 != '0' || c3 != '0'); // Check it's not U+0000 (escaped) + '00' } static boolean isOctalEscape(final char[] text, final int start, final int end) { if (start >= end) { return false; } final char c1 = text[start]; if (c1 < '0' || c1 > '7') { return false; } if (start + 1 >= end) { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } final char c2 = text[start + 1]; if (c2 < '0' || c2 > '7') { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } if (start + 2 >= end) { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } final char c3 = text[start + 2]; if (c3 < '0' || c3 > '7') { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } return (c1 != '0' || c2 != '0' || c3 != '0'); // Check it's not U+0000 (escaped) + '00' } /* * Perform the first step unescape operation based on String. */ static String unicodeUnescape(final String text) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text.charAt(i + 1); if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; // First, discard any additional 'u' characters, which are allowed while (f < max) { final char cf = text.charAt(f); if (cf != ESCAPE_UHEXA_PREFIX2) { break; } f++; } int s = f; // Parse the hexadecimal digits while (f < (s + 4) && f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - s) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding Java parser fail. i++; continue; } codepoint = parseIntFromReference(text, s, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // Other escape sequences will not be processed in this unescape step. i++; continue; } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Determine whether we will need unicode unescape or not, so that we avoid creating a writer object * if it is not needed. */ static boolean requiresUnicodeUnescape(final char[] text, final int offset, final int len) { if (text == null) { return false; } final int max = (offset + len); for (int i = offset; i < max; i++) { final char c = text[i]; if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } if (c == ESCAPE_PREFIX) { final char c1 = text[i + 1]; if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape return true; } } } return false; } /* * Perform the first step unescape operation based on char[]. * * NOTE: We should only be calling this if we already executed requiresUnicodeEscape and it returned true! */ static void unicodeUnescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text[i + 1]; if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; // First, discard any additional 'u' characters, which are allowed while (f < max) { final char cf = text[f]; if (cf != ESCAPE_UHEXA_PREFIX2) { break; } f++; } int s = f; // Parse the hexadecimal digits while (f < (s + 4) && f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - s) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding Java parser fail. i++; continue; } codepoint = parseIntFromReference(text, s, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // Other escape sequences will not be processed in this unescape step. i++; continue; } } /* * At this point we know for sure we will need some kind of unescape, so we * can copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char) codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } /* * Perform an unescape operation based on String. */ static String unescape(final String text) { if (text == null) { return null; } // Will be exactly the same object if no unicode escape was needed final String unicodeEscapedText = unicodeUnescape(text); StringBuilder strBuilder = null; final int offset = 0; final int max = unicodeEscapedText.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = unicodeEscapedText.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = unicodeEscapedText.charAt(i + 1); switch (c1) { case '0': if (!isOctalEscape(unicodeEscapedText,i + 1,max)) { codepoint = 0x00; referenceOffset = i + 1; }; break; case 'b': codepoint = 0x08; referenceOffset = i + 1; break; case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '"': codepoint = 0x22; referenceOffset = i + 1; break; case '\'': codepoint = 0x27; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 >= '0' && c1 <= '7') { // This can be a octal escape, we need at least 1 more char, and up to 3 more. int f = i + 2; while (f < (i + 4) && f < max) { // We need only a max of two more chars final char cf = unicodeEscapedText.charAt(f); if (!(cf >= '0' && cf <= '7')) { break; } f++; } codepoint = parseIntFromReference(unicodeEscapedText, i + 1, f, 8); if (codepoint > 0xFF) { // Maximum octal escape char is FF. Ignore the last digit codepoint = parseIntFromReference(unicodeEscapedText, i + 1, f - 1, 8); referenceOffset = f - 2; } else { referenceOffset = f - 1; } // Don't continue here, just let the unescape code below do its job } else { // Other escape sequences are not allowed by Java. So we leave it as is // and expect the corresponding Java parser to fail. i++; continue; } } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(unicodeEscapedText, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return unicodeEscapedText; } if (max - readOffset > 0) { strBuilder.append(unicodeEscapedText, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } /* * Unescape in Java is a bit different because two different escape systems might have been applied one on * top of the other: Octal escapes (\041) are supported at runtime, whereas unicode escapes (\u00E1) are * applied at parse time. So it is technically possible to have an unicode-escaped octal escape. That means * one output char would be represented in input by 4 * 6 = 24 chars, corresponding to the 6 chars of each * of the unicode-escapes for each of the max-4 chars of the octal escape. * * This means that we will have to use a buffer and that, each time we fill the buffer, we will have to * check that at least the last 8 characters are not a '\', which will mean we can be sure that we are not * interrupting any escape sequence. That number (8) is so because that is the largest amount of non-\ chars * that can happen being involved in an escape sequence, combining both escape methods: "\u005C777" */ char[] buffer = new char[20]; int read = reader.read(buffer, 0, buffer.length); if (read < 0) { return; } int bufferSize = read; while (bufferSize > 0 || read >= 0) { int nonEscCounter = 0; int n = bufferSize; while (nonEscCounter < 8 && n-- != 0) { if (buffer[n] == '\\') { nonEscCounter = 0; continue; } nonEscCounter++; } if (nonEscCounter < 8 && read >= 0) { // not found an 8-char non-escape sequence in the whole buffer, will need to read more buffer if (bufferSize == buffer.length) { // Actually, there is no room for reading more, so let's grow the buffer final char[] newBuffer = new char[buffer.length + (buffer.length / 2)]; System.arraycopy(buffer, 0, newBuffer, 0, buffer.length); buffer = newBuffer; } read = reader.read(buffer, bufferSize, (buffer.length - bufferSize)); if (read >= 0) { bufferSize += read; } continue; } n = (n < 0? bufferSize : n + nonEscCounter); // Once we have defined a 'safe' buffer, just call the char[]-based method unescape(buffer, 0, n, writer); System.arraycopy(buffer, n, buffer, 0, (bufferSize - n)); bufferSize -= n; read = reader.read(buffer, bufferSize, (buffer.length - bufferSize)); if (read >= 0) { bufferSize += read; } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } char[] unicodeEscapedText = text; int unicodeEscapedOffset = offset; int unicodeEscapedLen = len; if (requiresUnicodeUnescape(text, offset, len)) { final CharArrayWriter charArrayWriter = new CharArrayWriter(len + 2); unicodeUnescape(text, offset, len, charArrayWriter); unicodeEscapedText = charArrayWriter.toCharArray(); unicodeEscapedOffset = 0; unicodeEscapedLen = unicodeEscapedText.length; } final int max = (unicodeEscapedOffset + unicodeEscapedLen); int readOffset = unicodeEscapedOffset; int referenceOffset = unicodeEscapedOffset; for (int i = unicodeEscapedOffset; i < max; i++) { final char c = unicodeEscapedText[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = unicodeEscapedText[i + 1]; switch (c1) { case '0': if (!isOctalEscape(unicodeEscapedText,i + 1,max)) { codepoint = 0x00; referenceOffset = i + 1; }; break; case 'b': codepoint = 0x08; referenceOffset = i + 1; break; case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '"': codepoint = 0x22; referenceOffset = i + 1; break; case '\'': codepoint = 0x27; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 >= '0' && c1 <= '7') { // This can be a octal escape, we need at least 1 more char, and up to 3 more. int f = i + 2; while (f < (i + 4) && f < max) { // We need only a max of two more chars final char cf = unicodeEscapedText[f]; if (!(cf >= '0' && cf <= '7')) { break; } f++; } codepoint = parseIntFromReference(unicodeEscapedText, i + 1, f, 8); if (codepoint > 0xFF) { // Maximum octal escape char is FF. Ignore the last digit codepoint = parseIntFromReference(unicodeEscapedText, i + 1, f - 1, 8); referenceOffset = f - 2; } else { referenceOffset = f - 1; } // Don't continue here, just let the unescape code below do its job } else { // Other escape sequences are not allowed by Java. So we leave it as is // and expect the corresponding Java parser to fail. i++; continue; } } } /* * At this point we know for sure we will need some kind of unescape, so we * can copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(unicodeEscapedText, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(unicodeEscapedText, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/javascript/000077500000000000000000000000001311410233600260355ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/javascript/JavaScriptEscape.java000066400000000000000000001474461311410233600321070ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.javascript; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing JavaScript escape/unescape operations. *

* * Configuration of escape/unescape operations * *

* Escape operations can be (optionally) configured by means of: *

*
    *
  • Level, which defines how deep the escape operation must be (what * chars are to be considered eligible for escaping, depending on the specific * needs of the scenario). Its values are defined by the {@link org.unbescape.javascript.JavaScriptEscapeLevel} * enum.
  • *
  • Type, which defines whether escaping should be performed by means of SECs * (Single Escape Characters like \n) or additionally by means of x-based or u-based * hexadecimal escapes (\xE1 or \u00E1). * Its values are defined by the {@link org.unbescape.javascript.JavaScriptEscapeType} enum.
  • *
*

* Unescape operations need no configuration parameters. Unescape operations * will always perform complete unescape of SECs (\n), x-based (\xE1) * and u-based (\u00E1) hexadecimal escapes, and even octal escapes (\057, which * are deprecated since ECMAScript v5 and therefore not used for escaping). *

* * Features * *

* Specific features of the JavaScript escape/unescape operations performed by means of this class: *

*
    *
  • The JavaScript basic escape set is supported. This basic set consists of: *
      *
    • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
    • *
    *
  • *
  • X-based hexadecimal escapes (a.k.a. hexadecimal escapes) are supported both in escape * and unescape operations: \xE1.
  • *
  • U-based hexadecimal escapes (a.k.a. unicode escapes) are supported both in escape * and unescape operations: \u00E1.
  • *
  • Octal escapes are supported, though only in unescape operations: \071. These are not supported * in escape operations because octal escapes were deprecated in version 5 of the ECMAScript * specification.
  • *
  • Support for the whole Unicode character set: \u0000 to \u10FFFF, including * characters not representable by only one char in Java (>\uFFFF).
  • *
* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
SEC
*
Single Escape Character: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F) (optional, only in </). *
*
XHEXA escapes
*
Also called x-based hexadecimal escapes or simply hexadecimal escapes: * compact representation of unicode codepoints up to U+00FF, with \x * followed by exactly two hexadecimal figures: \xE1. XHEXA is many times used * instead of UHEXA (when possible) in order to obtain shorter escaped strings.
*
UHEXA escapes
*
Also called u-based hexadecimal escapes or simply unicode escapes: * complete representation of unicode codepoints up to U+FFFF, with \u * followed by exactly four hexadecimal figures: \u00E1. Unicode codepoints > * U+FFFF can be represented in JavaScript by mean of two UHEXA escapes (a * surrogate pair).
*
Octal escapes
*
Octal representation of unicode codepoints up to U+00FF, with \ * followed by up to three octal figures: \071. Though up to three octal figures * are allowed, octal numbers > 377 (0xFF) are not supported. Note * octal escapes have been deprecated as of version 5 of the ECMAScript specification.
*
Unicode Codepoint
*
Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the * first char is a high surrogate (\uD800 to \uDBFF) and the * second is a low surrogate (\uDC00 to \uDFFF).
*
* * References * *

* The following references apply: *

* * * * @author Daniel Fernández * * @since 1.0.0 * */ public final class JavaScriptEscape { /** *

* Perform a JavaScript level 1 (only basic set) escape operation * on a String input. *

*

* Level 1 means this method will only escape the JavaScript basic escape set: *

*
    *
  • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
  • *
*

* This method calls {@link #escapeJavaScript(String, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJavaScriptMinimal(final String text) { return escapeJavaScript(text, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JavaScript level 2 (basic set and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The JavaScript basic escape set: *
      *
    • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to using \xFF Hexadecimal Escapes * if possible (characters <= U+00FF), then default to \uFFFF * Hexadecimal Escapes. This type of escape produces the smallest escaped string possible. *

*

* This method calls {@link #escapeJavaScript(String, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJavaScript(final String text) { return escapeJavaScript(text, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JavaScript escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.javascript.JavaScriptEscapeType} and * {@link org.unbescape.javascript.JavaScriptEscapeLevel} argument values. *

*

* All other String-based escapeJavaScript*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see * {@link org.unbescape.javascript.JavaScriptEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.javascript.JavaScriptEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJavaScript(final String text, final JavaScriptEscapeType type, final JavaScriptEscapeLevel level) { if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return JavaScriptEscapeUtil.escape(text, type, level); } /** *

* Perform a JavaScript level 1 (only basic set) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the JavaScript basic escape set: *

*
    *
  • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
  • *
*

* This method calls {@link #escapeJavaScript(String, Writer, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaScriptMinimal(final String text, final Writer writer) throws IOException { escapeJavaScript(text, writer, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JavaScript level 2 (basic set and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The JavaScript basic escape set: *
      *
    • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to using \xFF Hexadecimal Escapes * if possible (characters <= U+00FF), then default to \uFFFF * Hexadecimal Escapes. This type of escape produces the smallest escaped string possible. *

*

* This method calls {@link #escapeJavaScript(String, Writer, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaScript(final String text, final Writer writer) throws IOException { escapeJavaScript(text, writer, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JavaScript escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.javascript.JavaScriptEscapeType} and * {@link org.unbescape.javascript.JavaScriptEscapeLevel} argument values. *

*

* All other String/Writer-based escapeJavaScript*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link org.unbescape.javascript.JavaScriptEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.javascript.JavaScriptEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaScript(final String text, final Writer writer, final JavaScriptEscapeType type, final JavaScriptEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } JavaScriptEscapeUtil.escape(new InternalStringReader(text), writer, type, level); } /** *

* Perform a JavaScript level 1 (only basic set) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the JavaScript basic escape set: *

*
    *
  • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
  • *
*

* This method calls {@link #escapeJavaScript(Reader, Writer, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaScriptMinimal(final Reader reader, final Writer writer) throws IOException { escapeJavaScript(reader, writer, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JavaScript level 2 (basic set and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The JavaScript basic escape set: *
      *
    • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to using \xFF Hexadecimal Escapes * if possible (characters <= U+00FF), then default to \uFFFF * Hexadecimal Escapes. This type of escape produces the smallest escaped string possible. *

*

* This method calls {@link #escapeJavaScript(Reader, Writer, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaScript(final Reader reader, final Writer writer) throws IOException { escapeJavaScript(reader, writer, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JavaScript escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.javascript.JavaScriptEscapeType} and * {@link org.unbescape.javascript.JavaScriptEscapeLevel} argument values. *

*

* All other Reader/Writer-based escapeJavaScript*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link org.unbescape.javascript.JavaScriptEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.javascript.JavaScriptEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJavaScript(final Reader reader, final Writer writer, final JavaScriptEscapeType type, final JavaScriptEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } JavaScriptEscapeUtil.escape(reader, writer, type, level); } /** *

* Perform a JavaScript level 1 (only basic set) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the JavaScript basic escape set: *

*
    *
  • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
  • *
*

* This method calls * {@link #escapeJavaScript(char[], int, int, java.io.Writer, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeJavaScriptMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeJavaScript(text, offset, len, writer, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JavaScript level 2 (basic set and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The JavaScript basic escape set: *
      *
    • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \v (U+000B), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to using \xFF Hexadecimal Escapes * if possible (characters <= U+00FF), then default to \uFFFF * Hexadecimal Escapes. This type of escape produces the smallest escaped string possible. *

*

* This method calls * {@link #escapeJavaScript(char[], int, int, java.io.Writer, JavaScriptEscapeType, JavaScriptEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.javascript.JavaScriptEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA}
  • *
  • level: * {@link org.unbescape.javascript.JavaScriptEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeJavaScript(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeJavaScript(text, offset, len, writer, JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA, JavaScriptEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JavaScript escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.javascript.JavaScriptEscapeType} and * {@link org.unbescape.javascript.JavaScriptEscapeLevel} argument values. *

*

* All other char[]-based escapeJavaScript*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link org.unbescape.javascript.JavaScriptEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.javascript.JavaScriptEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeJavaScript(final char[] text, final int offset, final int len, final Writer writer, final JavaScriptEscapeType type, final JavaScriptEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } JavaScriptEscapeUtil.escape(text, offset, len, writer, type, level); } /** *

* Perform a JavaScript unescape operation on a String input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JavaScript unescape of SECs, x-based, u-based * and octal escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeJavaScript(final String text) { if (text == null) { return null; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed return text; } return JavaScriptEscapeUtil.unescape(text); } /** *

* Perform a JavaScript unescape operation on a String input, * writing results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JavaScript unescape of SECs, x-based, u-based * and octal escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeJavaScript(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (text == null) { return; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed writer.write(text); return; } JavaScriptEscapeUtil.unescape(new InternalStringReader(text), writer); } /** *

* Perform a JavaScript unescape operation on a Reader input, * writing results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JavaScript unescape of SECs, x-based, u-based * and octal escapes. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeJavaScript(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } JavaScriptEscapeUtil.unescape(reader, writer); } /** *

* Perform a JavaScript unescape operation on a char[] input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JavaScript unescape of SECs, x-based, u-based * and octal escapes. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeJavaScript(final char[] text, final int offset, final int len, final Writer writer) throws IOException{ if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } JavaScriptEscapeUtil.unescape(text, offset, len, writer); } private JavaScriptEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/javascript/JavaScriptEscapeLevel.java000066400000000000000000000141371311410233600330650ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.javascript; /** *

* Levels defined for JavaScript escape/unescape operations: *

* *
    *
  • Level 1: Escape only the basic escape set. Note the result of a level-1 escape * operation might still contain non-ASCII characters if they existed in input, and therefore you * will still need to correctly manage your input/output character encoding settings. Such * basic set consists of: *
      *
    • The Single Escape Characters: * \0 (U+0000), * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \' (U+0027), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. Also, note that \v * (U+000B) is actually included as a Single Escape * Character in the JavaScript (ECMAScript) specification, but will not be used as it * is not supported by Microsoft Internet Explorer versions < 9. *
    • *
    • * The ampersand symbol (&, U+0026), which will be escaped in order to protect from * code injection in XHTML environments (browsers will parse XHTML escape codes inside * literals in <script> tags). Note there is no Single Escape Character * for this symbol, so it will be escaped using the sequence corresponding to the selected * escape type (e.g. \u0026). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0001 to U+001F and * U+007F to U+009F. *
    • *
    *
  • *
  • Level 2: Escape the basic escape set (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.javascript.JavaScriptEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum JavaScriptEscapeLevel { /** * Level 1 escape: escape only the basic escape set: Single Escape Chars plus non-displayable control chars. */ LEVEL_1_BASIC_ESCAPE_SET(1), /** * Level 2 escape: escape the basic escape set plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static JavaScriptEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_BASIC_ESCAPE_SET; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } JavaScriptEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/javascript/JavaScriptEscapeType.java000066400000000000000000000070711311410233600327360ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.javascript; /** *

* Types of escape operations to be performed on JavaScript text: *

* *
    *
  • SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA: Use * Single Escape Chars whenever possible (depending on the specified * {@link org.unbescape.javascript.JavaScriptEscapeLevel}). For escaped characters that do * not have an associated SEC, default to using \xFF Hexadecimal Escapes * if possible (characters <= U+00FF), then default to \uFFFF * Hexadecimal Escapes. This type of escape produces the smallest escaped string * possible.
  • *
  • SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA: Use * Single Escape Chars whenever possible (depending on the specified * {@link org.unbescape.javascript.JavaScriptEscapeLevel}). For escaped characters that do * not have an associated SEC, default to using \uFFFF Hexadecimal Escapes.
  • *
  • XHEXA_DEFAULT_TO_UHEXA: Replace escaped characters with * \xFF Hexadecimal Escapes if possible (characters <= U+00FF), * default to \uFFFF Hexadecimal Escapes.
  • *
  • UHEXA: Replace escaped characters with * \uFFFF Hexadecimal Escapes.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.javascript.JavaScriptEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum JavaScriptEscapeType { /** * Use Single Escape Chars if possible, default to \xFF hexadecimal escapes * if possible (characters <= U+FF), then default to \uFFFF hexadecimal escapes. */ SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA(true, true), /** * Use Single Escape Chars if possible, default to \uFFFF hexadecimal escapes. */ SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA(true, false), /** * Use \xFF hexadecimal escapes if possible (characters <= U+FF), default * to \uFFFF hexadecimal escapes. */ XHEXA_DEFAULT_TO_UHEXA(false, true), /** * Always use \uFFFF hexadecimal escapes. */ UHEXA(false, false); private final boolean useSECs; private final boolean useXHexa; JavaScriptEscapeType(final boolean useSECs, final boolean useXHexa) { this.useSECs = useSECs; this.useXHexa = useXHexa; } boolean getUseSECs() { return this.useSECs; } boolean getUseXHexa() { return this.useXHexa; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/javascript/JavaScriptEscapeUtil.java000066400000000000000000001436661311410233600327450ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.javascript; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class JavaScriptEscapeUtil { /* * JAVASCRIPT ESCAPE/UNESCAPE OPERATIONS * ------------------------------------- * * See: http://www.ecmascript.org/docs.php * http://mathiasbynens.be/notes/javascript-escapes * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - SINGLE ESCAPE CHARACTERS (SECs): * U+0000 -> %0 * U+0008 -> %b * U+0009 -> %t * U+000A -> %n * U+000B -> %v [NOT USED IN ESCAPE - Not supported by Internet Explorer < 9] * U+000C -> %f * U+000D -> %r * U+0022 -> %" * U+0027 -> %' * U+005C -> %% * U+002F -> %/ [ONLY USED WHEN / APPEARS IN TAGS] * - HEXADECIMAL ESCAPE [XHEXA] (only for characters <= U+00FF): %x?? * - UNICODE ESCAPE [UHEXA] (also hexadecimal) * Characters <= U+FFFF: %u???? * Characters > U+FFFF : %u????%u???? (surrogate character pair) * %u{?*} [NOT USED - Possible syntax for ECMAScript 6] * - OCTAL ESCAPE: %377 [NOT USED IN ESCAPE - Deprecated in ECMAScript v5] * - GENERAL ESCAPE: %* -> * ('%a' -> 'a') * (except the [%,%n] sequence, which is not an escape sequence but a line continuation) * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; private static final char ESCAPE_XHEXA_PREFIX2 = 'x'; private static final char ESCAPE_UHEXA_PREFIX2 = 'u'; private static final char[] ESCAPE_XHEXA_PREFIX = "\\x".toCharArray(); private static final char[] ESCAPE_UHEXA_PREFIX = "\\u".toCharArray(); /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); /* * Structures for holding the Single Escape Characters */ private static int SEC_CHARS_LEN = '\\' + 1; // 0x5C + 1 = 0x5D private static char SEC_CHARS_NO_SEC = '*'; private static char[] SEC_CHARS; /* * Structured for holding the 'escape level' assigned to chars (not codepoints) up to ESCAPE_LEVELS_LEN. * - The last position of the ESCAPE_LEVELS array will be used for determining the level of all * codepoints >= (ESCAPE_LEVELS_LEN - 1) */ private static final char ESCAPE_LEVELS_LEN = 0x9f + 2; // Last relevant char to be indexed is 0x9f private static final byte[] ESCAPE_LEVELS; static { /* * Initialize Single Escape Characters */ SEC_CHARS = new char[SEC_CHARS_LEN]; Arrays.fill(SEC_CHARS,SEC_CHARS_NO_SEC); SEC_CHARS[0x00] = '0'; SEC_CHARS[0x08] = 'b'; SEC_CHARS[0x09] = 't'; SEC_CHARS[0x0A] = 'n'; SEC_CHARS[0x0C] = 'f'; SEC_CHARS[0x0D] = 'r'; SEC_CHARS[0x22] = '"'; SEC_CHARS[0x27] = '\''; SEC_CHARS[0x5C] = '\\'; // slash (solidus) character: will only be escaped if in '>> 4) % 0x10]; return result; } static char[] toUHexa(final int codepoint) { final char[] result = new char[4]; result[3] = HEXA_CHARS_UPPER[codepoint % 0x10]; result[2] = HEXA_CHARS_UPPER[(codepoint >>> 4) % 0x10]; result[1] = HEXA_CHARS_UPPER[(codepoint >>> 8) % 0x10]; result[0] = HEXA_CHARS_UPPER[(codepoint >>> 12) % 0x10]; return result; } /* * Perform an escape operation, based on String, according to the specified level and type. */ static String escape(final String text, final JavaScriptEscapeType escapeType, final JavaScriptEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); final boolean useSECs = escapeType.getUseSECs(); final boolean useXHexa = escapeType.getUseXHexa(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Check whether the character is a slash (solidus). In such case, only escape if it * appears after a '<' ('= 3 (non alphanumeric) */ if (codepoint == '/' && level < 3 && (i == 0 || text.charAt(i - 1) != '<')) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. * We also check we are not dealing with U+2028 or U+2029, which the JavaScript spec considers * LineTerminators and therefore should be escaped always. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1] && codepoint != '\u2028' && codepoint != '\u2029') { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs, XHEXA and UHEXA * * ----------------------------------------------------------------------------------------- */ if (useSECs && codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char strBuilder.append(ESCAPE_PREFIX); strBuilder.append(sec); continue; } } /* * No SEC-escape was possible, so we need xhexa/uhexa escape. */ if (useXHexa && codepoint <= 0xFF) { // Codepoint is <= 0xFF, so we can use XHEXA escapes strBuilder.append(ESCAPE_XHEXA_PREFIX); strBuilder.append(toXHexa(codepoint)); continue; } if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[0])); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[1])); continue; } strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final JavaScriptEscapeType escapeType, final JavaScriptEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useSECs = escapeType.getUseSECs(); final boolean useXHexa = escapeType.getUseXHexa(); int c0, c1, c2; // c0: last char, c1: current char, c2: next char c1 = -1; c2 = reader.read(); while (c2 >= 0) { c0 = c1; c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { writer.write(c1); continue; } /* * Check whether the character is a slash (solidus). In such case, only escape if it * appears after a '<' ('= 3 (non alphanumeric) */ if (codepoint == '/' && level < 3 && c0 != '<') { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. * We also check we are not dealing with U+2028 or U+2029, which the JavaScript spec considers * LineTerminators and therefore should be escaped always. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1] && codepoint != '\u2028' && codepoint != '\u2029') { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c0 = c1; c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c0 = c1; c1 = c2; c2 = reader.read(); } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs, XHEXA and UHEXA * * ----------------------------------------------------------------------------------------- */ if (useSECs && codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need xhexa/uhexa escape. */ if (useXHexa && codepoint <= 0xFF) { // Codepoint is <= 0xFF, so we can use XHEXA escapes writer.write(ESCAPE_XHEXA_PREFIX); writer.write(toXHexa(codepoint)); continue; } if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } } /* * Perform an escape operation, based on char[], according to the specified level and type. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final JavaScriptEscapeType escapeType, final JavaScriptEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useSECs = escapeType.getUseSECs(); final boolean useXHexa = escapeType.getUseXHexa(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Check whether the character is a slash (solidus). In such case, only escape if it * appears after a '<' ('= 3 (non alphanumeric) */ if (codepoint == '/' && level < 3 && (i == 0 || text[i - 1] != '<')) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. * We also check we are not dealing with U+2028 or U+2029, which the JavaScript spec considers * LineTerminators and therefore should be escaped always. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1] && codepoint != '\u2028' && codepoint != '\u2029') { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs, XHEXA and UHEXA * * ----------------------------------------------------------------------------------------- */ if (useSECs && codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need xhexa/uhexa escape. */ if (useXHexa && codepoint <= 0xFF) { // Codepoint is <= 0xFF, so we can use XHEXA escapes writer.write(ESCAPE_XHEXA_PREFIX); writer.write(toXHexa(codepoint)); continue; } if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } /* * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need * to create substrings of the text being unescaped to feed such method. * - No need to check all chars are within the radix limits - reference parsing code will already have done so. */ static int parseIntFromReference(final String text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text.charAt(i); int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final int[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = (char) text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static boolean isOctalEscape(final String text, final int start, final int end) { if (start >= end) { return false; } final char c1 = text.charAt(start); if (c1 < '0' || c1 > '7') { return false; } if (start + 1 >= end) { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } final char c2 = text.charAt(start + 1); if (c2 < '0' || c2 > '7') { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } if (start + 2 >= end) { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } final char c3 = text.charAt(start + 2); if (c3 < '0' || c3 > '7') { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } return (c1 != '0' || c2 != '0' || c3 != '0'); // Check it's not U+0000 (escaped) + '00' } static boolean isOctalEscape(final char[] text, final int start, final int end) { if (start >= end) { return false; } final char c1 = text[start]; if (c1 < '0' || c1 > '7') { return false; } if (start + 1 >= end) { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } final char c2 = text[start + 1]; if (c2 < '0' || c2 > '7') { return (c1 != '0'); // It would not be an octal escape, but the U+0000 escape sequence. } if (start + 2 >= end) { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } final char c3 = text[start + 2]; if (c3 < '0' || c3 > '7') { return (c1 != '0' || c2 != '0'); // It would not be an octal escape, but the U+0000 escape sequence + '0'. } return (c1 != '0' || c2 != '0' || c3 != '0'); // Check it's not U+0000 (escaped) + '00' } /* * Perform an unescape operation based on String. */ static String unescape(final String text) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text.charAt(i + 1); switch (c1) { case '0': if (!isOctalEscape(text,i + 1,max)) { codepoint = 0x00; referenceOffset = i + 1; }; break; case 'b': codepoint = 0x08; referenceOffset = i + 1; break; case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'v': codepoint = 0x0B; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '"': codepoint = 0x22; referenceOffset = i + 1; break; case '\'': codepoint = 0x27; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; case '/': codepoint = 0x2F; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 == ESCAPE_XHEXA_PREFIX2) { // This can be a xhexa escape, we need exactly two more characters int f = i + 2; while (f < (i + 4) && f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 2) { // We weren't able to consume the required two hexa chars, leave it as slash+'x', which // is invalid, and let the corresponding JavaScript engine fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; while (f < (i + 6) && f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JavaScript engine fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else if (c1 >= '0' && c1 <= '7') { // This can be a octal escape, we need at least 1 more char, and up to 3 more. int f = i + 2; while (f < (i + 4) && f < max) { // We need only a max of two more chars final char cf = text.charAt(f); if (!(cf >= '0' && cf <= '7')) { break; } f++; } codepoint = parseIntFromReference(text, i + 1, f, 8); if (codepoint > 0xFF) { // Maximum octal escape char is FF. Ignore the last digit codepoint = parseIntFromReference(text, i + 1, f - 1, 8); referenceOffset = f - 2; } else { referenceOffset = f - 1; } // Don't continue here, just let the unescape code below do its job } else if (c1 == '8' || c1 == '9' || c1 == '\n' || c1 == '\r' || c1 == '\u2028' || c1 == '\u2029') { // '8' and '9' are not valid octal escape sequences, and the other four characters // are LineTerminators, which are not allowed as escape sequences. So we leave it as is // and expect the corresponding JavaScript engine to fail (except in the case of slash + '\n', // which is considered a LineContinuator). i++; continue; } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the JavaScript specification (NonEscapeCharacter) codepoint = (int) c1; referenceOffset = i + 1; } } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } int escapei = 0; final char[] escapes = new char[4]; int c1, c2, ce; // c1: current char, c2: next char, ce: current escape char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); escapei = 0; /* * Check the need for an unescape operation at this point */ if (c1 != ESCAPE_PREFIX || c2 < 0) { writer.write(c1); continue; } int codepoint = -1; if (c1 == ESCAPE_PREFIX) { switch (c2) { case 'b': codepoint = 0x08; c1 = c2; c2 = reader.read(); break; case 't': codepoint = 0x09; c1 = c2; c2 = reader.read(); break; case 'n': codepoint = 0x0A; c1 = c2; c2 = reader.read(); break; case 'v': codepoint = 0x0B; c1 = c2; c2 = reader.read(); break; case 'f': codepoint = 0x0C; c1 = c2; c2 = reader.read(); break; case 'r': codepoint = 0x0D; c1 = c2; c2 = reader.read(); break; case '"': codepoint = 0x22; c1 = c2; c2 = reader.read(); break; case '\'': codepoint = 0x27; c1 = c2; c2 = reader.read(); break; case '\\': codepoint = 0x5C; c1 = c2; c2 = reader.read(); break; case '/': codepoint = 0x2F; c1 = c2; c2 = reader.read(); break; } if (codepoint == -1) { if (c2 == ESCAPE_XHEXA_PREFIX2) { // This can be a xhexa escape, we need exactly two more characters escapei = 0; ce = reader.read(); while (ce >= 0 && escapei < 2) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) { break; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei < 2) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JavaScript parser fail. writer.write(c1); writer.write(c2); for (int i = 0; i < escapei; i++) { c1 = c2; c2 = escapes[i]; writer.write(c2); } c1 = c2; c2 = ce; continue; } c1 = escapes[3]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, 2, 16); escapei = 0; // Don't continue here, just let the unescape code below do its job } else if (c2 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters escapei = 0; ce = reader.read(); while (ce >= 0 && escapei < 4) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) { break; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JavaScript parser fail. writer.write(c1); writer.write(c2); for (int i = 0; i < escapei; i++) { c1 = c2; c2 = escapes[i]; writer.write(c2); } c1 = c2; c2 = ce; continue; } c1 = escapes[3]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, 4, 16); escapei = 0; // Don't continue here, just let the unescape code below do its job } else if (c2 >= '0' && c2 <= '7') { // This can be a octal escape, we need at least 1 more char, and up to 3 more. // case '0': if (!isOctalEscape(text,i + 1,max)) { codepoint = 0x00; referenceOffset = i + 1; }; break; escapei = 0; ce = c2; while (ce >= 0 && escapei < 3) { if (!(ce >= '0' && ce <= '7')) { break; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } c1 = escapes[escapei - 1]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, escapei, 8); if (codepoint > 0xFF) { // Maximum octal escape char is FF. Ignore the last digit codepoint = parseIntFromReference(escapes, 0, escapei - 1, 8); System.arraycopy(escapes, escapei - 2, escapes, 0, 1); escapei = 1; } else if (codepoint == 0x0 && escapei > 1) { // In the case of '\000' , we will only consider the first '\0' as it is an escape on its // own, and the rest of the '00' will have to be output. So we save them at the escapes array System.arraycopy(escapes, 1, escapes, 0, escapei - 1); escapei--; } else { escapei = 0; } // Don't continue here, just let the unescape code below do its job } else if (c2 == '8' || c2 == '9' || c2 == '\n' || c2 == '\r' || c2 == '\u2028' || c2 == '\u2029') { // '8' and '9' are not valid octal escape sequences, and the other four characters // are LineTerminators, which are not allowed as escape sequences. So we leave it as is // and expect the corresponding JavaScript engine to fail (except in the case of slash + '\n', // which is considered a LineContinuator). writer.write(c1); writer.write(c2); c1 = c2; c2 = reader.read(); continue; } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the JavaScript specification (NonEscapeCharacter) codepoint = c2; c1 = c2; c2 = reader.read(); escapei = 0; } } } /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } /* * ---------------------------------------- * Cleanup, in case we had a partial match * ---------------------------------------- */ if (escapei > 0) { writer.write(escapes, 0, escapei); escapei = 0; } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text[i + 1]; switch (c1) { case '0': if (!isOctalEscape(text,i + 1,max)) { codepoint = 0x00; referenceOffset = i + 1; }; break; case 'b': codepoint = 0x08; referenceOffset = i + 1; break; case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'v': codepoint = 0x0B; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '"': codepoint = 0x22; referenceOffset = i + 1; break; case '\'': codepoint = 0x27; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; case '/': codepoint = 0x2F; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 == ESCAPE_XHEXA_PREFIX2) { // This can be a xhexa escape, we need exactly two more characters int f = i + 2; while (f < (i + 4) && f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 2) { // We weren't able to consume the required two hexa chars, leave it as slash+'x', which // is invalid, and let the corresponding JavaScript engine fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; while (f < (i + 6) && f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JavaScript engine fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else if (c1 >= '0' && c1 <= '7') { // This can be a octal escape, we need at least 1 more char, and up to 3 more. int f = i + 2; while (f < (i + 4) && f < max) { // We need only a max of two more chars final char cf = text[f]; if (!(cf >= '0' && cf <= '7')) { break; } f++; } codepoint = parseIntFromReference(text, i + 1, f, 8); if (codepoint > 0xFF) { // Maximum octal escape char is FF. Ignore the last digit codepoint = parseIntFromReference(text, i + 1, f - 1, 8); referenceOffset = f - 2; } else { referenceOffset = f - 1; } // Don't continue here, just let the unescape code below do its job } else if (c1 == '8' || c1 == '9' || c1 == '\n' || c1 == '\r' || c1 == '\u2028' || c1 == '\u2029') { // '8' and '9' are not valid octal escape sequences, and the other four characters // are LineTerminators, which are not allowed as escape sequences. So we leave it as is // and expect the corresponding JavaScript engine to fail (except in the case of slash + '\n', // which is considered a LineContinuator). i++; continue; } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the JavaScript specification (NonEscapeCharacter) codepoint = (int) c1; referenceOffset = i + 1; } } } /* * At this point we know for sure we will need some kind of unescape, so we * write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: writer the remaining escaped text and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/json/000077500000000000000000000000001311410233600246405ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/json/JsonEscape.java000066400000000000000000001301261311410233600275400ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.json; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing JSON escape/unescape operations. *

* * Configuration of escape/unescape operations * *

* Escape operations can be (optionally) configured by means of: *

*
    *
  • Level, which defines how deep the escape operation must be (what * chars are to be considered eligible for escaping, depending on the specific * needs of the scenario). Its values are defined by the {@link JsonEscapeLevel} * enum.
  • *
  • Type, which defines whether escaping should be performed by means of SECs * (Single Escape Characters like \n) or additionally by means of u-based * hexadecimal references (\u00E1). * Its values are defined by the {@link JsonEscapeType} enum.
  • *
*

* Unescape operations need no configuration parameters. Unescape operations * will always perform complete unescape of SECs (\n) * and u-based (\u00E1) hexadecimal escapes. *

* * Features * *

* Specific features of the JSON escape/unescape operations performed by means of this class: *

*
    *
  • The JSON basic escape set is supported. This basic set consists of: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
    • *
    *
  • *
  • U-based hexadecimal escapes (a.k.a. unicode escapes) are supported both in escape * and unescape operations: \u00E1.
  • *
  • Support for the whole Unicode character set: \u0000 to \u10FFFF, including * characters not representable by only one char in Java (>\uFFFF).
  • *
* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
SEC
*
Single Escape Character: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F) (optional, only in </). *
*
UHEXA escapes
*
Also called u-based hexadecimal escapes or simply unicode escapes: * complete representation of unicode codepoints up to U+FFFF, with \u * followed by exactly four hexadecimal figures: \u00E1. Unicode codepoints > * U+FFFF can be represented in JSON by mean of two UHEXA escapes (a * surrogate pair).
*
Unicode Codepoint
*
Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the * first char is a high surrogate (\uD800 to \uDBFF) and the * second is a low surrogate (\uDC00 to \uDFFF).
*
* * References * *

* The following references apply: *

* * * * @author Daniel Fernández * * @since 1.0.0 * */ public final class JsonEscape { /** *

* Perform a JSON level 1 (only basic set) escape operation * on a String input. *

*

* Level 1 means this method will only escape the JSON basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
  • *
*

* This method calls {@link #escapeJson(String, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJsonMinimal(final String text) { return escapeJson(text, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JSON level 2 (basic set and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The JSON basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeJson(String, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJson(final String text) { return escapeJson(text, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JSON escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link JsonEscapeType} and * {@link JsonEscapeLevel} argument values. *

*

* All other String-based escapeJson*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see * {@link JsonEscapeType}. * @param level the escape level to be applied, see {@link JsonEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeJson(final String text, final JsonEscapeType type, final JsonEscapeLevel level) { if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return JsonEscapeUtil.escape(text, type, level); } /** *

* Perform a JSON level 1 (only basic set) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the JSON basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
  • *
*

* This method calls {@link #escapeJson(String, Writer, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJsonMinimal(final String text, final Writer writer) throws IOException { escapeJson(text, writer, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JSON level 2 (basic set and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The JSON basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeJson(String, Writer, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJson(final String text, final Writer writer) throws IOException { escapeJson(text, writer, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JSON escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link JsonEscapeType} and * {@link JsonEscapeLevel} argument values. *

*

* All other String/Writer-based escapeJson*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link JsonEscapeType}. * @param level the escape level to be applied, see {@link JsonEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJson(final String text, final Writer writer, final JsonEscapeType type, final JsonEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } JsonEscapeUtil.escape(new InternalStringReader(text), writer, type, level); } /** *

* Perform a JSON level 1 (only basic set) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the JSON basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
  • *
*

* This method calls {@link #escapeJson(Reader, Writer, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJsonMinimal(final Reader reader, final Writer writer) throws IOException { escapeJson(reader, writer, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JSON level 2 (basic set and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The JSON basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapeJson(Reader, Writer, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJson(final Reader reader, final Writer writer) throws IOException { escapeJson(reader, writer, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JSON escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link JsonEscapeType} and * {@link JsonEscapeLevel} argument values. *

*

* All other Reader/Writer-based escapeJson*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link JsonEscapeType}. * @param level the escape level to be applied, see {@link JsonEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeJson(final Reader reader, final Writer writer, final JsonEscapeType type, final JsonEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } JsonEscapeUtil.escape(reader, writer, type, level); } /** *

* Perform a JSON level 1 (only basic set) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the JSON basic escape set: *

*
    *
  • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
  • *
*

* This method calls * {@link #escapeJson(char[], int, int, java.io.Writer, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeJsonMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeJson(text, offset, len, writer, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a JSON level 2 (basic set and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The JSON basic escape set: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls * {@link #escapeJson(char[], int, int, java.io.Writer, JsonEscapeType, JsonEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link JsonEscapeType#SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA}
  • *
  • level: * {@link JsonEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeJson(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeJson(text, offset, len, writer, JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA, JsonEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) JSON escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link JsonEscapeType} and * {@link JsonEscapeLevel} argument values. *

*

* All other char[]-based escapeJson*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see * {@link JsonEscapeType}. * @param level the escape level to be applied, see {@link JsonEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeJson(final char[] text, final int offset, final int len, final Writer writer, final JsonEscapeType type, final JsonEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } JsonEscapeUtil.escape(text, offset, len, writer, type, level); } /** *

* Perform a JSON unescape operation on a String input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JSON unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeJson(final String text) { if (text == null) { return null; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed return text; } return JsonEscapeUtil.unescape(text); } /** *

* Perform a JSON unescape operation on a String input, writing * results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JSON unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeJson(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (text == null) { return; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed writer.write(text); return; } JsonEscapeUtil.unescape(new InternalStringReader(text), writer); } /** *

* Perform a JSON unescape operation on a Reader input, writing * results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JSON unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeJson(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } JsonEscapeUtil.unescape(reader, writer); } /** *

* Perform a JSON unescape operation on a char[] input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete JSON unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeJson(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } JsonEscapeUtil.unescape(text, offset, len, writer); } private JsonEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/json/JsonEscapeLevel.java000066400000000000000000000132761311410233600305360ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.json; /** *

* Levels defined for JSON escape/unescape operations: *

* *
    *
  • Level 1: Escape only the basic escape set. Note the result of a level-1 escape * operation might still contain non-ASCII characters if they existed in input, and therefore you * will still need to correctly manage your input/output character encoding settings. Such * basic set consists of: *
      *
    • The Single Escape Characters: * \b (U+0008), * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \" (U+0022), * \\ (U+005C) and * \/ (U+002F). * Note that \/ is optional, and will only be used when the / * symbol appears after <, as in </. This is to avoid accidentally * closing <script> tags in HTML. *
    • *
    • * The ampersand symbol (&, U+0026), which will be escaped in order to protect from * code injection in XHTML environments (browsers will parse XHTML escape codes inside * literals in <script> tags). Note there is no Single Escape Character * for this symbol, so it will be escaped using the sequence corresponding to the selected * escape type (e.g. \u0026). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F (required * by the JSON spec) and U+007F to U+009F (additional). *
    • *
    *
  • *
  • Level 2: Escape the basic escape set (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link JsonEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum JsonEscapeLevel { /** * Level 1 escape: escape only the basic escape set: Single Escape Chars plus non-displayable control chars. */ LEVEL_1_BASIC_ESCAPE_SET(1), /** * Level 2 escape: escape the basic escape set plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static JsonEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_BASIC_ESCAPE_SET; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } JsonEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/json/JsonEscapeType.java000066400000000000000000000040701311410233600304000ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.json; /** *

* Types of escape operations to be performed on JSON text: *

* *
    *
  • SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA: Use * Single Escape Chars whenever possible (depending on the specified * {@link JsonEscapeLevel}). For escaped characters that do * not have an associated SEC, default to using \uFFFF Hexadecimal Escapes.
  • *
  • UHEXA: Replace escaped characters with * \uFFFF Hexadecimal Escapes.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link JsonEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum JsonEscapeType { /** * Use Single Escape Chars if possible, default to \uFFFF hexadecimal escapes. */ SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA(true), /** * Always use \uFFFF hexadecimal escapes. */ UHEXA(false); private final boolean useSECs; JsonEscapeType(final boolean useSECs) { this.useSECs = useSECs; } boolean getUseSECs() { return this.useSECs; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/json/JsonEscapeUtil.java000066400000000000000000001046511311410233600304020ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.json; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class JsonEscapeUtil { /* * JSON ESCAPE/UNESCAPE OPERATIONS * ------------------------------- * * See: http://www.ietf.org/rfc/rfc4627.txt * http://timelessrepo.com/json-isnt-a-javascript-subset * http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/ * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - SINGLE ESCAPE CHARACTERS (SECs): * U+0008 -> %b * U+0009 -> %t * U+000A -> %n * U+000C -> %f * U+000D -> %r * U+0022 -> %" * U+005C -> %% * U+002F -> %/ [ONLY USED WHEN / APPEARS IN TAGS] * - UNICODE ESCAPE [UHEXA] * Characters <= U+FFFF: %u???? * Characters > U+FFFF : %u????%u???? (surrogate character pair) * %u{?*} [NOT USED - Possible syntax for ECMAScript 6] * * * ------------------------ * NOTE: JSON is NOT equivalent to the JavaScript Object Literal notation. JSON is just a format for * data interchange that happens to have a syntax that is ALMOST A SUBSET of the JavaScript Object * Literal notation (U+2028 and U+2029 LineTerminators are allowed in JSON but not in JavaScript). * ------------------------ * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; private static final char ESCAPE_UHEXA_PREFIX2 = 'u'; private static final char[] ESCAPE_UHEXA_PREFIX = "\\u".toCharArray(); /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); /* * Structures for holding the Single Escape Characters */ private static int SEC_CHARS_LEN = '\\' + 1; // 0x5C + 1 = 0x5D private static char SEC_CHARS_NO_SEC = '*'; private static char[] SEC_CHARS; /* * Structured for holding the 'escape level' assigned to chars (not codepoints) up to ESCAPE_LEVELS_LEN. * - The last position of the ESCAPE_LEVELS array will be used for determining the level of all * codepoints >= (ESCAPE_LEVELS_LEN - 1) */ private static final char ESCAPE_LEVELS_LEN = 0x9f + 2; // Last relevant char to be indexed is 0x9f private static final byte[] ESCAPE_LEVELS; static { /* * Initialize Single Escape Characters */ SEC_CHARS = new char[SEC_CHARS_LEN]; Arrays.fill(SEC_CHARS,SEC_CHARS_NO_SEC); SEC_CHARS[0x08] = 'b'; SEC_CHARS[0x09] = 't'; SEC_CHARS[0x0A] = 'n'; SEC_CHARS[0x0C] = 'f'; SEC_CHARS[0x0D] = 'r'; SEC_CHARS[0x22] = '"'; SEC_CHARS[0x5C] = '\\'; // slash (solidus) character: will only be escaped if in '>> 4) % 0x10]; result[1] = HEXA_CHARS_UPPER[(codepoint >>> 8) % 0x10]; result[0] = HEXA_CHARS_UPPER[(codepoint >>> 12) % 0x10]; return result; } /* * Perform an escape operation, based on String, according to the specified level and type. */ static String escape(final String text, final JsonEscapeType escapeType, final JsonEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); final boolean useSECs = escapeType.getUseSECs(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Check whether the character is a slash (solidus). In such case, only escape if it * appears after a '<' ('= 3 (non alphanumeric) */ if (codepoint == '/' && level < 3 && (i == offset || text.charAt(i - 1) != '<')) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (useSECs && codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char strBuilder.append(ESCAPE_PREFIX); strBuilder.append(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[0])); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[1])); continue; } strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final JsonEscapeType escapeType, final JsonEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useSECs = escapeType.getUseSECs(); int c0, c1, c2; // c0: last char, c1: current char, c2: next char c1 = -1; c2 = reader.read(); while (c2 >= 0) { c0 = c1; c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { writer.write(c1); continue; } /* * Check whether the character is a slash (solidus). In such case, only escape if it * appears after a '<' ('= 3 (non alphanumeric) */ if (codepoint == '/' && level < 3 && c0 != '<') { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c0 = c1; c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c0 = c1; c1 = c2; c2 = reader.read(); } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (useSECs && codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } } /* * Perform an escape operation, based on char[], according to the specified level and type. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final JsonEscapeType escapeType, final JsonEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useSECs = escapeType.getUseSECs(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Check whether the character is a slash (solidus). In such case, only escape if it * appears after a '<' ('= 3 (non alphanumeric) */ if (codepoint == '/' && level < 3 && (i == offset || text[i - 1] != '<')) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (useSECs && codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } /* * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need * to create substrings of the text being unescaped to feed such method. * - No need to check all chars are within the radix limits - reference parsing code will already have done so. */ static int parseIntFromReference(final String text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text.charAt(i); int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final int[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = (char) text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } /* * Perform an unescape operation based on String. */ static String unescape(final String text) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text.charAt(i + 1); switch (c1) { case 'b': codepoint = 0x08; referenceOffset = i + 1; break; case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '"': codepoint = 0x22; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; case '/': codepoint = 0x2F; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; while (f < (i + 6) && f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JSON parser fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // Other escape sequences are not allowed by JSON. So we leave it as is // and expect the corresponding JSON parser to fail. i++; continue; } } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } final int[] escapes = new int[4]; int c1, c2; // c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); /* * Check the need for an unescape operation at this point */ if (c1 != ESCAPE_PREFIX || c2 < 0) { writer.write(c1); continue; } int codepoint = -1; if (c1 == ESCAPE_PREFIX) { switch (c2) { case 'b': codepoint = 0x08; c1 = c2; c2 = reader.read(); break; case 't': codepoint = 0x09; c1 = c2; c2 = reader.read(); break; case 'n': codepoint = 0x0A; c1 = c2; c2 = reader.read(); break; case 'f': codepoint = 0x0C; c1 = c2; c2 = reader.read(); break; case 'r': codepoint = 0x0D; c1 = c2; c2 = reader.read(); break; case '"': codepoint = 0x22; c1 = c2; c2 = reader.read(); break; case '\\': codepoint = 0x5C; c1 = c2; c2 = reader.read(); break; case '/': codepoint = 0x2F; c1 = c2; c2 = reader.read(); break; } if (codepoint == -1) { if (c2 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int escapei = 0; int ce = reader.read(); while (ce >= 0 && escapei < 4) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) { break; } escapes[escapei] = ce; ce = reader.read(); escapei++; } if (escapei < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JSON parser fail. writer.write(c1); writer.write(c2); for (int i = 0; i < escapei; i++) { c1 = c2; c2 = escapes[i]; writer.write(c2); } c1 = c2; c2 = ce; continue; } c1 = escapes[3]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, 4, 16); // Don't continue here, just let the unescape code below do its job } else { // Other escape sequences are not allowed by JSON. So we leave it as is // and expect the corresponding JSON parser to fail. writer.write(c1); writer.write(c2); c1 = c2; c2 = reader.read(); continue; } } } /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text[i + 1]; switch (c1) { case 'b': codepoint = 0x08; referenceOffset = i + 1; break; case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '"': codepoint = 0x22; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; case '/': codepoint = 0x2F; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; while (f < (i + 6) && f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JSON parser fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // Other escape sequences are not allowed by JSON. So we leave it as is // and expect the corresponding JSON parser to fail. i++; continue; } } } /* * At this point we know for sure we will need some kind of unescape, so we * write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: writer the remaining escaped text and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/properties/000077500000000000000000000000001311410233600260635ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/properties/PropertiesEscape.java000066400000000000000000001771621311410233600322210ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.properties; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing Java Properties (.properties files) escape/unescape operations. *

* *

* This class supports both escaping of properties keys and * properties values. *

* * Configuration of escape/unescape operations * *

* Escape operations can be (optionally) configured by means of: *

*
    *
  • Level, which defines how deep the escape operation must be (what * chars are to be considered eligible for escaping, depending on the specific * needs of the scenario). Its values are defined by the {@link org.unbescape.properties.PropertiesKeyEscapeLevel} * and {@link org.unbescape.properties.PropertiesValueEscapeLevel} enums.
  • *
*

* Unescape operations need no configuration parameters. Unescape operations * will always perform complete Java Properties unescape of SECs and u-based escapes. *

* * Features * *

* Specific features of the .properties key/value escape/unescape operations performed by means of this class: *

*
    *
  • The Java Properties basic escape set is supported. This basic set consists of: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). * Besides, * (U+0020), * \: (U+003A) and * \= (U+003D) will be used in Properties keys (not values). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • U-based hexadecimal escapes (a.k.a. unicode escapes) are supported both in escape * and unescape operations: \u00E1.
  • *
  • Full set of escape syntax rules supported, both for .properties keys and * .properties values.
  • *
  • Support for the whole Unicode character set: \u0000 to \u10FFFF, including * characters not representable by only one char in Java (>\uFFFF).
  • *
* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
SEC
*
Single Escape Character: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). * Besides, * (U+0020), * \: (U+003A) and * \= (U+003D) will be used in Properties keys (not values). *
*
UHEXA escapes
*
Also called u-based hexadecimal escapes or simply unicode escapes: * complete representation of unicode codepoints up to U+FFFF, with \u * followed by exactly four hexadecimal figures: \u00E1. Unicode codepoints > * U+FFFF can be represented in Java by mean of two UHEXA escapes (a * surrogate pair).
*
Unicode Codepoint
*
Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the * first char is a high surrogate (\uD800 to \uDBFF) and the * second is a low surrogate (\uDC00 to \uDFFF).
*
* * References * *

* The following references apply: *

* * * * @author Daniel Fernández * * @since 1.0.0 * */ public final class PropertiesEscape { /** *

* Perform a Java Properties Value level 1 (only basic set) escape operation * on a String input. *

*

* Level 1 means this method will only escape the Java Properties basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesValue(String, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapePropertiesValueMinimal(final String text) { return escapePropertiesValue(text, PropertiesValueEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Value level 2 (basic set and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesValue(String, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapePropertiesValue(final String text) { return escapePropertiesValue(text, PropertiesValueEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Value escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesValueEscapeLevel} argument value. *

*

* All other String-based escapePropertiesValue*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesValueEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapePropertiesValue(final String text, final PropertiesValueEscapeLevel level) { if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return PropertiesValueEscapeUtil.escape(text, level); } /** *

* Perform a Java Properties Value level 1 (only basic set) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the Java Properties basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesValue(String, Writer, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapePropertiesValueMinimal(final String text, final Writer writer) throws IOException { escapePropertiesValue(text, writer, PropertiesValueEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Value level 2 (basic set and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesValue(String, Writer, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapePropertiesValue(final String text, final Writer writer) throws IOException { escapePropertiesValue(text, writer, PropertiesValueEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Value escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesValueEscapeLevel} argument value. *

*

* All other String/Writer-based escapePropertiesValue*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesValueEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapePropertiesValue(final String text, final Writer writer, final PropertiesValueEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } PropertiesValueEscapeUtil.escape(new InternalStringReader(text), writer, level); } /** *

* Perform a Java Properties Value level 1 (only basic set) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the Java Properties basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesValue(Reader, Writer, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapePropertiesValueMinimal(final Reader reader, final Writer writer) throws IOException { escapePropertiesValue(reader, writer, PropertiesValueEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Value level 2 (basic set and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesValue(Reader, Writer, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapePropertiesValue(final Reader reader, final Writer writer) throws IOException { escapePropertiesValue(reader, writer, PropertiesValueEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Value escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesValueEscapeLevel} argument value. *

*

* All other Reader/Writer-based escapePropertiesValue*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesValueEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapePropertiesValue(final Reader reader, final Writer writer, final PropertiesValueEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } PropertiesValueEscapeUtil.escape(reader, writer, level); } /** *

* Perform a Java Properties Value level 1 (only basic set) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the Java Properties basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesValue(char[], int, int, java.io.Writer, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesValueMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapePropertiesValue(text, offset, len, writer, PropertiesValueEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Value level 2 (basic set and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesValue(char[], int, int, java.io.Writer, PropertiesValueEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesValueEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesValue(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapePropertiesValue(text, offset, len, writer, PropertiesValueEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Value escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesValueEscapeLevel} argument value. *

*

* All other String-based escapePropertiesValue*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesValueEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesValue(final char[] text, final int offset, final int len, final Writer writer, final PropertiesValueEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } PropertiesValueEscapeUtil.escape(text, offset, len, writer, level); } /** *

* Perform a Java Properties Key level 1 (only basic set) escape operation * on a String input. *

*

* Level 1 means this method will only escape the Java Properties Key basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesKey(String, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapePropertiesKeyMinimal(final String text) { return escapePropertiesKey(text, PropertiesKeyEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Key level 2 (basic set and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties Key basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesKey(String, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapePropertiesKey(final String text) { return escapePropertiesKey(text, PropertiesKeyEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Key escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesKeyEscapeLevel} argument value. *

*

* All other String-based escapePropertiesKey*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesKeyEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapePropertiesKey(final String text, final PropertiesKeyEscapeLevel level) { if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return PropertiesKeyEscapeUtil.escape(text, level); } /** *

* Perform a Java Properties Key level 1 (only basic set) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the Java Properties Key basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesKey(String, Writer, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKeyMinimal(final String text, final Writer writer) throws IOException { escapePropertiesKey(text, writer, PropertiesKeyEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Key level 2 (basic set and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties Key basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesKey(String, Writer, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKey(final String text, final Writer writer) throws IOException { escapePropertiesKey(text, writer, PropertiesKeyEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Key escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesKeyEscapeLevel} argument value. *

*

* All other String/Writer-based escapePropertiesKey*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesKeyEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKey(final String text, final Writer writer, final PropertiesKeyEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } PropertiesKeyEscapeUtil.escape(new InternalStringReader(text), writer, level); } /** *

* Perform a Java Properties Key level 1 (only basic set) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the Java Properties Key basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesKey(Reader, Writer, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKeyMinimal(final Reader reader, final Writer writer) throws IOException { escapePropertiesKey(reader, writer, PropertiesKeyEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Key level 2 (basic set and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties Key basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesKey(Reader, Writer, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKey(final Reader reader, final Writer writer) throws IOException { escapePropertiesKey(reader, writer, PropertiesKeyEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Key escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesKeyEscapeLevel} argument value. *

*

* All other Reader/Writer-based escapePropertiesKey*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesKeyEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKey(final Reader reader, final Writer writer, final PropertiesKeyEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } PropertiesKeyEscapeUtil.escape(reader, writer, level); } /** *

* Perform a Java Properties Key level 1 (only basic set) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the Java Properties Key basic escape set: *

*
    *
  • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
  • *
  • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
  • *
*

* This method calls {@link #escapePropertiesKey(char[], int, int, java.io.Writer, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_1_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKeyMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapePropertiesKey(text, offset, len, writer, PropertiesKeyEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET); } /** *

* Perform a Java Properties Key level 2 (basic set and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The Java Properties Key basic escape set: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D) and * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by using the Single Escape Chars whenever possible. For escaped * characters that do not have an associated SEC, default to \uFFFF * Hexadecimal Escapes. *

*

* This method calls {@link #escapePropertiesKey(char[], int, int, java.io.Writer, PropertiesKeyEscapeLevel)} * with the following preconfigured values: *

*
    *
  • level: * {@link PropertiesKeyEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKey(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapePropertiesKey(text, offset, len, writer, PropertiesKeyEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET); } /** *

* Perform a (configurable) Java Properties Key escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.properties.PropertiesKeyEscapeLevel} argument value. *

*

* All other String-based escapePropertiesKey*(...) methods call this one with * preconfigured level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.properties.PropertiesKeyEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapePropertiesKey(final char[] text, final int offset, final int len, final Writer writer, final PropertiesKeyEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } PropertiesKeyEscapeUtil.escape(text, offset, len, writer, level); } /** *

* Perform a Java Properties (key or value) unescape operation on a String input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java Properties unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeProperties(final String text) { if (text == null) { return null; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed return text; } return PropertiesUnescapeUtil.unescape(text); } /** *

* Perform a Java Properties (key or value) unescape operation on a String input, * writing results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java Properties unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeProperties(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (text == null) { return; } if (text.indexOf('\\') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed writer.write(text); return; } PropertiesUnescapeUtil.unescape(new InternalStringReader(text), writer); } /** *

* Perform a Java Properties (key or value) unescape operation on a Reader input, * writing results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java Properties unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeProperties(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } PropertiesUnescapeUtil.unescape(reader, writer); } /** *

* Perform a Java Properties (key or value) unescape operation on a char[] input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete Java Properties unescape of SECs and u-based escapes. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeProperties(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } PropertiesUnescapeUtil.unescape(text, offset, len, writer); } private PropertiesEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } PropertiesKeyEscapeLevel.java000066400000000000000000000116601311410233600335710ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/properties/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.properties; /** *

* Levels defined for Java Properties escape/unescape operations: *

* *
    *
  • Level 1: Escape only the basic escape set. Note the result of a level-1 escape * operation might still contain non-ASCII characters if they existed in input, and therefore you * will still need to correctly manage your input/output character encoding settings. Such * basic set consists of: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * (U+0020), * \: (U+003A), * \= (U+003D), * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • Level 2: Escape the basic escape set (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.properties.PropertiesEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum PropertiesKeyEscapeLevel { /** * Level 1 escape: escape only the basic escape set: Single Escape Chars plus non-displayable control chars. */ LEVEL_1_BASIC_ESCAPE_SET(1), /** * Level 2 escape: escape the basic escape set plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static PropertiesKeyEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_BASIC_ESCAPE_SET; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } PropertiesKeyEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } PropertiesKeyEscapeUtil.java000066400000000000000000000442451311410233600334440ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/properties/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.properties; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class PropertiesKeyEscapeUtil { /* * JAVA PROPERTIES KEY ESCAPE OPERATIONS * ------------------------------------- * * See: http://en.wikipedia.org/wiki/.properties * http://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader- * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - SINGLE ESCAPE CHARACTERS (SECs): * U+0009 -> %t * U+000A -> %n * U+000C -> %f * U+000D -> %r * U+0020 -> % [ ONLY REQUIRED IN KEYS ] * U+003A -> %: [ ONLY REQUIRED IN KEYS ] * U+003D -> %= [ ONLY REQUIRED IN KEYS ] * U+005C -> %% * - UNICODE ESCAPE [UHEXA] * Characters <= U+FFFF: %u???? * Characters > U+FFFF : %u????%u???? (surrogate character pair) * * * ------------------------ * * NOTE: In Java .properties files, there is a difference between how keys and values must be escaped. Keys * require the escape of ':', '=' and whitespaces (U+0020), because the first of these characters (or a * combination of them) found in a .properties line is considered part of the key-value separator. * * ------------------------ * * NOTE: The way unicode (UHEXA) escapes are treated in Java literals and Java properties is different: whereas * in Java literals these are processed by the compiler and therefore processed before any other kind of * escapes, in Java properties unicode escapes are just like any other type of escape, i.e. more similar * to other languages like JavaScript. * * ------------------------ * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; private static final char[] ESCAPE_UHEXA_PREFIX = "\\u".toCharArray(); /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); /* * Structures for holding the Single Escape Characters */ private static int SEC_CHARS_LEN = '\\' + 1; // 0x5C + 1 = 0x5D private static char SEC_CHARS_NO_SEC = '*'; private static char[] SEC_CHARS; /* * Structured for holding the 'escape level' assigned to chars (not codepoints) up to ESCAPE_LEVELS_LEN. * - The last position of the ESCAPE_LEVELS array will be used for determining the level of all * codepoints >= (ESCAPE_LEVELS_LEN - 1) */ private static final char ESCAPE_LEVELS_LEN = 0x9f + 2; // Last relevant char to be indexed is 0x9f private static final byte[] ESCAPE_LEVELS; static { /* * Initialize Single Escape Characters */ SEC_CHARS = new char[SEC_CHARS_LEN]; Arrays.fill(SEC_CHARS,SEC_CHARS_NO_SEC); SEC_CHARS[0x09] = 't'; SEC_CHARS[0x0A] = 'n'; SEC_CHARS[0x0C] = 'f'; SEC_CHARS[0x0D] = 'r'; SEC_CHARS[0x20] = ' '; SEC_CHARS[0x3A] = ':'; SEC_CHARS[0x3B] = '='; SEC_CHARS[0x5C] = '\\'; /* * Initialization of escape levels. * Defined levels : * * - Level 1 : Basic escape set * - Level 2 : Basic escape set plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters * */ ESCAPE_LEVELS = new byte[ESCAPE_LEVELS_LEN]; /* * Everything is level 3 unless contrary indication. */ Arrays.fill(ESCAPE_LEVELS, (byte)3); /* * Everything non-ASCII is level 2 unless contrary indication. */ for (char c = 0x80; c < ESCAPE_LEVELS_LEN; c++) { ESCAPE_LEVELS[c] = 2; } /* * Alphanumeric characters are level 4. */ for (char c = 'A'; c <= 'Z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = '0'; c <= '9'; c++) { ESCAPE_LEVELS[c] = 4; } /* * Simple Escape Character will be level 1 (always escaped) */ ESCAPE_LEVELS[0x09] = 1; ESCAPE_LEVELS[0x0A] = 1; ESCAPE_LEVELS[0x0C] = 1; ESCAPE_LEVELS[0x0D] = 1; ESCAPE_LEVELS[0x20] = 1; ESCAPE_LEVELS[0x3A] = 1; ESCAPE_LEVELS[0x3B] = 1; ESCAPE_LEVELS[0x5C] = 1; /* * Java defines one ranges of non-displayable, control characters: U+0000 to U+001F. * Additionally, the U+007F to U+009F range is also escaped (which is allowed). */ for (char c = 0x00; c <= 0x1F; c++) { ESCAPE_LEVELS[c] = 1; } for (char c = 0x7F; c <= 0x9F; c++) { ESCAPE_LEVELS[c] = 1; } } private PropertiesKeyEscapeUtil() { super(); } static char[] toUHexa(final int codepoint) { final char[] result = new char[4]; result[3] = HEXA_CHARS_UPPER[codepoint % 0x10]; result[2] = HEXA_CHARS_UPPER[(codepoint >>> 4) % 0x10]; result[1] = HEXA_CHARS_UPPER[(codepoint >>> 8) % 0x10]; result[0] = HEXA_CHARS_UPPER[(codepoint >>> 12) % 0x10]; return result; } /* * Perform an escape operation, based on String, according to the specified level. */ static String escape(final String text, final PropertiesKeyEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char strBuilder.append(ESCAPE_PREFIX); strBuilder.append(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[0])); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[1])); continue; } strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final PropertiesKeyEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); int c1, c2; // c0: last char, c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c1 = c2; c2 = reader.read(); } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } } /* * Perform an escape operation, based on char[], according to the specified level. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final PropertiesKeyEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/properties/PropertiesUnescapeUtil.java000066400000000000000000000416731311410233600334170ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.properties; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class PropertiesUnescapeUtil { /* * JAVA PROPERTIES UNESCAPE OPERATIONS * ----------------------------------- * * See: http://en.wikipedia.org/wiki/.properties * http://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader- * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - SINGLE ESCAPE CHARACTERS (SECs): * U+0009 -> %t * U+000A -> %n * U+000C -> %f * U+000D -> %r * U+0020 -> % [ ONLY REQUIRED IN KEYS ] * U+003A -> %: [ ONLY REQUIRED IN KEYS ] * U+003D -> %= [ ONLY REQUIRED IN KEYS ] * U+005C -> %% * - UNICODE ESCAPE [UHEXA] * Characters <= U+FFFF: %u???? * Characters > U+FFFF : %u????%u???? (surrogate character pair) * * * ------------------------ * * NOTE: In Java .properties files, there is a difference between how keys and values must be escaped. Keys * require the escape of ':', '=' and whitespaces (U+0020), because the first of these characters (or a * combination of them) found in a .properties line is considered part of the key-value separator. * * ------------------------ * * NOTE: The way unicode (UHEXA) escapes are treated in Java literals and Java properties is different: whereas * in Java literals these are processed by the compiler and therefore processed before any other kind of * escapes, in Java properties unicode escapes are just like any other type of escape, i.e. more similar * to other languages like JavaScript. * * ------------------------ * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; private static final char ESCAPE_UHEXA_PREFIX2 = 'u'; /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); private PropertiesUnescapeUtil() { super(); } /* * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need * to create substrings of the text being unescaped to feed such method. * - No need to check all chars are within the radix limits - reference parsing code will already have done so. */ static int parseIntFromReference(final String text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text.charAt(i); int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } /* * Perform an unescape operation based on String. */ static String unescape(final String text) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text.charAt(i + 1); switch (c1) { case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; while (f < (i + 6) && f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding Java Properties parser fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the Java Properties specification codepoint = (int) c1; referenceOffset = i + 1; } } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a String. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer) throws IOException { if (reader == null) { return; } final char[] escapes = new char[4]; int c1, c2, ce; // c1: current char, c2: next char, ce: current escape char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); /* * Check the need for an unescape operation at this point */ if (c1 != ESCAPE_PREFIX || c2 < 0) { writer.write(c1); continue; } int codepoint = -1; if (c1 == ESCAPE_PREFIX) { switch (c2) { case 't': codepoint = 0x09; c1 = c2; c2 = reader.read(); break; case 'n': codepoint = 0x0A; c1 = c2; c2 = reader.read(); break; case 'f': codepoint = 0x0C; c1 = c2; c2 = reader.read(); break; case 'r': codepoint = 0x0D; c1 = c2; c2 = reader.read(); break; case '\\': codepoint = 0x5C; c1 = c2; c2 = reader.read(); break; } if (codepoint == -1) { if (c2 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int escapei = 0; ce = reader.read(); while (ce >= 0 && escapei < 4) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) { break; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding JavaScript parser fail. writer.write(c1); writer.write(c2); for (int i = 0; i < escapei; i++) { c1 = c2; c2 = escapes[i]; writer.write(c2); } c1 = c2; c2 = ce; continue; } c1 = escapes[3]; c2 = ce; codepoint = parseIntFromReference(escapes, 0, 4, 16); // Don't continue here, just let the unescape code below do its job } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the Java Properties specification codepoint = (int) c2; c1 = c2; c2 = reader.read(); } } } /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX || (i + 1) >= max) { continue; } int codepoint = -1; if (c == ESCAPE_PREFIX) { final char c1 = text[i + 1]; switch (c1) { case 't': codepoint = 0x09; referenceOffset = i + 1; break; case 'n': codepoint = 0x0A; referenceOffset = i + 1; break; case 'f': codepoint = 0x0C; referenceOffset = i + 1; break; case 'r': codepoint = 0x0D; referenceOffset = i + 1; break; case '\\': codepoint = 0x5C; referenceOffset = i + 1; break; } if (codepoint == -1) { if (c1 == ESCAPE_UHEXA_PREFIX2) { // This can be a uhexa escape, we need exactly four more characters int f = i + 2; while (f < (i + 6) && f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 2)) < 4) { // We weren't able to consume the required four hexa chars, leave it as slash+'u', which // is invalid, and let the corresponding Java Properties parser fail. i++; continue; } codepoint = parseIntFromReference(text, i + 2, f, 16); // Fast-forward to the first char after the parsed codepoint referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // We weren't able to consume any valid escape chars, just consider it a normal char, // which is allowed by the Java Properties specification codepoint = (int) c1; referenceOffset = i + 1; } } } /* * At this point we know for sure we will need some kind of unescape, so we * write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: writer the remaining escaped text and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } } PropertiesValueEscapeLevel.java000066400000000000000000000114251311410233600341140ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/properties/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.properties; /** *

* Levels defined for Java Properties escape/unescape operations: *

* *
    *
  • Level 1: Escape only the basic escape set. Note the result of a level-1 escape * operation might still contain non-ASCII characters if they existed in input, and therefore you * will still need to correctly manage your input/output character encoding settings. Such * basic set consists of: *
      *
    • The Single Escape Characters: * \t (U+0009), * \n (U+000A), * \f (U+000C), * \r (U+000D), * \\ (U+005C). *
    • *
    • * Two ranges of non-displayable, control characters (some of which are already part of the * single escape characters list): U+0000 to U+001F * and U+007F to U+009F. *
    • *
    *
  • *
  • Level 2: Escape the basic escape set (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings.
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.properties.PropertiesEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum PropertiesValueEscapeLevel { /** * Level 1 escape: escape only the basic escape set: Single Escape Chars plus non-displayable control chars. */ LEVEL_1_BASIC_ESCAPE_SET(1), /** * Level 2 escape: escape the basic escape set plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static PropertiesValueEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_BASIC_ESCAPE_SET; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } PropertiesValueEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } PropertiesValueEscapeUtil.java000066400000000000000000000437521311410233600337720ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/properties/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.properties; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class PropertiesValueEscapeUtil { /* * JAVA PROPERTIES VALUE ESCAPE OPERATIONS * --------------------------------------- * * See: http://en.wikipedia.org/wiki/.properties * http://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.Reader- * * (Note that, in the following examples, and in order to avoid escape problems during the compilation * of this class, the backslash symbol is replaced by '%') * * - SINGLE ESCAPE CHARACTERS (SECs): * U+0009 -> %t * U+000A -> %n * U+000C -> %f * U+000D -> %r * U+0020 -> % [ ONLY REQUIRED IN KEYS ] * U+003A -> %: [ ONLY REQUIRED IN KEYS ] * U+003D -> %= [ ONLY REQUIRED IN KEYS ] * U+005C -> %% * - UNICODE ESCAPE [UHEXA] * Characters <= U+FFFF: %u???? * Characters > U+FFFF : %u????%u???? (surrogate character pair) * * * ------------------------ * * NOTE: In Java .properties files, there is a difference between how keys and values must be escaped. Keys * require the escape of ':', '=' and whitespaces (U+0020), because the first of these characters (or a * combination of them) found in a .properties line is considered part of the key-value separator. * * ------------------------ * * NOTE: The way unicode (UHEXA) escapes are treated in Java literals and Java properties is different: whereas * in Java literals these are processed by the compiler and therefore processed before any other kind of * escapes, in Java properties unicode escapes are just like any other type of escape, i.e. more similar * to other languages like JavaScript. * * ------------------------ * */ /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '\\'; private static final char[] ESCAPE_UHEXA_PREFIX = "\\u".toCharArray(); /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); /* * Structures for holding the Single Escape Characters */ private static int SEC_CHARS_LEN = '\\' + 1; // 0x5C + 1 = 0x5D private static char SEC_CHARS_NO_SEC = '*'; private static char[] SEC_CHARS; /* * Structured for holding the 'escape level' assigned to chars (not codepoints) up to ESCAPE_LEVELS_LEN. * - The last position of the ESCAPE_LEVELS array will be used for determining the level of all * codepoints >= (ESCAPE_LEVELS_LEN - 1) */ private static final char ESCAPE_LEVELS_LEN = 0x9f + 2; // Last relevant char to be indexed is 0x9f private static final byte[] ESCAPE_LEVELS; static { /* * Initialize Single Escape Characters */ SEC_CHARS = new char[SEC_CHARS_LEN]; Arrays.fill(SEC_CHARS,SEC_CHARS_NO_SEC); SEC_CHARS[0x09] = 't'; SEC_CHARS[0x0A] = 'n'; SEC_CHARS[0x0C] = 'f'; SEC_CHARS[0x0D] = 'r'; SEC_CHARS[0x5C] = '\\'; /* * Initialization of escape levels. * Defined levels : * * - Level 1 : Basic escape set * - Level 2 : Basic escape set plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters * */ ESCAPE_LEVELS = new byte[ESCAPE_LEVELS_LEN]; /* * Everything is level 3 unless contrary indication. */ Arrays.fill(ESCAPE_LEVELS, (byte)3); /* * Everything non-ASCII is level 2 unless contrary indication. */ for (char c = 0x80; c < ESCAPE_LEVELS_LEN; c++) { ESCAPE_LEVELS[c] = 2; } /* * Alphanumeric characters are level 4. */ for (char c = 'A'; c <= 'Z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { ESCAPE_LEVELS[c] = 4; } for (char c = '0'; c <= '9'; c++) { ESCAPE_LEVELS[c] = 4; } /* * Simple Escape Character will be level 1 (always escaped) */ ESCAPE_LEVELS[0x09] = 1; ESCAPE_LEVELS[0x0A] = 1; ESCAPE_LEVELS[0x0C] = 1; ESCAPE_LEVELS[0x0D] = 1; ESCAPE_LEVELS[0x5C] = 1; /* * Java defines one ranges of non-displayable, control characters: U+0000 to U+001F. * Additionally, the U+007F to U+009F range is also escaped (which is allowed). */ for (char c = 0x00; c <= 0x1F; c++) { ESCAPE_LEVELS[c] = 1; } for (char c = 0x7F; c <= 0x9F; c++) { ESCAPE_LEVELS[c] = 1; } } private PropertiesValueEscapeUtil() { super(); } static char[] toUHexa(final int codepoint) { final char[] result = new char[4]; result[3] = HEXA_CHARS_UPPER[codepoint % 0x10]; result[2] = HEXA_CHARS_UPPER[(codepoint >>> 4) % 0x10]; result[1] = HEXA_CHARS_UPPER[(codepoint >>> 8) % 0x10]; result[0] = HEXA_CHARS_UPPER[(codepoint >>> 12) % 0x10]; return result; } /* * Perform an escape operation, based on String, according to the specified level. */ static String escape(final String text, final PropertiesValueEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char strBuilder.append(ESCAPE_PREFIX); strBuilder.append(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[0])); strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepointChars[1])); continue; } strBuilder.append(ESCAPE_UHEXA_PREFIX); strBuilder.append(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and writing the result * to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final PropertiesValueEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); int c1, c2; // c0: last char, c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c1 = c2; c2 = reader.read(); } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } } /* * Perform an escape operation, based on char[], according to the specified level. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final PropertiesValueEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[codepoint]) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (ESCAPE_LEVELS_LEN - 2) && level < ESCAPE_LEVELS[ESCAPE_LEVELS_LEN - 1]) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of SECs and UHEXA * * ----------------------------------------------------------------------------------------- */ if (codepoint < SEC_CHARS_LEN) { // We will try to use a SEC final char sec = SEC_CHARS[codepoint]; if (sec != SEC_CHARS_NO_SEC) { // SEC found! just write it and go for the next char writer.write(ESCAPE_PREFIX); writer.write(sec); continue; } } /* * No SEC-escape was possible, so we need uhexa escape. */ if (Character.charCount(codepoint) > 1) { final char[] codepointChars = Character.toChars(codepoint); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[0])); writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepointChars[1])); continue; } writer.write(ESCAPE_UHEXA_PREFIX); writer.write(toUHexa(codepoint)); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/uri/000077500000000000000000000000001311410233600244665ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/uri/UriEscape.java000066400000000000000000003372361311410233600272270ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.uri; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing URI escape/unescape operations. *

* * Features * *

* Specific features of the URI escape/unescape operations performed by means of this class: *

*
    *
  • Support for percent-encoding-based escape operations (RFC3986) for diverse parts of an URI: *
      *
    • Paths: Part of the URI path, might include several path levels/segments: * /admin/users/list?x=1users/list
    • *
    • Path Segments: Part of the URI path, can include only one path level * (/ chars will be escaped): /admin/users/list?x=1users
    • *
    • Query Parameters: Names and values of the URI query parameters: * /admin/users/list?x=1x (name), 1 (value)
    • *
    • URI Fragment Identifiers: client-side part of URIs, specified after #: * /admin/users/list?x=1#something#something
    • *
    *
  • *
  • Support for both percent-encoding and + based unescaping of whitespace in query * parameters.
  • *
* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
Percent encoding
*
The percent-encoding technique for escaping consists of transforming the character that needs to be * escaped into a sequence of bytes using a previously specified encoding (UTF-8 by default), and * then wrinting each byte as %HH, being HH its hexadecimal value (of the byte). *
*
* * References * *

* The following references apply: *

* * * * @author Daniel Fernández * * @since 1.1.0 * */ public final class UriEscape { /** * The default encoding for URI escaping/unescaping: UTF-8. */ public static final String DEFAULT_ENCODING = "UTF-8"; /** *

* Perform am URI path escape operation * on a String input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriPath(final String text) { return escapeUriPath(text, DEFAULT_ENCODING); } /** *

* Perform am URI path escape operation * on a String input. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param encoding the encoding to be used for unescaping. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriPath(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.escape(text, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment escape operation * on a String input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriPathSegment(final String text) { return escapeUriPathSegment(text, DEFAULT_ENCODING); } /** *

* Perform am URI path segment escape operation * on a String input. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param encoding the encoding to be used for escaping. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriPathSegment(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.escape(text, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) escape operation * on a String input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriQueryParam(final String text) { return escapeUriQueryParam(text, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) escape operation * on a String input. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param encoding the encoding to be used for escaping. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriQueryParam(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.escape(text, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier escape operation * on a String input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriFragmentId(final String text) { return escapeUriFragmentId(text, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier escape operation * on a String input. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param encoding the encoding to be used for escaping. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeUriFragmentId(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.escape(text, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } /** *

* Perform am URI path escape operation * on a String input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPath(final String text, final Writer writer) throws IOException { escapeUriPath(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path escape operation * on a String input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPath(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment escape operation * on a String input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPathSegment(final String text, final Writer writer) throws IOException { escapeUriPathSegment(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path segment escape operation * on a String input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPathSegment(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) escape operation * on a String input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriQueryParam(final String text, final Writer writer) throws IOException { escapeUriQueryParam(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) escape operation * on a String input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriQueryParam(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier escape operation * on a String input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriFragmentId(final String text, final Writer writer) throws IOException { escapeUriFragmentId(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier escape operation * on a String input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriFragmentId(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } /** *

* Perform am URI path escape operation * on a Reader input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPath(final Reader reader, final Writer writer) throws IOException { escapeUriPath(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path escape operation * on a Reader input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPath(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(reader, writer, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment escape operation * on a Reader input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPathSegment(final Reader reader, final Writer writer) throws IOException { escapeUriPathSegment(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path segment escape operation * on a Reader input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriPathSegment(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(reader, writer, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) escape operation * on a Reader input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriQueryParam(final Reader reader, final Writer writer) throws IOException { escapeUriQueryParam(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) escape operation * on a Reader input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriQueryParam(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(reader, writer, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier escape operation * on a Reader input using UTF-8 as encoding, * writing results to a Writer. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriFragmentId(final Reader reader, final Writer writer) throws IOException { escapeUriFragmentId(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier escape operation * on a Reader input, writing results to a Writer. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeUriFragmentId(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.escape(reader, writer, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } /** *

* Perform am URI path escape operation * on a char[] input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeUriPath(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeUriPath(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path escape operation * on a char[] input. *

*

* The following are the only allowed chars in an URI path (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • /
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs */ public static void escapeUriPath(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.escape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment escape operation * on a char[] input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeUriPathSegment(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeUriPathSegment(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path segment escape operation * on a char[] input. *

*

* The following are the only allowed chars in an URI path segment (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs */ public static void escapeUriPathSegment(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.escape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) escape operation * on a char[] input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeUriQueryParam(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeUriQueryParam(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) escape operation * on a char[] input. *

*

* The following are the only allowed chars in an URI query parameter (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ ' ( ) * , ;
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs */ public static void escapeUriQueryParam(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.escape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier escape operation * on a char[] input using UTF-8 as encoding. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the UTF-8 and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeUriFragmentId(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeUriFragmentId(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier escape operation * on a char[] input. *

*

* The following are the only allowed chars in an URI fragment identifier (will not be escaped): *

*
    *
  • A-Z a-z 0-9
  • *
  • - . _ ~
  • *
  • ! $ & ' ( ) * + , ; =
  • *
  • : @
  • *
  • / ?
  • *
*

* All other chars will be escaped by converting them to the sequence of bytes that * represents them in the specified encoding and then representing each byte * in %HH syntax, being HH the hexadecimal representation of the byte. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for escaping. * @throws IOException if an input/output exception occurs */ public static void escapeUriFragmentId(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.escape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } /** *

* Perform am URI path unescape operation * on a String input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriPath(final String text) { return unescapeUriPath(text, DEFAULT_ENCODING); } /** *

* Perform am URI path unescape operation * on a String input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use the specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param encoding the encoding to be used for unescaping. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriPath(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.unescape(text, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment unescape operation * on a String input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriPathSegment(final String text) { return unescapeUriPathSegment(text, DEFAULT_ENCODING); } /** *

* Perform am URI path segment unescape operation * on a String input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param encoding the encoding to be used for unescaping. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriPathSegment(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.unescape(text, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a String input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriQueryParam(final String text) { return unescapeUriQueryParam(text, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a String input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param encoding the encoding to be used for unescaping. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriQueryParam(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.unescape(text, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier unescape operation * on a String input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriFragmentId(final String text) { return unescapeUriFragmentId(text, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier unescape operation * on a String input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param encoding the encoding to be used for unescaping. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeUriFragmentId(final String text, final String encoding) { if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } return UriEscapeUtil.unescape(text, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } /** *

* Perform am URI path unescape operation * on a String input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPath(final String text, final Writer writer) throws IOException { unescapeUriPath(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path unescape operation * on a String input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use the specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPath(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment unescape operation * on a String input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPathSegment(final String text, final Writer writer) throws IOException { unescapeUriPathSegment(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path segment unescape operation * on a String input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPathSegment(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a String input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriQueryParam(final String text, final Writer writer) throws IOException { unescapeUriQueryParam(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a String input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriQueryParam(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier unescape operation * on a String input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriFragmentId(final String text, final Writer writer) throws IOException { unescapeUriFragmentId(text, writer, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier unescape operation * on a String input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriFragmentId(final String text, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(new InternalStringReader(text), writer, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } /** *

* Perform am URI path unescape operation * on a Reader input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPath(final Reader reader, final Writer writer) throws IOException { unescapeUriPath(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path unescape operation * on a Reader input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use the specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPath(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(reader, writer, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment unescape operation * on a Reader input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPathSegment(final Reader reader, final Writer writer) throws IOException { unescapeUriPathSegment(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path segment unescape operation * on a Reader input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriPathSegment(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(reader, writer, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a Reader input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriQueryParam(final Reader reader, final Writer writer) throws IOException { unescapeUriQueryParam(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a Reader input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriQueryParam(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(reader, writer, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier unescape operation * on a Reader input using UTF-8 as encoding, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriFragmentId(final Reader reader, final Writer writer) throws IOException { unescapeUriFragmentId(reader, writer, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier unescape operation * on a Reader input, writing results to a Writer. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeUriFragmentId(final Reader reader, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } UriEscapeUtil.unescape(reader, writer, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } /** *

* Perform am URI path unescape operation * on a char[] input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeUriPath(final char[] text, final int offset, final int len, final Writer writer) throws IOException { unescapeUriPath(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path unescape operation * on a char[] input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs */ public static void unescapeUriPath(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.unescape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.PATH, encoding); } /** *

* Perform am URI path segment unescape operation * on a char[] input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeUriPathSegment(final char[] text, final int offset, final int len, final Writer writer) throws IOException { unescapeUriPathSegment(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI path segment unescape operation * on a char[] input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs */ public static void unescapeUriPathSegment(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.unescape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.PATH_SEGMENT, encoding); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a char[] input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeUriQueryParam(final char[] text, final int offset, final int len, final Writer writer) throws IOException { unescapeUriQueryParam(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI query parameter (name or value) unescape operation * on a char[] input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs */ public static void unescapeUriQueryParam(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.unescape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.QUERY_PARAM, encoding); } /** *

* Perform am URI fragment identifier unescape operation * on a char[] input using UTF-8 as encoding. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use UTF-8 in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeUriFragmentId(final char[] text, final int offset, final int len, final Writer writer) throws IOException { unescapeUriFragmentId(text, offset, len, writer, DEFAULT_ENCODING); } /** *

* Perform am URI fragment identifier unescape operation * on a char[] input. *

*

* This method will unescape every percent-encoded (%HH) sequences present in input, * even for those characters that do not need to be percent-encoded in this context (unreserved characters * can be percent-encoded even if/when this is not required, though it is not generally considered a * good practice). *

*

* This method will use specified encoding in order to determine the characters specified in the * percent-encoded byte sequences. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @param encoding the encoding to be used for unescaping. * @throws IOException if an input/output exception occurs */ public static void unescapeUriFragmentId(final char[] text, final int offset, final int len, final Writer writer, final String encoding) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (encoding == null) { throw new IllegalArgumentException("Argument 'encoding' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } UriEscapeUtil.unescape(text, offset, len, writer, UriEscapeUtil.UriEscapeType.FRAGMENT_ID, encoding); } private UriEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/uri/UriEscapeUtil.java000066400000000000000000000633441311410233600300610ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.uri; import java.io.IOException; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.io.Writer; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.1.0 * */ final class UriEscapeUtil { /* * URI ESCAPE/UNESCAPE OPERATIONS * ------------------------------ * * See: http://www.ietf.org/rfc/rfc3986.txt * http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4 * * Different parts of an URI allow different characters, and therefore require different sets of * characters to be escaped (see RFC3986 for a list of reserved characters for each URI part) - but * the escaping method is always the same: convert the character to the bytes representing it in a * specific encoding (UTF-8 by default) and then percent-encode these bytes with two hexadecimal * digits, like '%0A'. * * - PATH: Part of the URI path, might include several path levels/segments: * '/admin/users/list?x=1' -> 'users/list' * - PATH SEGMENT: Part of the URI path, can include only one path level ('/' chars will be escaped): * '/admin/users/list?x=1' -> 'users' * - QUERY PARAMETER: Names and values of the URI query parameters: * '/admin/users/list?x=1' -> 'x' (name), '1' (value) * - URI FRAGMENT ID: URI fragments: * '/admin/users/list?x=1#something' -> '#something' * */ static enum UriEscapeType { PATH { @Override public boolean isAllowed(final int c) { return isPchar(c) || '/' == c; } }, PATH_SEGMENT { @Override public boolean isAllowed(final int c) { return isPchar(c); } }, QUERY_PARAM { @Override public boolean isAllowed(final int c) { // We specify these symbols separately because some of them are considered 'pchar' if ('=' == c || '&' == c || '+' == c || '#' == c) { return false; } return isPchar(c) || '/' == c || '?' == c; } @Override public boolean canPlusEscapeWhitespace() { return true; } }, FRAGMENT_ID { @Override public boolean isAllowed(final int c) { return isPchar(c) || '/' == c || '?' == c; } }; public abstract boolean isAllowed(final int c); /* * Determines whether whitespace could appear escaped as '+' in the * current escape type. * * This allows unescaping of application/x-www-form-urlencoded * URI query parameters, which specify '+' as escape character * for whitespace instead of the '%20' specified by RFC3986. * * http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4 * http://www.ietf.org/rfc/rfc3986.txt */ public boolean canPlusEscapeWhitespace() { // Will only be true for QUERY_PARAM return false; } /* * Specification of 'pchar' according to RFC3986 * http://www.ietf.org/rfc/rfc3986.txt */ private static boolean isPchar(final int c) { return isUnreserved(c) || isSubDelim(c) || ':' == c || '@' == c; } /* * Specification of 'unreserved' according to RFC3986 * http://www.ietf.org/rfc/rfc3986.txt */ private static boolean isUnreserved(final int c) { return isAlpha(c) || isDigit(c) || '-' == c || '.' == c || '_' == c || '~' == c; } /* * Specification of 'reserved' according to RFC3986 * http://www.ietf.org/rfc/rfc3986.txt */ private static boolean isReserved(final int c) { return isGenDelim(c) || isSubDelim(c); } /* * Specification of 'sub-delims' according to RFC3986 * http://www.ietf.org/rfc/rfc3986.txt */ private static boolean isSubDelim(final int c) { return '!' == c || '$' == c || '&' == c || '\'' == c || '(' == c || ')' == c || '*' == c || '+' == c || ',' == c || ';' == c || '=' == c; } /* * Specification of 'gen-delims' according to RFC3986 * http://www.ietf.org/rfc/rfc3986.txt */ private static boolean isGenDelim(final int c) { return ':' == c || '/' == c || '?' == c || '#' == c || '[' == c || ']' == c || '@' == c; } /* * Character.isLetter() is not used here because it would include * non a-to-z letters. */ static boolean isAlpha(final int c) { return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z'; } /* * Character.isDigit() is not used here because it would include * non 0-to-9 numbers like i.e. arabic or indian numbers. */ private static boolean isDigit(final int c) { return c >= '0' && c <= '9'; } } /* * Prefixes defined for use in escape and unescape operations */ private static final char ESCAPE_PREFIX = '%'; /* * Small utility char arrays for hexadecimal conversion. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); private UriEscapeUtil() { super(); } static char[] printHexa(final byte b) { final char[] result = new char[2]; result[0] = HEXA_CHARS_UPPER[(b >> 4) & 0xF]; result[1] = HEXA_CHARS_UPPER[b & 0xF]; return result; } static byte parseHexa(final char c1, final char c2) { byte result = 0; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c1 == HEXA_CHARS_UPPER[j] || c1 == HEXA_CHARS_LOWER[j]) { result += (j << 4); break; } } for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c2 == HEXA_CHARS_UPPER[j] || c2 == HEXA_CHARS_LOWER[j]) { result += j; break; } } return result; } /* * Perform an escape operation, based on String, according to the specified type. */ static String escape(final String text, final UriEscapeType escapeType, final String encoding) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be alphabetic, and we won't need to do anything at * all for them. No need to use the complete UriEscapeType check system at all. */ if (UriEscapeType.isAlpha(codepoint)) { continue; } /* * Check whether the character is allowed or not */ if (escapeType.isAllowed(codepoint)) { continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape * * ----------------------------------------------------------------------------------------- */ final byte[] charAsBytes; try { charAsBytes = new String(Character.toChars(codepoint)).getBytes(encoding); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException("Exception while escaping URI: Bad encoding '" + encoding + "'", e); } for (final byte b : charAsBytes) { strBuilder.append('%'); strBuilder.append(printHexa(b)); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final UriEscapeType escapeType, final String encoding) throws IOException { if (reader == null) { return; } int c1, c2; // c0: last char, c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); /* * Shortcut: most characters will be alphabetic, and we won't need to do anything at * all for them. No need to use the complete UriEscapeType check system at all. */ if (UriEscapeType.isAlpha(codepoint)) { writer.write(c1); continue; } /* * Check whether the character is allowed or not */ if (escapeType.isAllowed(codepoint)) { writer.write(c1); continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c1 = c2; c2 = reader.read(); } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape * * ----------------------------------------------------------------------------------------- */ final byte[] charAsBytes; try { charAsBytes = new String(Character.toChars(codepoint)).getBytes(encoding); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException("Exception while escaping URI: Bad encoding '" + encoding + "'", e); } for (final byte b : charAsBytes) { writer.write('%'); writer.write(printHexa(b)); } } } /* * Perform an escape operation, based on char[], according to the specified type */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final UriEscapeType escapeType, final String encoding) throws IOException { if (text == null || text.length == 0) { return; } final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); /* * Shortcut: most characters will be alphabetic, and we won't need to do anything at * all for them. No need to use the complete UriEscapeType check system at all. */ if (UriEscapeType.isAlpha(codepoint)) { continue; } /* * Check whether the character is allowed or not */ if (escapeType.isAllowed(codepoint)) { continue; } /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * ----------------------------------------------------------------------------------------- * * Perform the real escape * * ----------------------------------------------------------------------------------------- */ final byte[] charAsBytes; try { charAsBytes = new String(Character.toChars(codepoint)).getBytes(encoding); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException("Exception while escaping URI: Bad encoding '" + encoding + "'", e); } for (final byte b : charAsBytes) { writer.write('%'); writer.write(printHexa(b)); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } /* * Perform an unescape operation based on String. */ static String unescape(final String text, final UriEscapeType escapeType, final String encoding) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX && (c != '+' || !escapeType.canPlusEscapeWhitespace())) { continue; } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } /* * Deal with possible '+'-escaped whitespace (application/x-www-form-urlencoded) */ if (c == '+') { // if we reached this point with c == '+', it's escaping a whitespace strBuilder.append(' '); readOffset = i + 1; continue; } /* * ESCAPE PROCESS * -------------- * If there are more than one percent-encoded/escaped sequences together, we will * need to unescape them all at once (because they might be bytes --up to 4-- of * the same char). */ // Max possible size will be the remaining amount of chars / 3 final byte[] bytes = new byte[(max-i)/3]; char aheadC = c; int pos = 0; while (((i + 2) < max) && aheadC == ESCAPE_PREFIX) { bytes[pos++] = parseHexa(text.charAt(i + 1), text.charAt(i + 2)); i += 3; if (i < max) { aheadC = text.charAt(i); } } if (i < max && aheadC == ESCAPE_PREFIX) { // Incomplete escape sequence! throw new IllegalArgumentException("Incomplete escaping sequence in input"); } try { strBuilder.append(new String(bytes, 0, pos, encoding)); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException("Exception while escaping URI: Bad encoding '" + encoding + "'", e); } readOffset = i; } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer, final UriEscapeType escapeType, final String encoding) throws IOException { if (reader == null) { return; } byte[] escapes = new byte[4]; int c1, c2, ce0, ce1, ce2; // c1: current char, c2: next char, ce0, ce1, ce2: current escape chars c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); /* * Check the need for an unescape operation at this point */ if ((c1 != ESCAPE_PREFIX || c2 < 0) && (c1 != '+' || !escapeType.canPlusEscapeWhitespace())) { writer.write(c1); continue; } /* * Deal with possible '+'-escaped whitespace (application/x-www-form-urlencoded) */ if (c1 == '+') { // if we reached this point with c == '+', it's escaping a whitespace writer.write(' '); continue; } /* * ESCAPE PROCESS * -------------- * If there are more than one percent-encoded/escaped sequences together, we will * need to unescape them all at once (because they might be bytes --up to 4-- of * the same char). */ int pos = 0; ce0 = c1; ce1 = c2; ce2 = reader.read(); while (ce0 == ESCAPE_PREFIX && ce1 >= 0 && ce2 >= 0) { if (pos == escapes.length) { // we need to grow! byte[] newEscapes = new byte[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } escapes[pos++] = parseHexa((char) ce1, (char) ce2); ce0 = reader.read(); ce1 = ce0 < 0 ? ce0 : ce0 != ESCAPE_PREFIX ? 0x0 : reader.read(); ce2 = ce1 < 0 ? ce1 : ce0 != ESCAPE_PREFIX ? 0x0 : reader.read(); } if (ce0 == ESCAPE_PREFIX) { // Incomplete escape sequence! throw new IllegalArgumentException("Incomplete escaping sequence in input"); } c2 = ce0; try { writer.write(new String(escapes, 0, pos, encoding)); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException("Exception while escaping URI: Bad encoding '" + encoding + "'", e); } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer, final UriEscapeType escapeType, final String encoding) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != ESCAPE_PREFIX && (c != '+' || !escapeType.canPlusEscapeWhitespace())) { continue; } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset copy all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } /* * Deal with possible '+'-escaped whitespace (application/x-www-form-urlencoded) */ if (c == '+') { // if we reached this point with c == '+', it's escaping a whitespace writer.write(' '); readOffset = i + 1; continue; } /* * ESCAPE PROCESS * -------------- * If there are more than one percent-encoded/escaped sequences together, we will * need to unescape them all at once (because they might be bytes --up to 4-- of * the same char). */ // Max possible size will be the remaining amount of chars / 3 final byte[] bytes = new byte[(max-i)/3]; char aheadC = c; int pos = 0; while (((i + 2) < max) && aheadC == ESCAPE_PREFIX) { bytes[pos++] = parseHexa(text[i + 1], text[i + 2]); i += 3; if (i < max) { aheadC = text[i]; } } if (i < max && aheadC == ESCAPE_PREFIX) { // Incomplete escape sequence! throw new IllegalArgumentException("Incomplete escaping sequence in input"); } try { writer.write(new String(bytes, 0, pos, encoding)); } catch (final UnsupportedEncodingException e) { throw new IllegalArgumentException("Exception while escaping URI: Bad encoding '" + encoding + "'", e); } readOffset = i; } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/000077500000000000000000000000001311410233600244675ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/Xml10EscapeSymbolsInitializer.java000066400000000000000000000117161311410233600331370ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; import java.util.Arrays; /** *

* This class initializes the {@link XmlEscapeSymbols#XML10_SYMBOLS} structure. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class Xml10EscapeSymbolsInitializer { static XmlEscapeSymbols initializeXml10(final boolean attributes) { final XmlEscapeSymbols.References xml10References = new XmlEscapeSymbols.References(); /* * -------------------------------------------------------------------------------------------------- * XML 1.0 CHARACTER ENTITY REFERENCES * See: http://www.w3.org/TR/xml * -------------------------------------------------------------------------------------------------- */ xml10References.addReference(34, """); xml10References.addReference(38, "&"); xml10References.addReference(39, "'"); xml10References.addReference(60, "<"); xml10References.addReference(62, ">"); /* * Initialization of escape levels. * Defined levels : * * - Level 1 : Markup-significant characters (including the apostrophe) * - Level 2 : Markup-significant characters plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters * */ final byte[] escapeLevels = new byte[XmlEscapeSymbols.LEVELS_LEN]; /* * Everything is level 3 unless contrary indication. */ Arrays.fill(escapeLevels, (byte)3); /* * Everything non-ASCII is level 2 unless contrary indication. */ for (char c = 0x80; c < XmlEscapeSymbols.LEVELS_LEN; c++) { escapeLevels[c] = 2; } /* * Alphanumeric characters are level 4. */ for (char c = 'A'; c <= 'Z'; c++) { escapeLevels[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { escapeLevels[c] = 4; } for (char c = '0'; c <= '9'; c++) { escapeLevels[c] = 4; } /* * The five XML predefined entities will be escaped always (level 1) */ escapeLevels['\''] = 1; escapeLevels['"'] = 1; escapeLevels['<'] = 1; escapeLevels['>'] = 1; escapeLevels['&'] = 1; /* * If these symbols are being initialized for escaping attributes, then we will * need to add \t, \n and \r */ if (attributes) { escapeLevels['\t'] = 1; escapeLevels['\n'] = 1; escapeLevels['\r'] = 1; } /* * XML 1.0 allows a series of control characters, but they should appear * escaped: [#x7F-#x84] | [#x86-#x9F] */ for (char c = 0x7F; c <= 0x84; c++) { escapeLevels[c] = 1; } for (char c = 0x86; c <= 0x9F; c++) { escapeLevels[c] = 1; } /* * Create the new symbols structure */ return new XmlEscapeSymbols(xml10References, escapeLevels, new Xml10CodepointValidator()); } private Xml10EscapeSymbolsInitializer() { super(); } static final class Xml10CodepointValidator implements XmlCodepointValidator { /* * XML 1.0 does not allow many control characters, nor unpaired surrogate chars * (characters used for composing two-char codepoints, but appearing on their own). */ public boolean isValid(final int codepoint) { if (codepoint < 0x20) { return (codepoint == 0x9 || codepoint == 0xA || codepoint == 0xD); } if (codepoint <= 0xD7FF) { // U+D800 - U+DFFF are reserved for low + high surrogates return true; } if (codepoint < 0xE000) { return false; } if (codepoint <= 0xFFFD) { // U+FFFE and U+FFFF are non-characters, and therefore not valid return true; } if (codepoint < 0x10000) { return false; } return true; } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/Xml11EscapeSymbolsInitializer.java000066400000000000000000000124331311410233600331350ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; import java.util.Arrays; /** *

* This class initializes the {@link org.unbescape.xml.XmlEscapeSymbols#XML11_SYMBOLS} structure. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class Xml11EscapeSymbolsInitializer { static XmlEscapeSymbols initializeXml11(final boolean attributes) { final XmlEscapeSymbols.References xml11References = new XmlEscapeSymbols.References(); /* * -------------------------------------------------------------------------------------------------- * XML 1.1 CHARACTER ENTITY REFERENCES * See: http://www.w3.org/TR/xml11 * -------------------------------------------------------------------------------------------------- */ xml11References.addReference( 34, """); xml11References.addReference( 38, "&"); xml11References.addReference( 39, "'"); xml11References.addReference( 60, "<"); xml11References.addReference( 62, ">"); /* * Initialization of escape levels. * Defined levels : * * - Level 1 : Markup-significant characters (including the apostrophe) * - Level 2 : Markup-significant characters plus all non-ASCII * - Level 3 : All non-alphanumeric characters * - Level 4 : All characters * * Note all XML 1.1 levels include the escape of allowed control characteres. * */ final byte[] escapeLevels = new byte[XmlEscapeSymbols.LEVELS_LEN]; /* * Everything is level 3 unless contrary indication. */ Arrays.fill(escapeLevels, (byte)3); /* * Everything non-ASCII is level 2 unless contrary indication. */ for (char c = 0x80; c < XmlEscapeSymbols.LEVELS_LEN; c++) { escapeLevels[c] = 2; } /* * Alphanumeric characters are level 4. */ for (char c = 'A'; c <= 'Z'; c++) { escapeLevels[c] = 4; } for (char c = 'a'; c <= 'z'; c++) { escapeLevels[c] = 4; } for (char c = '0'; c <= '9'; c++) { escapeLevels[c] = 4; } /* * The five XML predefined entities will be escaped always (level 1) */ escapeLevels['\''] = 1; escapeLevels['"'] = 1; escapeLevels['<'] = 1; escapeLevels['>'] = 1; escapeLevels['&'] = 1; /* * If these symbols are being initialized for escaping attributes, then we will * need to add \t, \n and \r */ if (attributes) { escapeLevels['\t'] = 1; escapeLevels['\n'] = 1; escapeLevels['\r'] = 1; } /* * XML 1.1 allows a series of control characters, but they should appear * escaped: [#x1-#x8] | [#xB-#xC] | [#xE-#x1F] | [#x7F-#x84] | [#x86-#x9F] */ for (char c = 0x1; c <= 0x8; c++) { escapeLevels[c] = 1; } escapeLevels[0xB] = 1; escapeLevels[0xC] = 1; for (char c = 0xE; c <= 0x1F; c++) { escapeLevels[c] = 1; } for (char c = 0x7F; c <= 0x84; c++) { escapeLevels[c] = 1; } for (char c = 0x86; c <= 0x9F; c++) { escapeLevels[c] = 1; } /* * Create the new symbols structure */ return new XmlEscapeSymbols(xml11References, escapeLevels, new Xml11CodepointValidator()); } private Xml11EscapeSymbolsInitializer() { super(); } static final class Xml11CodepointValidator implements XmlCodepointValidator { /* * XML 1.1 does not allow the null byte, nor unpaired surrogate chars * (characters used for composing two-char codepoints, but appearing on their own). */ public boolean isValid(final int codepoint) { if (codepoint == 0x0) { return false; } if (codepoint <= 0xD7FF) { // U+D800 - U+DFFF are reserved for low + high surrogates return true; } if (codepoint < 0xE000) { return false; } if (codepoint <= 0xFFFD) { // U+FFFE and U+FFFF are non-characters, and therefore not valid return true; } if (codepoint < 0x10000) { return false; } return true; } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/XmlCodepointValidator.java000066400000000000000000000024371311410233600316130ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; /** *

* Implementations of this interface are used to determine what codepoitns are allowed in * XML escaped output (even when escaped), and what codepoints should be simply removed from * output. *

*

* Implementations of this interface must be thread-safe. *

* * @author Daniel Fernández * * @since 1.0.0 * */ interface XmlCodepointValidator { boolean isValid(final int codepoint); } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/XmlEscape.java000066400000000000000000003371071311410233600272260ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; import java.io.IOException; import java.io.Reader; import java.io.Writer; /** *

* Utility class for performing XML escape/unescape operations. *

* * Configuration of escape/unescape operations * *

* Escape operations can be (optionally) configured by means of: *

*
    *
  • Level, which defines how deep the escape operation must be (what * chars are to be considered eligible for escaping, depending on the specific * needs of the scenario). Its values are defined by the {@link org.unbescape.xml.XmlEscapeLevel} * enum.
  • *
  • Type, which defines whether escaping should be performed by means of CERs * (Character Entity References) or by means of decimal/hexadecimal numerical references. * Its values are defined by the {@link org.unbescape.xml.XmlEscapeType} enum.
  • *
*

* Unescape operations need no configuration parameters. Unescape operations * will always perform complete unescape of CERs, decimal and hexadecimal references. *

* * Features * *

* This class supports both XML 1.0 and XML 1.1 escape/unescape operations. Whichever the XML version used, * only the five predefined XML character entities are supported: &lt;, * &gt;, &amp;, &quot and &apos;. This * means there is no support for DTD-defined or user-defined entities. *

*

* Each version of XML establishes a series of characters that are considered not-valid, even * when escaped —for example, the \u0000 (null byte)—. Escape operations will * automatically remove these chars. *

*

* Also, each version of XML establishes a series of control characters that, even if allowed as * valid characters, should always appear escaped. For example: \u0001 to * \u0008 in XML 1.1. *

*

* This class supports the whole Unicode character set: \u0000 to \u10FFFF, * including characters not representable by only one char in Java (>\uFFFF). *

* * Input/Output * *

* There are four different input/output modes that can be used in escape/unescape operations: *

*
    *
  • String input, String output: Input is specified as a String object * and output is returned as another. In order to improve memory performance, all escape and unescape * operations will return the exact same input object as output if no escape/unescape modifications * are required.
  • *
  • String input, java.io.Writer output: Input will be read from a String * and output will be written into the specified java.io.Writer.
  • *
  • java.io.Reader input, java.io.Writer output: Input will be read from a Reader * and output will be written into the specified java.io.Writer.
  • *
  • char[] input, java.io.Writer output: Input will be read from a char array * (char[]) and output will be written into the specified java.io.Writer. * Two int arguments called offset and len will be * used for specifying the part of the char[] that should be escaped/unescaped. These methods * should be called with offset = 0 and len = text.length in order to process * the whole char[].
  • *
* * Glossary * *
*
ER
*
XML Entity Reference: references to variables used to define shortcuts to standard text or * special characters. Entity references start with '&' and end with * ';'.
*
CER
*
Character Entity Reference: XML Entity Reference used to define a shortcut to a specific * character. XML specifies five predefined CERs: &lt; (<), * &gt; (>), &amp; (&), * &quot; (") and &apos; * (').
*
DCR
*
Decimal Character Reference: base-10 numerical representation of an Unicode codepoint: * &#225;
*
HCR
*
Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: * á. Note that XML only allows lower-case 'x' for defining hexadecimal * character entity references (in contrast with HTML, which allows both '&#x...;' and * '&#x...;').
*
Unicode Codepoint
*
Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the * first char is a high surrogate (\uD800 to \uDBFF) and the * second is a low surrogate (\uDC00 to \uDFFF).
*
* * References * *

* The following references apply: *

* * * * @author Daniel Fernández * * @since 1.0.0 * */ public final class XmlEscape { /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a String input. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls {@link #escapeXml10(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeXml10Minimal(final String text) { return escapeXml(text, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a String input. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls {@link #escapeXml11(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeXml11Minimal(final String text) { return escapeXml(text, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a String input meant to be an XML attribute value. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml10(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. * * @since 1.1.5 */ public static String escapeXml10AttributeMinimal(final String text) { return escapeXml(text, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a String input meant to be an XML attribute value. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml11(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. * * @since 1.1.5 */ public static String escapeXml11AttributeMinimal(final String text) { return escapeXml(text, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml10(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeXml10(final String text) { return escapeXml(text, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml11(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeXml11(final String text) { return escapeXml(text, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input meant to be an XML attribute value. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml10(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. * * @since 1.1.5 */ public static String escapeXml10Attribute(final String text) { return escapeXml(text, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input meant to be an XML attribute value. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml11(String, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. * * @since 1.1.5 */ public static String escapeXml11Attribute(final String text) { return escapeXml(text, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) XML 1.0 escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other String-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeXml10(final String text, final XmlEscapeType type, final XmlEscapeLevel level) { return escapeXml(text, XmlEscapeSymbols.XML10_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a String input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other String-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String escapeXml11(final String text, final XmlEscapeType type, final XmlEscapeLevel level) { return escapeXml(text, XmlEscapeSymbols.XML11_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.0 escape operation on a String input * meant to be an XML attribute value. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other String-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. * * @since 1.1.5 */ public static String escapeXml10Attribute(final String text, final XmlEscapeType type, final XmlEscapeLevel level) { return escapeXml(text, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a String input * meant to be an XML attribute value. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other String-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @return The escaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no escaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. * * @since 1.1.5 */ public static String escapeXml11Attribute(final String text, final XmlEscapeType type, final XmlEscapeLevel level) { return escapeXml(text, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, type, level); } /* * Private escape method called from XML 1.0 and XML 1.1 public methods, once the correct * symbol set has been selected. */ private static String escapeXml(final String text, final XmlEscapeSymbols symbols, final XmlEscapeType type, final XmlEscapeLevel level) { if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } return XmlEscapeUtil.escape(text, symbols, type, level); } /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls {@link #escapeXml10(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml10Minimal(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls {@link #escapeXml11(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml11Minimal(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a String input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml10(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10AttributeMinimal(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a String input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml11(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11AttributeMinimal(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml10(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml10(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml11(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml11(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml10(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10Attribute(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a String input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml11(String, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11Attribute(final String text, final Writer writer) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) XML 1.0 escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other String/Writer-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml10(final String text, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML10_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a String input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other String/Writer-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml11(final String text, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML11_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.0 escape operation on a String input * meant to be an XML attribute value, writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other String/Writer-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10Attribute(final String text, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a String input * meant to be an XML attribute value, writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other String/Writer-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the String to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11Attribute(final String text, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, type, level); } /* * Private escape method called from XML 1.0 and XML 1.1 public methods, once the correct * symbol set has been selected. */ private static void escapeXml(final String text, final Writer writer, final XmlEscapeSymbols symbols, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } XmlEscapeUtil.escape(new InternalStringReader(text), writer, symbols, type, level); } /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls {@link #escapeXml10(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml10Minimal(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls {@link #escapeXml11(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml11Minimal(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a Reader input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml10(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10AttributeMinimal(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a Reader input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml11(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11AttributeMinimal(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml10(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml10(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a Reader input, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml11(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml11(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a Reader input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml10(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10Attribute(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a Reader input meant to be an XML attribute value, writing results to a Writer. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml11(Reader, Writer, XmlEscapeType, XmlEscapeLevel)} with the following * preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11Attribute(final Reader reader, final Writer writer) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) XML 1.0 escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other Reader/Writer-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml10(final Reader reader, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML10_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a Reader input, * writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other Reader/Writer-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void escapeXml11(final Reader reader, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML11_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.0 escape operation on a Reader input * meant to be an XML attribute value, writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other Reader/Writer-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10Attribute(final Reader reader, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a Reader input * meant to be an XML attribute value, writing results to a Writer. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other Reader/Writer-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be escaped. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11Attribute(final Reader reader, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(reader, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, type, level); } /* * Private escape method called from XML 1.0 and XML 1.1 public methods, once the correct * symbol set has been selected. */ private static void escapeXml(final Reader reader, final Writer writer, final XmlEscapeSymbols symbols, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } XmlEscapeUtil.escape(reader, writer, symbols, type, level); } /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls * {@link #escapeXml10(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeXml10Minimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a char[] input. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* This method calls * {@link #escapeXml10(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeXml11Minimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 1 (only markup-significant chars) escape operation * on a char[] input meant to be an XML attribute value. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls * {@link #escapeXml10(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10AttributeMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 1 (only markup-significant chars) escape operation * on a char[] input meant to be an XML attribute value. *

*

* Level 1 means this method will only escape the five markup-significant characters which * are predefined as Character Entity References in XML: * <, >, &, " and '. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls * {@link #escapeXml10(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_1_ONLY_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11AttributeMinimal(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml10(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeXml10(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML10_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a char[] input. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* This method calls {@link #escapeXml11(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void escapeXml11(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML11_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.0 level 2 (markup-significant and all non-ASCII chars) escape operation * on a char[] input meant to be an XML attribute value. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml10(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10Attribute(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform an XML 1.1 level 2 (markup-significant and all non-ASCII chars) escape operation * on a char[] input meant to be an XML attribute value. *

*

* Level 2 means this method will escape: *

*
    *
  • The five markup-significant characters: <, >, &, * " and '
  • *
  • All non ASCII characters.
  • *
*

* This escape will be performed by replacing those chars by the corresponding XML Character Entity References * (e.g. '&lt;') when such CER exists for the replaced character, and replacing by a hexadecimal * character reference (e.g. '&#x2430;') when there there is no CER for the replaced character. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* This method calls {@link #escapeXml11(char[], int, int, java.io.Writer, XmlEscapeType, XmlEscapeLevel)} * with the following preconfigured values: *

*
    *
  • type: * {@link org.unbescape.xml.XmlEscapeType#CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA}
  • *
  • level: * {@link org.unbescape.xml.XmlEscapeLevel#LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT}
  • *
*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11Attribute(final char[] text, final int offset, final int len, final Writer writer) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA, XmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT); } /** *

* Perform a (configurable) XML 1.0 escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other char[]-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeXml10(final char[] text, final int offset, final int len, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML10_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a char[] input. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* All other char[]-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs */ public static void escapeXml11(final char[] text, final int offset, final int len, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML11_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.0 escape operation on a char[] input * meant to be an XML attribute value. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other char[]-based escapeXml10*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml10Attribute(final char[] text, final int offset, final int len, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML10_ATTRIBUTE_SYMBOLS, type, level); } /** *

* Perform a (configurable) XML 1.1 escape operation on a char[] input * meant to be an XML attribute value. *

*

* This method will perform an escape operation according to the specified * {@link org.unbescape.xml.XmlEscapeType} and {@link org.unbescape.xml.XmlEscapeLevel} * argument values. *

*

* Besides, being an attribute value also \t, \n and \r will * be escaped to avoid white-space normalization from removing line feeds (turning them into white * spaces) during future parsing operations. *

*

* All other char[]-based escapeXml11*(...) methods call this one with preconfigured * type and level values. *

*

* This method is thread-safe. *

* * @param text the char[] to be escaped. * @param offset the position in text at which the escape operation should start. * @param len the number of characters in text that should be escaped. * @param writer the java.io.Writer to which the escaped result will be written. Nothing will * be written at all to this writer if input is null. * @param type the type of escape operation to be performed, see {@link org.unbescape.xml.XmlEscapeType}. * @param level the escape level to be applied, see {@link org.unbescape.xml.XmlEscapeLevel}. * @throws IOException if an input/output exception occurs * * @since 1.1.5 */ public static void escapeXml11Attribute(final char[] text, final int offset, final int len, final Writer writer, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { escapeXml(text, offset, len, writer, XmlEscapeSymbols.XML11_ATTRIBUTE_SYMBOLS, type, level); } /* * Private escape method called from XML 1.0 and XML 1.1 public methods, once the correct * symbol set has been selected. */ private static void escapeXml(final char[] text, final int offset, final int len, final Writer writer, final XmlEscapeSymbols symbols, final XmlEscapeType type, final XmlEscapeLevel level) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (type == null) { throw new IllegalArgumentException("The 'type' argument cannot be null"); } if (level == null) { throw new IllegalArgumentException("The 'level' argument cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } XmlEscapeUtil.escape(text, offset, len, writer, symbols, type, level); } /** *

* Perform an XML unescape operation on a String input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete XML 1.0/1.1 unescape of CERs, decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @return The unescaped result String. As a memory-performance improvement, will return the exact * same object as the text input argument if no unescaping modifications were required (and * no additional String objects will be created during processing). Will * return null if input is null. */ public static String unescapeXml(final String text) { // The chosen symbols (1.0 or 1.1) don't really matter, as both contain the same CERs if (text == null) { return null; } if (text.indexOf('&') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed return text; } return XmlEscapeUtil.unescape(text, XmlEscapeSymbols.XML11_SYMBOLS); } /** *

* Perform an XML unescape operation on a String input, * writing results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete XML 1.0/1.1 unescape of CERs, decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param text the String to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeXml(final String text, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } if (text == null) { return; } if (text.indexOf('&') < 0) { // Fail fast, avoid more complex (and less JIT-table) method to execute if not needed writer.write(text); return; } // The chosen symbols (1.0 or 1.1) don't really matter, as both contain the same CERs XmlEscapeUtil.unescape(new InternalStringReader(text), writer, XmlEscapeSymbols.XML11_SYMBOLS); } /** *

* Perform an XML unescape operation on a Reader input, * writing results to a Writer. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete XML 1.0/1.1 unescape of CERs, decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param reader the Reader reading the text to be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs * * @since 1.1.2 */ public static void unescapeXml(final Reader reader, final Writer writer) throws IOException { if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } // The chosen symbols (1.0 or 1.1) don't really matter, as both contain the same CERs XmlEscapeUtil.unescape(reader, writer, XmlEscapeSymbols.XML11_SYMBOLS); } /** *

* Perform an XML unescape operation on a char[] input. *

*

* No additional configuration arguments are required. Unescape operations * will always perform complete XML 1.0/1.1 unescape of CERs, decimal * and hexadecimal references. *

*

* This method is thread-safe. *

* * @param text the char[] to be unescaped. * @param offset the position in text at which the unescape operation should start. * @param len the number of characters in text that should be unescaped. * @param writer the java.io.Writer to which the unescaped result will be written. Nothing will * be written at all to this writer if input is null. * @throws IOException if an input/output exception occurs */ public static void unescapeXml(final char[] text, final int offset, final int len, final Writer writer) throws IOException{ if (writer == null) { throw new IllegalArgumentException("Argument 'writer' cannot be null"); } final int textLen = (text == null? 0 : text.length); if (offset < 0 || offset > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } if (len < 0 || (offset + len) > textLen) { throw new IllegalArgumentException( "Invalid (offset, len). offset=" + offset + ", len=" + len + ", text.length=" + textLen); } // The chosen symbols (1.0 or 1.1) don't really matter, as both contain the same CERs XmlEscapeUtil.unescape(text, offset, len, writer, XmlEscapeSymbols.XML11_SYMBOLS); } private XmlEscape() { super(); } /* * This is basically a very simplified, thread-unsafe version of StringReader that should * perform better than the original StringReader by removing all synchronization structures. * * Note the only implemented methods are those that we know are really used from within the * stream-based escape/unescape operations. */ private static final class InternalStringReader extends Reader { private String str; private int length; private int next = 0; public InternalStringReader(final String s) { super(); this.str = s; this.length = s.length(); } @Override public int read() throws IOException { if (this.next >= length) { return -1; } return this.str.charAt(this.next++); } @Override public int read(final char[] cbuf, final int off, final int len) throws IOException { if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } if (this.next >= this.length) { return -1; } int n = Math.min(this.length - this.next, len); this.str.getChars(this.next, this.next + n, cbuf, off); this.next += n; return n; } @Override public void close() throws IOException { this.str = null; // Just set the reference to null, help the GC } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/XmlEscapeLevel.java000066400000000000000000000122001311410233600301760ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; /** *

* Levels defined for XML escape/unescape operations: *

* *
    *
  • Level 1: Escape only markup-significant characters (all five XML predefined * entities). Therefore <, >, &, " and * ' will be escaped. This level is safe for use in texts and also XML tag attributes * (tag attributes are always quoted in XML). Note the result of a level-1 escape operation might * still contain non-ASCII characters if they existed in input, and therefore you will still need * to correctly manage your input/output character encoding settings.
  • *
  • Level 2: Escape all markup-significant characters (as defined in level 1), plus all * non-ASCII characters. The result of a level-2 escape operation is therefore always ASCII-only text, and * safer to use in complex scenarios with mixed input/output character encodings. This level is safe for * use in texts and also XML tag attributes (tag attributes are always quoted in XML).
  • *
  • Level 3: Escape all non-alphanumeric characters, this is, all but those in the * A-Z, a-z and 0-9 ranges. This level * can be safely used for completely escaping texts, including whitespace, line feeds, punctuation, etc. in * scenarios where this adds an extra level of safety.
  • *
  • Level 4: Escape all characters, even alphanumeric ones.
  • *
* *

* Note that, apart from the settings established by each of these levels, different XML versions might establish * the required escaping of a series of control characteres (basically, all the allowed ones). These * control character will be always escaped, from level 1. Besides, some characters considered invalid * in such versions of XML might be directly removed from output. *

* *

* Also note that no level 0 exists, in order to keep consistency with HTML escape levels defined in * {@link org.unbescape.html.HtmlEscapeLevel}. *

* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.xml.XmlEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum XmlEscapeLevel { /** * Level 1 escape: escape only markup-significant characters (all five XML predefined entities): * <, >, &, " and ' */ LEVEL_1_ONLY_MARKUP_SIGNIFICANT(1), /** * Level 2 escape: escape markup-significant characters plus all non-ASCII characters (result will always be ASCII). */ LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT(2), /** * Level 3 escape: escape all non-alphanumeric characteres (escape all but those in the * A-Z, a-z and 0-9 ranges). */ LEVEL_3_ALL_NON_ALPHANUMERIC(3), /** * Level 4 escape: escape all characters, including alphanumeric. */ LEVEL_4_ALL_CHARACTERS(4); private final int escapeLevel; /** *

* Utility method for obtaining an enum value from its corresponding int level value. *

* * @param level the level * @return the escape level enum constant, or IllegalArgumentException if level does not exist. */ public static XmlEscapeLevel forLevel(final int level) { switch (level) { case 1: return LEVEL_1_ONLY_MARKUP_SIGNIFICANT; case 2: return LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT; case 3: return LEVEL_3_ALL_NON_ALPHANUMERIC; case 4: return LEVEL_4_ALL_CHARACTERS; default: throw new IllegalArgumentException("No escape level enum constant defined for level: " + level); } } XmlEscapeLevel(final int escapeLevel) { this.escapeLevel = escapeLevel; } /** * Return the int escape level. * * @return the escape level. */ public int getEscapeLevel() { return this.escapeLevel; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/XmlEscapeSymbols.java000066400000000000000000000343531311410233600305740ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; /** *

* Instances of this class group all the complex data structures needed to support escape and unescape * operations for XML. *

*

* In contrast with HTML escape operations, the entity references to be used for XML escape/unescape operations * can be defined by the user by manually creating an instance of this class containing all the entities he/she * wants to escape. *

*

* It is not recommended to use this XML class for HTML escape/unescape operations. Use the methods * in {@link org.unbescape.html.HtmlEscape} instead, as HTML escape rules include a series of tweaks not allowed in * XML, as well as being less lenient with regard to aspects such as case-sensitivity. Besides, the HTML escape * infrastructure is able to apply a series of performance optimizations not possible in XML due to the fact that * the number of HTML Character Entity References (Named Character References in HTML5 jargon) is fixed * and known in advance. *

*

* Objects of this class are thread-safe. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class XmlEscapeSymbols { /* * GLOSSARY * ------------------------ * * ER * XML Entity Reference: references to variables used to define shortcuts to standard text or * special characters. Entity references start with '&' and end with ';'. * * CER * Character Entity Reference: XML Entity Reference used to define a shortcut to a specific * character. XML specifies five 'predefined' CERs: < (<), > (>), & (&), " (") and ' ('). * * DCR * Decimal Character Reference: base-10 numerical representation of an Unicode codepoint: á * * HCR * Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: á * Note that XML only allows lower-case 'x' for defining hexadecimal character entity references (in contrast * with HTML, which allows both '&#x...;' and '&#X...;'). * * Unicode Codepoint * Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the first char is a high * surrogate (\uD800 to \uDBFF) and the second is a low surrogate (\uDC00 to \uDFFF). * See: http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html * */ /* * Constants holding the definition of all the XmlEscapeSymbols for XML 1.0 and 1.1, to be used in escape and * unescape operations. * * Note different sets are needed for attributes in order to escape \t, \n and \r in attributes. Even if these * are characters allowed by the XML spec to appear in attribute values, the spec also specifies that attribute * values should be normalised when read so that these characters are turned into white space characters. So * in order to preserve the original values properly, we need these characters to be escaped. * See: https://www.w3.org/TR/REC-xml/#AVNormalize */ static final XmlEscapeSymbols XML10_SYMBOLS; static final XmlEscapeSymbols XML11_SYMBOLS; static final XmlEscapeSymbols XML10_ATTRIBUTE_SYMBOLS; static final XmlEscapeSymbols XML11_ATTRIBUTE_SYMBOLS; static { XML10_SYMBOLS = Xml10EscapeSymbolsInitializer.initializeXml10(false); XML11_SYMBOLS = Xml11EscapeSymbolsInitializer.initializeXml11(false); XML10_ATTRIBUTE_SYMBOLS = Xml10EscapeSymbolsInitializer.initializeXml10(true); XML11_ATTRIBUTE_SYMBOLS = Xml11EscapeSymbolsInitializer.initializeXml11(true); } /* * NOTE * ------------- * Most of the fields in objects of this class are package-accessible, as the class itself is, in order * to allow them (the fields) to be directly accessed from the classes doing the real escape/unescape (basically, * the {@link org.unbescape.xml.XmlEscapeUtil} class. * ------------- */ /* * Size of the array specifying the escape levels. */ static final char LEVELS_LEN = 0x9f + 2; /* * This array will hold the 'escape level' assigned to chars (not codepoints) up to LEVELS_LEN. * - The last position of this array will be used for determining the level of all codepoints >= (LEVELS_LEN - 1) */ final byte[] ESCAPE_LEVELS = new byte[LEVELS_LEN]; /* * This array will contain all the codepoints that might be escaped, numerically ordered. * - Positions in this array will correspond to positions in the SORTED_CERS_BY_CODEPOINT array, so that one array * (this one) holds the codepoints while the other one holds the CERs such codepoints refer to. * - Gives the opportunity to store all codepoints in numerical order and therefore be able to perform * binary search operations in order to quickly find codepoints (and translate to CERs) when escaping. */ final int[] SORTED_CODEPOINTS; /* * This array contains all the CERs corresponding to the codepoints stored in SORTED_CODEPOINTS. This array is * ordered so that each index in SORTED_CODEPOINTS can also be used to retrieve the corresponding CER when used * on this array. */ final char[][] SORTED_CERS_BY_CODEPOINT; /* * This array will contain all the CERs that might be unescaped, alphabetically ordered. * - Positions in this array will correspond to positions in the SORTED_CODEPOINTS_BY_CER array, so that one array * (this one) holds the CERs while the other one holds the codepoint(s) such CERs refer to. * - Gives the opportunity to store all CERs in alphabetical order and therefore be able to perform * binary search operations in order to quickly find CERs (and translate to codepoints) when unescaping. */ final char[][] SORTED_CERS; /* * This array contains all the codepoints corresponding to the CERs stored in SORTED_CERS. This array is * ordered so that each index in SORTED_CERS can also be used to retrieve the corresponding CODEPOINT when used * on this array. */ final int[] SORTED_CODEPOINTS_BY_CER; /* * This object will be in charge of validating each codepoint in input, in order to determine * whether such codepoint will be allowed in escaped output (escaped or not). Invalid codepoints * will be simply discarded. */ final XmlCodepointValidator CODEPOINT_VALIDATOR; /* * Create a new XmlEscapeSymbols structure. This will initialize all the structures needed to cover the * specified references and escape levels, including sorted arrays, overflow maps, etc. */ XmlEscapeSymbols(final References references, final byte[] escapeLevels, final XmlCodepointValidator codepointValidator) { super(); this.CODEPOINT_VALIDATOR = codepointValidator; // Initialize escape levels: just copy the array System.arraycopy(escapeLevels, 0, ESCAPE_LEVELS, 0, LEVELS_LEN); // Initialize the length of the escaping structures final int structureLen = references.references.size(); // Initialize some auxiliary structures final List cers = new ArrayList(structureLen + 5); final List codepoints = new ArrayList(structureLen + 5); // For each reference, initialize its corresponding codepoint -> CER and CER -> codepoint structures for (final Reference reference : references.references) { cers.add(reference.cer); // can be null codepoints.add(Integer.valueOf(reference.codepoint)); } // We can initialize now the arrays SORTED_CODEPOINTS = new int[structureLen]; SORTED_CERS_BY_CODEPOINT = new char[structureLen][]; SORTED_CERS = new char[structureLen][]; SORTED_CODEPOINTS_BY_CER = new int[structureLen]; final List cersOrdered = new ArrayList(cers); Collections.sort(cersOrdered, new Comparator() { public int compare(final char[] o1, final char[] o2) { return new String(o1).compareTo(new String(o2)); } }); final List codepointsOrdered = new ArrayList(codepoints); Collections.sort(codepointsOrdered); // Order the CODEPOINT -> CERs (escape)structures for (short i = 0; i < structureLen; i++) { final int codepoint = codepointsOrdered.get(i); SORTED_CODEPOINTS[i] = codepoint; for (short j = 0; j < structureLen; j++) { if (codepoint == codepoints.get(j)) { SORTED_CERS_BY_CODEPOINT[i] = cers.get(j); break; } } } // Order the CERs -> CODEPOINT (unescape)structures for (short i = 0; i < structureLen; i++) { final char[] cer = cersOrdered.get(i); SORTED_CERS[i] = cer; for (short j = 0; j < structureLen; j++) { if (Arrays.equals(cer, cers.get(j))) { SORTED_CODEPOINTS_BY_CER[i] = codepoints.get(j); break; } } } } /* * These two methods (two versions: for String and for char[]) compare each of the candidate * text fragments with an CER coming from the SORTED_CERS array, during binary search operations. */ private static int compare(final char[] cer, final String text, final int start, final int end) { final int textLen = end - start; final int maxCommon = Math.min(cer.length, textLen); int i; // char 0 is discarded, will be & in both cases for (i = 1; i < maxCommon; i++) { final char tc = text.charAt(start + i); if (cer[i] < tc) { return -1; } else if (cer[i] > tc) { return 1; } } if (cer.length > i) { return 1; } if (textLen > i) { return -1; } return 0; } private static int compare(final char[] cer, final char[] text, final int start, final int end) { final int textLen = end - start; final int maxCommon = Math.min(cer.length, textLen); int i; // char 0 is discarded, will be & in both cases for (i = 1; i < maxCommon; i++) { final char tc = text[start + i]; if (cer[i] < tc) { return -1; } else if (cer[i] > tc) { return 1; } } if (cer.length > i) { return 1; } if (textLen > i) { return -1; } return 0; } /* * These two methods (two versions: for String and for char[]) are used during unescape at the * {@link XmlEscapeUtil} class in order to quickly find the entity corresponding to a preselected fragment * of text (if there is such entity). */ static int binarySearch(final char[][] values, final String text, final int start, final int end) { int low = 0; int high = values.length - 1; while (low <= high) { final int mid = (low + high) >>> 1; final char[] midVal = values[mid]; final int cmp = compare(midVal, text, start, end); if (cmp == -1) { low = mid + 1; } else if (cmp == 1) { high = mid - 1; } else { // Found!! return mid; } } return Integer.MIN_VALUE; // Not found! } static int binarySearch(final char[][] values, final char[] text, final int start, final int end) { int low = 0; int high = values.length - 1; while (low <= high) { final int mid = (low + high) >>> 1; final char[] midVal = values[mid]; final int cmp = compare(midVal, text, start, end); if (cmp == -1) { low = mid + 1; } else if (cmp == 1) { high = mid - 1; } else { // Found!! return mid; } } return Integer.MIN_VALUE; // Not found! } /* * Inner utility classes that model the named character references to be included in an initialized * instance of the XmlEscapeSymbols class. */ static final class References { private final List references = new ArrayList(200); References() { super(); } void addReference(final int codepoint, final String cer) { this.references.add(new Reference(cer, codepoint)); } } private static final class Reference { private final char[] cer; private final int codepoint; private Reference(final String cer, final int codepoint) { super(); // cer CAN be null -> codepoint should be removed from escaped output. this.cer = cer.toCharArray(); this.codepoint = codepoint; } } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/XmlEscapeType.java000066400000000000000000000063531311410233600300640ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; /** *

* Types of escape operations to be performed on XML text: *

* *
    *
  • CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_DECIMAL: Replace escaped characters * with Character Entity References whenever possible (depending on the specified * {@link org.unbescape.xml.XmlEscapeLevel}), and default to using Decimal Character References * for escaped characters that do not have an associated CER.
  • *
  • CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_DECIMAL: Replace escaped characters * with Character Entity References whenever possible (depending on the specified * {@link org.unbescape.xml.XmlEscapeLevel}), and default to using Hexadecimal Character References * for escaped characters that do not have an associated CER.
  • *
  • DECIMAL_REFERENCES: Replace escaped characters with * Decimal Character References (will never use CER).
  • *
  • HEXADECIMAL_REFERENCES: Replace escaped characters with * Hexadecimal Character References (will never use CERs).
  • *
* *

* For further information, see the Glossary and the References sections at the * documentation for the {@link org.unbescape.xml.XmlEscape} class. *

* * @author Daniel Fernández * * @since 1.0.0 * */ public enum XmlEscapeType { /** * Use Character Entity References if possible, default to Decimal Character References. */ CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_DECIMAL(true, false), /** * Use Character Entity Referencess if possible, default to Hexadecimal Character References. */ CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA(true, true), /** * Always use Decimal Character References (no CERs will be used). */ DECIMAL_REFERENCES(false, false), /** * Always use Hexadecimal Character References (no CERs will be used). */ HEXADECIMAL_REFERENCES(false, true); private final boolean useCERs; private final boolean useHexa; XmlEscapeType(final boolean useCERs, final boolean useHexa) { this.useCERs = useCERs; this.useHexa = useHexa; } boolean getUseCERs() { return this.useCERs; } boolean getUseHexa() { return this.useHexa; } } unbescape-unbescape-1.1.5.RELEASE/src/main/java/org/unbescape/xml/XmlEscapeUtil.java000066400000000000000000001202571311410233600300600ustar00rootroot00000000000000/* * ============================================================================= * * Copyright (c) 2014, The UNBESCAPE team (http://www.unbescape.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ package org.unbescape.xml; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.Arrays; /** *

* Internal class in charge of performing the real escape/unescape operations. *

* * @author Daniel Fernández * * @since 1.0.0 * */ final class XmlEscapeUtil { /* * GLOSSARY * ------------------------ * * ER * XML Entity Reference: references to variables used to define shortcuts to standard text or * special characters. Entity references start with '&' and end with ';'. * * CER * Character Entity Reference: XML Entity Reference used to define a shortcut to a specific * character. XML specifies five 'predefined' CERs: < (<), > (>), & (&), " (") and ' ('). * * DCER * Decimal Character Entity Reference: base-10 numerical representation of an Unicode codepoint: á * * HCER * Hexadecimal Character Reference: hexadecimal numerical representation of an Unicode codepoint: á * Note that XML only allows lower-case 'x' for defining hexadecimal character entity references (in contrast * with HTML, which allows both '&#x...;' and '&#X...;'). * * Unicode Codepoint * Each of the int values conforming the Unicode code space. * Normally corresponding to a Java char primitive value (codepoint <= \uFFFF), * but might be two chars for codepoints \u10000 to \u10FFFF if the first char is a high * surrogate (\uD800 to \uDBFF) and the second is a low surrogate (\uDC00 to \uDFFF). * See: http://www.oracle.com/technetwork/articles/javase/supplementary-142654.html * */ /* * Prefixes and suffix defined for use in decimal/hexa escape and unescape. */ private static final char REFERENCE_PREFIX = '&'; private static final char REFERENCE_NUMERIC_PREFIX2 = '#'; private static final char REFERENCE_HEXA_PREFIX3 = 'x'; private static final char[] REFERENCE_DECIMAL_PREFIX = "&#".toCharArray(); private static final char[] REFERENCE_HEXA_PREFIX = "&#x".toCharArray(); private static final char REFERENCE_SUFFIX = ';'; /* * Small utility char arrays for hexadecimal conversion. * Even if XML does not allow a lower-case 'x' for specifying hexadecimal entity references, it does not * force hexadecimal digits themselves to be lower-case. */ private static char[] HEXA_CHARS_UPPER = "0123456789ABCDEF".toCharArray(); private static char[] HEXA_CHARS_LOWER = "0123456789abcdef".toCharArray(); private XmlEscapeUtil() { super(); } /* * Perform an escape operation, based on String, according to the specified level and type. */ static String escape(final String text, final XmlEscapeSymbols symbols, final XmlEscapeType escapeType, final XmlEscapeLevel escapeLevel) { if (text == null) { return null; } final int level = escapeLevel.getEscapeLevel(); final boolean useCERs = escapeType.getUseCERs(); final boolean useHexa = escapeType.getUseHexa(); StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); boolean codepointValid = symbols.CODEPOINT_VALIDATOR.isValid(codepoint); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (XmlEscapeSymbols.LEVELS_LEN - 2) && level < symbols.ESCAPE_LEVELS[codepoint] && codepointValid) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (XmlEscapeSymbols.LEVELS_LEN - 2) && level < symbols.ESCAPE_LEVELS[XmlEscapeSymbols.LEVELS_LEN - 1] && codepointValid) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 20); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * If the char is invalid, there is nothing to write, simply skip it (which we already did by * incrementing the readOffset. */ if (!codepointValid) { continue; } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs. * * ----------------------------------------------------------------------------------------- */ if (useCERs) { // We will try to use a CER final int codepointIndex = Arrays.binarySearch(symbols.SORTED_CODEPOINTS, codepoint); if (codepointIndex >= 0) { // CER found! just write it and go for the next char strBuilder.append(symbols.SORTED_CERS_BY_CODEPOINT[codepointIndex]); continue; } } /* * No NCR-escape was possible (or allowed), so we need decimal/hexa escape. */ if (useHexa) { strBuilder.append(REFERENCE_HEXA_PREFIX); strBuilder.append(Integer.toHexString(codepoint)); } else { strBuilder.append(REFERENCE_DECIMAL_PREFIX); strBuilder.append(String.valueOf(codepoint)); } strBuilder.append(REFERENCE_SUFFIX); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no escape was actually needed. Otherwise * append the remaining unescaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an escape operation, based on a Reader, according to the specified level and type and writing the * result to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void escape( final Reader reader, final Writer writer, final XmlEscapeSymbols symbols, final XmlEscapeType escapeType, final XmlEscapeLevel escapeLevel) throws IOException { if (reader == null) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useCERs = escapeType.getUseCERs(); final boolean useHexa = escapeType.getUseHexa(); int c1, c2; // c0: last char, c1: current char, c2: next char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); final int codepoint = codePointAt((char)c1, (char)c2); boolean codepointValid = symbols.CODEPOINT_VALIDATOR.isValid(codepoint); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (XmlEscapeSymbols.LEVELS_LEN - 2) && level < symbols.ESCAPE_LEVELS[codepoint] && codepointValid) { writer.write(c1); continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (XmlEscapeSymbols.LEVELS_LEN - 2) && level < symbols.ESCAPE_LEVELS[XmlEscapeSymbols.LEVELS_LEN - 1] && codepointValid) { writer.write(c1); if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. writer.write(c2); c1 = c2; c2 = reader.read(); } continue; } /* * We know we need to escape, so from here on we will only work with the codepoint -- we can advance * the chars. */ if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char positions with a single codepoint. c1 = c2; c2 = reader.read(); } /* * If the char is invalid, there is nothing to write, simply skip it (which we already did by * incrementing the readOffset. */ if (!codepointValid) { // nothing to write continue; } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs. * * ----------------------------------------------------------------------------------------- */ if (useCERs) { // We will try to use a CER final int codepointIndex = Arrays.binarySearch(symbols.SORTED_CODEPOINTS, codepoint); if (codepointIndex >= 0) { // CER found! just write it and go for the next char writer.write(symbols.SORTED_CERS_BY_CODEPOINT[codepointIndex]); continue; } } /* * No NCR-escape was possible (or allowed), so we need decimal/hexa escape. */ if (useHexa) { writer.write(REFERENCE_HEXA_PREFIX); writer.write(Integer.toHexString(codepoint)); } else { writer.write(REFERENCE_DECIMAL_PREFIX); writer.write(String.valueOf(codepoint)); } writer.write(REFERENCE_SUFFIX); } } /* * Perform an escape operation, based on char[], according to the specified level and type. */ static void escape(final char[] text, final int offset, final int len, final Writer writer, final XmlEscapeSymbols symbols, final XmlEscapeType escapeType, final XmlEscapeLevel escapeLevel) throws IOException { if (text == null || text.length == 0) { return; } final int level = escapeLevel.getEscapeLevel(); final boolean useCERs = escapeType.getUseCERs(); final boolean useHexa = escapeType.getUseHexa(); final int max = (offset + len); int readOffset = offset; for (int i = offset; i < max; i++) { final int codepoint = Character.codePointAt(text, i); boolean codepointValid = symbols.CODEPOINT_VALIDATOR.isValid(codepoint); /* * Shortcut: most characters will be ASCII/Alphanumeric, and we won't need to do anything at * all for them */ if (codepoint <= (XmlEscapeSymbols.LEVELS_LEN - 2) && level < symbols.ESCAPE_LEVELS[codepoint] && codepointValid) { continue; } /* * Shortcut: we might not want to escape non-ASCII chars at all either. */ if (codepoint > (XmlEscapeSymbols.LEVELS_LEN - 2) && level < symbols.ESCAPE_LEVELS[XmlEscapeSymbols.LEVELS_LEN - 1] && codepointValid) { if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually reading two char[] positions with a single codepoint. i++; } continue; } /* * At this point we know for sure we will need some kind of escape, so we * can write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } if (Character.charCount(codepoint) > 1) { // This is to compensate that we are actually escaping two char[] positions with a single codepoint. i++; } readOffset = i + 1; /* * If the char is invalid, there is nothing to write, simply skip it (which we already did by * incrementing the readOffset. */ if (!codepointValid) { continue; } /* * ----------------------------------------------------------------------------------------- * * Perform the real escape, attending the different combinations of NCR, DCR and HCR needs. * * ----------------------------------------------------------------------------------------- */ if (useCERs) { // We will try to use a CER final int codepointIndex = Arrays.binarySearch(symbols.SORTED_CODEPOINTS, codepoint); if (codepointIndex >= 0) { // CER found! just write it and go for the next char writer.write(symbols.SORTED_CERS_BY_CODEPOINT[codepointIndex]); continue; } } /* * No NCR-escape was possible (or allowed), so we need decimal/hexa escape. */ if (useHexa) { writer.write(REFERENCE_HEXA_PREFIX); writer.write(Integer.toHexString(codepoint)); } else { writer.write(REFERENCE_DECIMAL_PREFIX); writer.write(String.valueOf(codepoint)); } writer.write(REFERENCE_SUFFIX); } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: append the remaining unescaped text to the writer and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } /* * This methods (the two versions) are used instead of Integer.parseInt(str,radix) in order to avoid the need * to create substrings of the text being unescaped to feed such method. * - No need to check all chars are within the radix limits - reference parsing code will already have done so. */ static int parseIntFromReference(final String text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text.charAt(i); int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } static int parseIntFromReference(final char[] text, final int start, final int end, final int radix) { int result = 0; for (int i = start; i < end; i++) { final char c = text[i]; int n = -1; for (int j = 0; j < HEXA_CHARS_UPPER.length; j++) { if (c == HEXA_CHARS_UPPER[j] || c == HEXA_CHARS_LOWER[j]) { n = j; break; } } result = (radix * result) + n; } return result; } /* * Perform an unescape operation based on String. */ static String unescape(final String text, final XmlEscapeSymbols symbols) { if (text == null) { return null; } StringBuilder strBuilder = null; final int offset = 0; final int max = text.length(); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text.charAt(i); /* * Check the need for an unescape operation at this point */ if (c != REFERENCE_PREFIX || (i + 1) >= max) { continue; } int codepoint = 0; if (c == REFERENCE_PREFIX) { final char c1 = text.charAt(i + 1); if (c1 == '\u0020' || // SPACE c1 == '\n' || // LF c1 == '\u0009' || // TAB c1 == '\u000C' || // FF c1 == '\u003C' || // LES-THAN SIGN c1 == '\u0026') { // AMPERSAND // Not a character references. No characters are consumed, and nothing is returned. continue; } else if (c1 == REFERENCE_NUMERIC_PREFIX2) { if (i + 2 >= max) { // No reference possible continue; } final char c2 = text.charAt(i + 2); if (c2 == REFERENCE_HEXA_PREFIX3 && (i + 3) < max) { // This is a hexadecimal reference int f = i + 3; while (f < max) { final char cf = text.charAt(f); if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 3)) <= 0) { // We weren't able to consume any hexa chars continue; } if ((f >= max) || text.charAt(f) != REFERENCE_SUFFIX) { continue; } f++; // Count the REFERENCE_SUFFIX (semi-colon) codepoint = parseIntFromReference(text, i + 3, f - 1, 16); referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else if (c2 >= '0' && c2 <= '9') { // This is a decimal reference int f = i + 2; while (f < max) { final char cf = text.charAt(f); if (!(cf >= '0' && cf <= '9')) { break; } f++; } if ((f - (i + 2)) <= 0) { // We weren't able to consume any decimal chars continue; } if ((f >= max) || text.charAt(f) != REFERENCE_SUFFIX) { continue; } f++; // Count the REFERENCE_SUFFIX (semi-colon) codepoint = parseIntFromReference(text, i + 2, f - 1, 10); referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // This is not a valid reference, just discard continue; } } else { // This is a named reference, must be comprised only of ALPHABETIC chars int f = i + 1; while (f < max) { final char cf = text.charAt(f); if (!((cf >= 'a' && cf <= 'z') || (cf >= 'A' && cf <= 'Z') || (cf >= '0' && cf <= '9'))) { break; } f++; } if ((f - (i + 1)) <= 0) { // We weren't able to consume any alphanumeric continue; } if ((f < max) && text.charAt(f) == REFERENCE_SUFFIX) { f++; } final int ncrPosition = XmlEscapeSymbols.binarySearch(symbols.SORTED_CERS, text, i, f); if (ncrPosition >= 0) { codepoint = symbols.SORTED_CODEPOINTS_BY_CER[ncrPosition]; } else { // Not found! Just ignore our efforts to find a match. continue; } referenceOffset = f - 1; } } /* * At this point we know for sure we will need some kind of unescape, so we * can increase the offset and initialize the string builder if needed, along with * copying to it all the contents pending up to this point. */ if (strBuilder == null) { strBuilder = new StringBuilder(max + 5); } if (i - readOffset > 0) { strBuilder.append(text, readOffset, i); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { strBuilder.append(Character.toChars(codepoint)); } else { strBuilder.append((char)codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: return the original String object if no unescape was actually needed. Otherwise * append the remaining escaped text to the string builder and return. * ----------------------------------------------------------------------------------------------- */ if (strBuilder == null) { return text; } if (max - readOffset > 0) { strBuilder.append(text, readOffset, max); } return strBuilder.toString(); } /* * Perform an unescape operation based on a Reader, writing the results to a Writer. * * Note this reader is going to be read char-by-char, so some kind of buffering might be appropriate if this * is an inconvenience for the specific Reader implementation. */ static void unescape(final Reader reader, final Writer writer, final XmlEscapeSymbols symbols) throws IOException { if (reader == null) { return; } char[] escapes = new char[10]; int escapei = 0; int c1, c2, ce; // c1: current char, c2: next char, ce: current escaped char c2 = reader.read(); while (c2 >= 0) { c1 = c2; c2 = reader.read(); escapei = 0; /* * Check the need for an unescape operation at this point */ if (c1 != REFERENCE_PREFIX || c2 < 0) { writer.write(c1); continue; } int codepoint = 0; if (c1 == REFERENCE_PREFIX) { if (c2 == '\u0020' || // SPACE c2 == '\n' || // LF c2 == '\u0009' || // TAB c2 == '\u000C' || // FF c2 == '\u003C' || // LES-THAN SIGN c2 == '\u0026') { // AMPERSAND // Not a character references. No characters are consumed, and nothing is returned. writer.write(c1); continue; } else if (c2 == REFERENCE_NUMERIC_PREFIX2) { final int c3 = reader.read(); if (c3 < 0) { // No reference possible writer.write(c1); writer.write(c2); c1 = c2; c2 = c3; continue; } if (c3 == REFERENCE_HEXA_PREFIX3) { // This is a hexadecimal reference ce = reader.read(); while (ce >= 0) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'F') || (ce >= 'a' && ce <= 'f'))) { break; } if (escapei == escapes.length) { // too many escape chars for our array: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei == 0) { // We weren't able to consume any hexa chars writer.write(c1); writer.write(c2); writer.write(c3); c1 = c3; c2 = ce; continue; } if (ce != REFERENCE_SUFFIX) { // If the reference does not end in a ';', it's not a valid reference writer.write(c1); writer.write(c2); writer.write(c3); writer.write(escapes, 0, escapei); c1 = escapes[escapei - 1]; c2 = ce; continue; } c1 = ce; c2 = reader.read(); codepoint = parseIntFromReference(escapes, 0, escapei, 16); // Don't continue here, just let the unescape code below do its job } else if (c3 >= '0' && c3 <= '9') { // This is a decimal reference ce = c3; while (ce >= 0) { if (!(ce >= '0' && ce <= '9')) { break; } if (escapei == escapes.length) { // too many escape chars for our array: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei == 0) { // We weren't able to consume any decimal chars writer.write(c1); writer.write(c2); c1 = c2; c2 = c3; continue; } if (ce != REFERENCE_SUFFIX) { // If the reference does not end in a ';', it's not a valid reference writer.write(c1); writer.write(c2); writer.write(escapes, 0, escapei); c1 = escapes[escapei - 1]; c2 = ce; continue; } c1 = ce; c2 = reader.read(); codepoint = parseIntFromReference(escapes, 0, escapei, 10); // Don't continue here, just let the unescape code below do its job } else { // This is not a valid reference, just discard writer.write(c1); writer.write(c2); c1 = c2; c2 = c3; continue; } } else { // This is a named reference, must be comprised only of ALPHABETIC chars ce = c2; while (ce >= 0) { if (!((ce >= '0' && ce <= '9') || (ce >= 'A' && ce <= 'Z') || (ce >= 'a' && ce <= 'z'))) { break; } if (escapei == escapes.length) { // too many escape chars for our array: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } escapes[escapei] = (char) ce; ce = reader.read(); escapei++; } if (escapei == 0) { // We weren't able to consume any decimal chars writer.write(c1); continue; } if (escapei + 2 >= escapes.length) { // the entire escape sequence does not fit: grow it! final char[] newEscapes = new char[escapes.length + 4]; System.arraycopy(escapes, 0, newEscapes, 0, escapes.length); escapes = newEscapes; } System.arraycopy(escapes, 0, escapes, 1, escapei); escapes[0] = (char) c1; escapei++; if (ce == REFERENCE_SUFFIX) { // If the reference ends in a ';', just consume it escapes[escapei++] = (char) ce; ce = reader.read(); } c1 = escapes[escapei - 1]; c2 = ce; final int ncrPosition = XmlEscapeSymbols.binarySearch(symbols.SORTED_CERS, escapes, 0, escapei); if (ncrPosition >= 0) { codepoint = symbols.SORTED_CODEPOINTS_BY_CER[ncrPosition]; } else { // Not found! Just ignore our efforts to find a match. writer.write(escapes, 0, escapei); continue; } } } /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char)codepoint); } } } /* * Perform an unescape operation based on char[]. */ static void unescape(final char[] text, final int offset, final int len, final Writer writer, final XmlEscapeSymbols symbols) throws IOException { if (text == null) { return; } final int max = (offset + len); int readOffset = offset; int referenceOffset = offset; for (int i = offset; i < max; i++) { final char c = text[i]; /* * Check the need for an unescape operation at this point */ if (c != REFERENCE_PREFIX || (i + 1) >= max) { continue; } int codepoint = 0; if (c == REFERENCE_PREFIX) { final char c1 = text[i + 1]; if (c1 == '\u0020' || // SPACE c1 == '\n' || // LF c1 == '\u0009' || // TAB c1 == '\u000C' || // FF c1 == '\u003C' || // LES-THAN SIGN c1 == '\u0026') { // AMPERSAND // Not a character references. No characters are consumed, and nothing is returned. continue; } else if (c1 == REFERENCE_NUMERIC_PREFIX2) { if (i + 2 >= max) { // No reference possible continue; } final char c2 = text[i + 2]; if (c2 == REFERENCE_HEXA_PREFIX3 && (i + 3) < max) { // This is a hexadecimal reference int f = i + 3; while (f < max) { final char cf = text[f]; if (!((cf >= '0' && cf <= '9') || (cf >= 'A' && cf <= 'F') || (cf >= 'a' && cf <= 'f'))) { break; } f++; } if ((f - (i + 3)) <= 0) { // We weren't able to consume any hexa chars continue; } if ((f >= max) || text[f] != REFERENCE_SUFFIX) { continue; } f++; // Count the REFERENCE_SUFFIX (semi-colon) codepoint = parseIntFromReference(text, i + 3, f - 1, 16); referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else if (c2 >= '0' && c2 <= '9') { // This is a decimal reference int f = i + 2; while (f < max) { final char cf = text[f]; if (!(cf >= '0' && cf <= '9')) { break; } f++; } if ((f - (i + 2)) <= 0) { // We weren't able to consume any decimal chars continue; } if ((f >= max) || text[f] != REFERENCE_SUFFIX) { continue; } f++; // Count the REFERENCE_SUFFIX (semi-colon) codepoint = parseIntFromReference(text, i + 2, f - 1, 10); referenceOffset = f - 1; // Don't continue here, just let the unescape code below do its job } else { // This is not a valid reference, just discard continue; } } else { // This is a named reference, must be comprised only of ALPHABETIC chars int f = i + 1; while (f < max) { final char cf = text[f]; if (!((cf >= 'a' && cf <= 'z') || (cf >= 'A' && cf <= 'Z') || (cf >= '0' && cf <= '9'))) { break; } f++; } if ((f - (i + 1)) <= 0) { // We weren't able to consume any alphanumeric continue; } if ((f < max) && text[f] == REFERENCE_SUFFIX) { f++; } final int ncrPosition = XmlEscapeSymbols.binarySearch(symbols.SORTED_CERS, text, i, f); if (ncrPosition >= 0) { codepoint = symbols.SORTED_CODEPOINTS_BY_CER[ncrPosition]; } else { // Not found! Just ignore our efforts to find a match. continue; } referenceOffset = f - 1; } } /* * At this point we know for sure we will need some kind of unescape, so we * write all the contents pending up to this point. */ if (i - readOffset > 0) { writer.write(text, readOffset, (i - readOffset)); } i = referenceOffset; readOffset = i + 1; /* * -------------------------- * * Perform the real unescape * * -------------------------- */ if (codepoint > '\uFFFF') { writer.write(Character.toChars(codepoint)); } else { writer.write((char) codepoint); } } /* * ----------------------------------------------------------------------------------------------- * Final cleaning: writer the remaining escaped text and return. * ----------------------------------------------------------------------------------------------- */ if (max - readOffset > 0) { writer.write(text, readOffset, (max - readOffset)); } } private static int codePointAt(final char c1, final char c2) { if (Character.isHighSurrogate(c1)) { if (c2 >= 0) { if (Character.isLowSurrogate(c2)) { return Character.toCodePoint(c1, c2); } } } return c1; } } unbescape-unbescape-1.1.5.RELEASE/src/site/000077500000000000000000000000001311410233600202325ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/site/contributing.html000066400000000000000000000121201311410233600236230ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java
In order to contribute to Unbescape, please make sure you read and understand the Unbescape Contributing Terms and Conditions. You will be asked to explicitly accept these before any of your contributions are merged into the project.

unbescape-unbescape-1.1.5.RELEASE/src/site/css/000077500000000000000000000000001311410233600210225ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/site/css/bootstrap-responsive.css000066400000000000000000000510071311410233600257470ustar00rootroot00000000000000/*! * Bootstrap Responsive v2.1.1 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */ .clearfix { *zoom: 1; } .clearfix:before, .clearfix:after { display: table; line-height: 0; content: ""; } .clearfix:after { clear: both; } .hide-text { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; } .input-block-level { display: block; width: 100%; min-height: 30px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .hidden { display: none; visibility: hidden; } .visible-phone { display: none !important; } .visible-tablet { display: none !important; } .hidden-desktop { display: none !important; } .visible-desktop { display: inherit !important; } @media (min-width: 768px) and (max-width: 979px) { .hidden-desktop { display: inherit !important; } .visible-desktop { display: none !important ; } .visible-tablet { display: inherit !important; } .hidden-tablet { display: none !important; } } @media (max-width: 767px) { .hidden-desktop { display: inherit !important; } .visible-desktop { display: none !important; } .visible-phone { display: inherit !important; } .hidden-phone { display: none !important; } } @media (min-width: 1200px) { .row { margin-left: -30px; *zoom: 1; } .row:before, .row:after { display: table; line-height: 0; content: ""; } .row:after { clear: both; } [class*="span"] { float: left; min-height: 1px; margin-left: 30px; } .container, .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 1170px; } .span12 { width: 1170px; } .span11 { width: 1070px; } .span10 { width: 970px; } .span9 { width: 870px; } .span8 { width: 770px; } .span7 { width: 670px; } .span6 { width: 570px; } .span5 { width: 470px; } .span4 { width: 370px; } .span3 { width: 270px; } .span2 { width: 170px; } .span1 { width: 70px; } .offset12 { margin-left: 1230px; } .offset11 { margin-left: 1130px; } .offset10 { margin-left: 1030px; } .offset9 { margin-left: 930px; } .offset8 { margin-left: 830px; } .offset7 { margin-left: 730px; } .offset6 { margin-left: 630px; } .offset5 { margin-left: 530px; } .offset4 { margin-left: 430px; } .offset3 { margin-left: 330px; } .offset2 { margin-left: 230px; } .offset1 { margin-left: 130px; } .row-fluid { width: 100%; *zoom: 1; } .row-fluid:before, .row-fluid:after { display: table; line-height: 0; content: ""; } .row-fluid:after { clear: both; } .row-fluid [class*="span"] { display: block; float: left; width: 100%; min-height: 30px; margin-left: 2.564102564102564%; *margin-left: 2.5109110747408616%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .row-fluid [class*="span"]:first-child { margin-left: 0; } .row-fluid .span12 { width: 100%; *width: 99.94680851063829%; } .row-fluid .span11 { width: 91.45299145299145%; *width: 91.39979996362975%; } .row-fluid .span10 { width: 82.90598290598291%; *width: 82.8527914166212%; } .row-fluid .span9 { width: 74.35897435897436%; *width: 74.30578286961266%; } .row-fluid .span8 { width: 65.81196581196582%; *width: 65.75877432260411%; } .row-fluid .span7 { width: 57.26495726495726%; *width: 57.21176577559556%; } .row-fluid .span6 { width: 48.717948717948715%; *width: 48.664757228587014%; } .row-fluid .span5 { width: 40.17094017094017%; *width: 40.11774868157847%; } .row-fluid .span4 { width: 31.623931623931625%; *width: 31.570740134569924%; } .row-fluid .span3 { width: 23.076923076923077%; *width: 23.023731587561375%; } .row-fluid .span2 { width: 14.52991452991453%; *width: 14.476723040552828%; } .row-fluid .span1 { width: 5.982905982905983%; *width: 5.929714493544281%; } .row-fluid .offset12 { margin-left: 105.12820512820512%; *margin-left: 105.02182214948171%; } .row-fluid .offset12:first-child { margin-left: 102.56410256410257%; *margin-left: 102.45771958537915%; } .row-fluid .offset11 { margin-left: 96.58119658119658%; *margin-left: 96.47481360247316%; } .row-fluid .offset11:first-child { margin-left: 94.01709401709402%; *margin-left: 93.91071103837061%; } .row-fluid .offset10 { margin-left: 88.03418803418803%; *margin-left: 87.92780505546462%; } .row-fluid .offset10:first-child { margin-left: 85.47008547008548%; *margin-left: 85.36370249136206%; } .row-fluid .offset9 { margin-left: 79.48717948717949%; *margin-left: 79.38079650845607%; } .row-fluid .offset9:first-child { margin-left: 76.92307692307693%; *margin-left: 76.81669394435352%; } .row-fluid .offset8 { margin-left: 70.94017094017094%; *margin-left: 70.83378796144753%; } .row-fluid .offset8:first-child { margin-left: 68.37606837606839%; *margin-left: 68.26968539734497%; } .row-fluid .offset7 { margin-left: 62.393162393162385%; *margin-left: 62.28677941443899%; } .row-fluid .offset7:first-child { margin-left: 59.82905982905982%; *margin-left: 59.72267685033642%; } .row-fluid .offset6 { margin-left: 53.84615384615384%; *margin-left: 53.739770867430444%; } .row-fluid .offset6:first-child { margin-left: 51.28205128205128%; *margin-left: 51.175668303327875%; } .row-fluid .offset5 { margin-left: 45.299145299145295%; *margin-left: 45.1927623204219%; } .row-fluid .offset5:first-child { margin-left: 42.73504273504273%; *margin-left: 42.62865975631933%; } .row-fluid .offset4 { margin-left: 36.75213675213675%; *margin-left: 36.645753773413354%; } .row-fluid .offset4:first-child { margin-left: 34.18803418803419%; *margin-left: 34.081651209310785%; } .row-fluid .offset3 { margin-left: 28.205128205128204%; *margin-left: 28.0987452264048%; } .row-fluid .offset3:first-child { margin-left: 25.641025641025642%; *margin-left: 25.53464266230224%; } .row-fluid .offset2 { margin-left: 19.65811965811966%; *margin-left: 19.551736679396257%; } .row-fluid .offset2:first-child { margin-left: 17.094017094017094%; *margin-left: 16.98763411529369%; } .row-fluid .offset1 { margin-left: 11.11111111111111%; *margin-left: 11.004728132387708%; } .row-fluid .offset1:first-child { margin-left: 8.547008547008547%; *margin-left: 8.440625568285142%; } input, textarea, .uneditable-input { margin-left: 0; } .controls-row [class*="span"] + [class*="span"] { margin-left: 30px; } input.span12, textarea.span12, .uneditable-input.span12 { width: 1156px; } input.span11, textarea.span11, .uneditable-input.span11 { width: 1056px; } input.span10, textarea.span10, .uneditable-input.span10 { width: 956px; } input.span9, textarea.span9, .uneditable-input.span9 { width: 856px; } input.span8, textarea.span8, .uneditable-input.span8 { width: 756px; } input.span7, textarea.span7, .uneditable-input.span7 { width: 656px; } input.span6, textarea.span6, .uneditable-input.span6 { width: 556px; } input.span5, textarea.span5, .uneditable-input.span5 { width: 456px; } input.span4, textarea.span4, .uneditable-input.span4 { width: 356px; } input.span3, textarea.span3, .uneditable-input.span3 { width: 256px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 156px; } input.span1, textarea.span1, .uneditable-input.span1 { width: 56px; } .thumbnails { margin-left: -30px; } .thumbnails > li { margin-left: 30px; } .row-fluid .thumbnails { margin-left: 0; } } @media (min-width: 768px) and (max-width: 979px) { .row { margin-left: -20px; *zoom: 1; } .row:before, .row:after { display: table; line-height: 0; content: ""; } .row:after { clear: both; } [class*="span"] { float: left; min-height: 1px; margin-left: 20px; } .container, .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 724px; } .span12 { width: 724px; } .span11 { width: 662px; } .span10 { width: 600px; } .span9 { width: 538px; } .span8 { width: 476px; } .span7 { width: 414px; } .span6 { width: 352px; } .span5 { width: 290px; } .span4 { width: 228px; } .span3 { width: 166px; } .span2 { width: 104px; } .span1 { width: 42px; } .offset12 { margin-left: 764px; } .offset11 { margin-left: 702px; } .offset10 { margin-left: 640px; } .offset9 { margin-left: 578px; } .offset8 { margin-left: 516px; } .offset7 { margin-left: 454px; } .offset6 { margin-left: 392px; } .offset5 { margin-left: 330px; } .offset4 { margin-left: 268px; } .offset3 { margin-left: 206px; } .offset2 { margin-left: 144px; } .offset1 { margin-left: 82px; } .row-fluid { width: 100%; *zoom: 1; } .row-fluid:before, .row-fluid:after { display: table; line-height: 0; content: ""; } .row-fluid:after { clear: both; } .row-fluid [class*="span"] { display: block; float: left; width: 100%; min-height: 30px; margin-left: 2.7624309392265194%; *margin-left: 2.709239449864817%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .row-fluid [class*="span"]:first-child { margin-left: 0; } .row-fluid .span12 { width: 100%; *width: 99.94680851063829%; } .row-fluid .span11 { width: 91.43646408839778%; *width: 91.38327259903608%; } .row-fluid .span10 { width: 82.87292817679558%; *width: 82.81973668743387%; } .row-fluid .span9 { width: 74.30939226519337%; *width: 74.25620077583166%; } .row-fluid .span8 { width: 65.74585635359117%; *width: 65.69266486422946%; } .row-fluid .span7 { width: 57.18232044198895%; *width: 57.12912895262725%; } .row-fluid .span6 { width: 48.61878453038674%; *width: 48.56559304102504%; } .row-fluid .span5 { width: 40.05524861878453%; *width: 40.00205712942283%; } .row-fluid .span4 { width: 31.491712707182323%; *width: 31.43852121782062%; } .row-fluid .span3 { width: 22.92817679558011%; *width: 22.87498530621841%; } .row-fluid .span2 { width: 14.3646408839779%; *width: 14.311449394616199%; } .row-fluid .span1 { width: 5.801104972375691%; *width: 5.747913483013988%; } .row-fluid .offset12 { margin-left: 105.52486187845304%; *margin-left: 105.41847889972962%; } .row-fluid .offset12:first-child { margin-left: 102.76243093922652%; *margin-left: 102.6560479605031%; } .row-fluid .offset11 { margin-left: 96.96132596685082%; *margin-left: 96.8549429881274%; } .row-fluid .offset11:first-child { margin-left: 94.1988950276243%; *margin-left: 94.09251204890089%; } .row-fluid .offset10 { margin-left: 88.39779005524862%; *margin-left: 88.2914070765252%; } .row-fluid .offset10:first-child { margin-left: 85.6353591160221%; *margin-left: 85.52897613729868%; } .row-fluid .offset9 { margin-left: 79.8342541436464%; *margin-left: 79.72787116492299%; } .row-fluid .offset9:first-child { margin-left: 77.07182320441989%; *margin-left: 76.96544022569647%; } .row-fluid .offset8 { margin-left: 71.2707182320442%; *margin-left: 71.16433525332079%; } .row-fluid .offset8:first-child { margin-left: 68.50828729281768%; *margin-left: 68.40190431409427%; } .row-fluid .offset7 { margin-left: 62.70718232044199%; *margin-left: 62.600799341718584%; } .row-fluid .offset7:first-child { margin-left: 59.94475138121547%; *margin-left: 59.838368402492065%; } .row-fluid .offset6 { margin-left: 54.14364640883978%; *margin-left: 54.037263430116376%; } .row-fluid .offset6:first-child { margin-left: 51.38121546961326%; *margin-left: 51.27483249088986%; } .row-fluid .offset5 { margin-left: 45.58011049723757%; *margin-left: 45.47372751851417%; } .row-fluid .offset5:first-child { margin-left: 42.81767955801105%; *margin-left: 42.71129657928765%; } .row-fluid .offset4 { margin-left: 37.01657458563536%; *margin-left: 36.91019160691196%; } .row-fluid .offset4:first-child { margin-left: 34.25414364640884%; *margin-left: 34.14776066768544%; } .row-fluid .offset3 { margin-left: 28.45303867403315%; *margin-left: 28.346655695309746%; } .row-fluid .offset3:first-child { margin-left: 25.69060773480663%; *margin-left: 25.584224756083227%; } .row-fluid .offset2 { margin-left: 19.88950276243094%; *margin-left: 19.783119783707537%; } .row-fluid .offset2:first-child { margin-left: 17.12707182320442%; *margin-left: 17.02068884448102%; } .row-fluid .offset1 { margin-left: 11.32596685082873%; *margin-left: 11.219583872105325%; } .row-fluid .offset1:first-child { margin-left: 8.56353591160221%; *margin-left: 8.457152932878806%; } input, textarea, .uneditable-input { margin-left: 0; } .controls-row [class*="span"] + [class*="span"] { margin-left: 20px; } input.span12, textarea.span12, .uneditable-input.span12 { width: 710px; } input.span11, textarea.span11, .uneditable-input.span11 { width: 648px; } input.span10, textarea.span10, .uneditable-input.span10 { width: 586px; } input.span9, textarea.span9, .uneditable-input.span9 { width: 524px; } input.span8, textarea.span8, .uneditable-input.span8 { width: 462px; } input.span7, textarea.span7, .uneditable-input.span7 { width: 400px; } input.span6, textarea.span6, .uneditable-input.span6 { width: 338px; } input.span5, textarea.span5, .uneditable-input.span5 { width: 276px; } input.span4, textarea.span4, .uneditable-input.span4 { width: 214px; } input.span3, textarea.span3, .uneditable-input.span3 { width: 152px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 90px; } input.span1, textarea.span1, .uneditable-input.span1 { width: 28px; } } @media (max-width: 767px) { body { padding-right: 20px; padding-left: 20px; } .navbar-fixed-top, .navbar-fixed-bottom, .navbar-static-top { margin-right: -20px; margin-left: -20px; } .container-fluid { padding: 0; } .dl-horizontal dt { float: none; width: auto; clear: none; text-align: left; } .dl-horizontal dd { margin-left: 0; } .container { width: auto; } .row-fluid { width: 100%; } .row, .thumbnails { margin-left: 0; } .thumbnails > li { float: none; margin-left: 0; } [class*="span"], .row-fluid [class*="span"] { display: block; float: none; width: 100%; margin-left: 0; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .span12, .row-fluid .span12 { width: 100%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .input-large, .input-xlarge, .input-xxlarge, input[class*="span"], select[class*="span"], textarea[class*="span"], .uneditable-input { display: block; width: 100%; min-height: 30px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .input-prepend input, .input-append input, .input-prepend input[class*="span"], .input-append input[class*="span"] { display: inline-block; width: auto; } .controls-row [class*="span"] + [class*="span"] { margin-left: 0; } .modal { position: fixed; top: 20px; right: 20px; left: 20px; width: auto; margin: 0; } .modal.fade.in { top: auto; } } @media (max-width: 480px) { .nav-collapse { -webkit-transform: translate3d(0, 0, 0); } .page-header h1 small { display: block; line-height: 20px; } input[type="checkbox"], input[type="radio"] { border: 1px solid #ccc; } .form-horizontal .control-label { float: none; width: auto; padding-top: 0; text-align: left; } .form-horizontal .controls { margin-left: 0; } .form-horizontal .control-list { padding-top: 0; } .form-horizontal .form-actions { padding-right: 10px; padding-left: 10px; } .modal { top: 10px; right: 10px; left: 10px; } .modal-header .close { padding: 10px; margin: -10px; } .carousel-caption { position: static; } } @media (max-width: 979px) { body { padding-top: 0; } .navbar-fixed-top, .navbar-fixed-bottom { position: static; } .navbar-fixed-top { margin-bottom: 20px; } .navbar-fixed-bottom { margin-top: 20px; } .navbar-fixed-top .navbar-inner, .navbar-fixed-bottom .navbar-inner { padding: 5px; } .navbar .container { width: auto; padding: 0; } .navbar .brand { padding-right: 10px; padding-left: 10px; margin: 0 0 0 -5px; } .nav-collapse { clear: both; } .nav-collapse .nav { float: none; margin: 0 0 10px; } .nav-collapse .nav > li { float: none; } .nav-collapse .nav > li > a { margin-bottom: 2px; } .nav-collapse .nav > .divider-vertical { display: none; } .nav-collapse .nav .nav-header { color: #777777; text-shadow: none; } .nav-collapse .nav > li > a, .nav-collapse .dropdown-menu a { padding: 9px 15px; font-weight: bold; color: #777777; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .nav-collapse .btn { padding: 4px 10px 4px; font-weight: normal; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .nav-collapse .dropdown-menu li + li a { margin-bottom: 2px; } .nav-collapse .nav > li > a:hover, .nav-collapse .dropdown-menu a:hover { background-color: #f2f2f2; } .navbar-inverse .nav-collapse .nav > li > a:hover, .navbar-inverse .nav-collapse .dropdown-menu a:hover { background-color: #111111; } .nav-collapse.in .btn-group { padding: 0; margin-top: 5px; } .nav-collapse .dropdown-menu { position: static; top: auto; left: auto; display: block; float: none; max-width: none; padding: 0; margin: 0 15px; background-color: transparent; border: none; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } .nav-collapse .dropdown-menu:before, .nav-collapse .dropdown-menu:after { display: none; } .nav-collapse .dropdown-menu .divider { display: none; } .nav-collapse .nav > li > .dropdown-menu:before, .nav-collapse .nav > li > .dropdown-menu:after { display: none; } .nav-collapse .navbar-form, .nav-collapse .navbar-search { float: none; padding: 10px 15px; margin: 10px 0; border-top: 1px solid #f2f2f2; border-bottom: 1px solid #f2f2f2; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); } .navbar-inverse .nav-collapse .navbar-form, .navbar-inverse .nav-collapse .navbar-search { border-top-color: #111111; border-bottom-color: #111111; } .navbar .nav-collapse .nav.pull-right { float: none; margin-left: 0; } .nav-collapse, .nav-collapse.collapse { height: 0; overflow: hidden; } .navbar .btn-navbar { display: block; } .navbar-static .navbar-inner { padding-right: 10px; padding-left: 10px; } } @media (min-width: 980px) { .nav-collapse.collapse { height: auto !important; overflow: visible !important; } } unbescape-unbescape-1.1.5.RELEASE/src/site/css/bootstrap-responsive.min.css000066400000000000000000000371321311410233600265340ustar00rootroot00000000000000/*! * Bootstrap Responsive v2.1.1 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade.in{top:auto}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:block;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} unbescape-unbescape-1.1.5.RELEASE/src/site/css/bootstrap.css000066400000000000000000003465601311410233600235670ustar00rootroot00000000000000/*! * Bootstrap v2.1.1 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */ article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { display: block; } audio, canvas, video { display: inline-block; *display: inline; *zoom: 1; } audio:not([controls]) { display: none; } html { font-size: 100%; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } a:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } a:hover, a:active { outline: 0; } sub, sup { position: relative; font-size: 75%; line-height: 0; vertical-align: baseline; } sup { top: -0.5em; } sub { bottom: -0.25em; } img { width: auto\9; height: auto; max-width: 100%; vertical-align: middle; border: 0; -ms-interpolation-mode: bicubic; } #map_canvas img { max-width: none; } button, input, select, textarea { margin: 0; font-size: 100%; vertical-align: middle; } button, input { *overflow: visible; line-height: normal; } button::-moz-focus-inner, input::-moz-focus-inner { padding: 0; border: 0; } button, input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } input[type="search"] { -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; -webkit-appearance: textfield; } input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; } textarea { overflow: auto; vertical-align: top; } .clearfix { *zoom: 1; } .clearfix:before, .clearfix:after { display: table; line-height: 0; content: ""; } .clearfix:after { clear: both; } .hide-text { font: 0/0 a; color: transparent; text-shadow: none; background-color: transparent; border: 0; } .input-block-level { display: block; width: 100%; min-height: 30px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } body { margin: 0; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 14px; line-height: 20px; color: #333333; background-color: #ffffff; } a { color: #0088cc; text-decoration: none; } a:hover { color: #005580; text-decoration: underline; } .img-rounded { -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .img-polaroid { padding: 4px; background-color: #fff; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); } .img-circle { -webkit-border-radius: 500px; -moz-border-radius: 500px; border-radius: 500px; } .row { margin-left: -20px; *zoom: 1; } .row:before, .row:after { display: table; line-height: 0; content: ""; } .row:after { clear: both; } [class*="span"] { float: left; min-height: 1px; margin-left: 20px; } .container, .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } .span12 { width: 940px; } .span11 { width: 860px; } .span10 { width: 780px; } .span9 { width: 700px; } .span8 { width: 620px; } .span7 { width: 540px; } .span6 { width: 460px; } .span5 { width: 380px; } .span4 { width: 300px; } .span3 { width: 220px; } .span2 { width: 140px; } .span1 { width: 60px; } .offset12 { margin-left: 980px; } .offset11 { margin-left: 900px; } .offset10 { margin-left: 820px; } .offset9 { margin-left: 740px; } .offset8 { margin-left: 660px; } .offset7 { margin-left: 580px; } .offset6 { margin-left: 500px; } .offset5 { margin-left: 420px; } .offset4 { margin-left: 340px; } .offset3 { margin-left: 260px; } .offset2 { margin-left: 180px; } .offset1 { margin-left: 100px; } .row-fluid { width: 100%; *zoom: 1; } .row-fluid:before, .row-fluid:after { display: table; line-height: 0; content: ""; } .row-fluid:after { clear: both; } .row-fluid [class*="span"] { display: block; float: left; width: 100%; min-height: 30px; margin-left: 2.127659574468085%; *margin-left: 2.074468085106383%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .row-fluid [class*="span"]:first-child { margin-left: 0; } .row-fluid .span12 { width: 100%; *width: 99.94680851063829%; } .row-fluid .span11 { width: 91.48936170212765%; *width: 91.43617021276594%; } .row-fluid .span10 { width: 82.97872340425532%; *width: 82.92553191489361%; } .row-fluid .span9 { width: 74.46808510638297%; *width: 74.41489361702126%; } .row-fluid .span8 { width: 65.95744680851064%; *width: 65.90425531914893%; } .row-fluid .span7 { width: 57.44680851063829%; *width: 57.39361702127659%; } .row-fluid .span6 { width: 48.93617021276595%; *width: 48.88297872340425%; } .row-fluid .span5 { width: 40.42553191489362%; *width: 40.37234042553192%; } .row-fluid .span4 { width: 31.914893617021278%; *width: 31.861702127659576%; } .row-fluid .span3 { width: 23.404255319148934%; *width: 23.351063829787233%; } .row-fluid .span2 { width: 14.893617021276595%; *width: 14.840425531914894%; } .row-fluid .span1 { width: 6.382978723404255%; *width: 6.329787234042553%; } .row-fluid .offset12 { margin-left: 104.25531914893617%; *margin-left: 104.14893617021275%; } .row-fluid .offset12:first-child { margin-left: 102.12765957446808%; *margin-left: 102.02127659574467%; } .row-fluid .offset11 { margin-left: 95.74468085106382%; *margin-left: 95.6382978723404%; } .row-fluid .offset11:first-child { margin-left: 93.61702127659574%; *margin-left: 93.51063829787232%; } .row-fluid .offset10 { margin-left: 87.23404255319149%; *margin-left: 87.12765957446807%; } .row-fluid .offset10:first-child { margin-left: 85.1063829787234%; *margin-left: 84.99999999999999%; } .row-fluid .offset9 { margin-left: 78.72340425531914%; *margin-left: 78.61702127659572%; } .row-fluid .offset9:first-child { margin-left: 76.59574468085106%; *margin-left: 76.48936170212764%; } .row-fluid .offset8 { margin-left: 70.2127659574468%; *margin-left: 70.10638297872339%; } .row-fluid .offset8:first-child { margin-left: 68.08510638297872%; *margin-left: 67.9787234042553%; } .row-fluid .offset7 { margin-left: 61.70212765957446%; *margin-left: 61.59574468085106%; } .row-fluid .offset7:first-child { margin-left: 59.574468085106375%; *margin-left: 59.46808510638297%; } .row-fluid .offset6 { margin-left: 53.191489361702125%; *margin-left: 53.085106382978715%; } .row-fluid .offset6:first-child { margin-left: 51.063829787234035%; *margin-left: 50.95744680851063%; } .row-fluid .offset5 { margin-left: 44.68085106382979%; *margin-left: 44.57446808510638%; } .row-fluid .offset5:first-child { margin-left: 42.5531914893617%; *margin-left: 42.4468085106383%; } .row-fluid .offset4 { margin-left: 36.170212765957444%; *margin-left: 36.06382978723405%; } .row-fluid .offset4:first-child { margin-left: 34.04255319148936%; *margin-left: 33.93617021276596%; } .row-fluid .offset3 { margin-left: 27.659574468085104%; *margin-left: 27.5531914893617%; } .row-fluid .offset3:first-child { margin-left: 25.53191489361702%; *margin-left: 25.425531914893618%; } .row-fluid .offset2 { margin-left: 19.148936170212764%; *margin-left: 19.04255319148936%; } .row-fluid .offset2:first-child { margin-left: 17.02127659574468%; *margin-left: 16.914893617021278%; } .row-fluid .offset1 { margin-left: 10.638297872340425%; *margin-left: 10.53191489361702%; } .row-fluid .offset1:first-child { margin-left: 8.51063829787234%; *margin-left: 8.404255319148938%; } [class*="span"].hide, .row-fluid [class*="span"].hide { display: none; } [class*="span"].pull-right, .row-fluid [class*="span"].pull-right { float: right; } .container { margin-right: auto; margin-left: auto; *zoom: 1; } .container:before, .container:after { display: table; line-height: 0; content: ""; } .container:after { clear: both; } .container-fluid { padding-right: 20px; padding-left: 20px; *zoom: 1; } .container-fluid:before, .container-fluid:after { display: table; line-height: 0; content: ""; } .container-fluid:after { clear: both; } p { margin: 0 0 10px; } .lead { margin-bottom: 20px; font-size: 21px; font-weight: 200; line-height: 30px; } small { font-size: 85%; } strong { font-weight: bold; } em { font-style: italic; } cite { font-style: normal; } .muted { color: #999999; } .text-warning { color: #c09853; } .text-error { color: #b94a48; } .text-info { color: #3a87ad; } .text-success { color: #468847; } h1, h2, h3, h4, h5, h6 { margin: 10px 0; font-family: inherit; font-weight: bold; line-height: 1; color: inherit; text-rendering: optimizelegibility; } h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-weight: normal; line-height: 1; color: #999999; } h1 { font-size: 36px; line-height: 40px; } h2 { font-size: 30px; line-height: 40px; } h3 { font-size: 24px; line-height: 40px; } h4 { font-size: 18px; line-height: 20px; } h5 { font-size: 14px; line-height: 20px; } h6 { font-size: 12px; line-height: 20px; } h1 small { font-size: 24px; } h2 small { font-size: 18px; } h3 small { font-size: 14px; } h4 small { font-size: 14px; } .page-header { padding-bottom: 9px; margin: 20px 0 30px; border-bottom: 1px solid #eeeeee; } ul, ol { padding: 0; margin: 0 0 10px 25px; } ul ul, ul ol, ol ol, ol ul { margin-bottom: 0; } li { line-height: 20px; } ul.unstyled, ol.unstyled { margin-left: 0; list-style: none; } dl { margin-bottom: 20px; } dt, dd { line-height: 20px; } dt { font-weight: bold; } dd { margin-left: 10px; } .dl-horizontal { *zoom: 1; } .dl-horizontal:before, .dl-horizontal:after { display: table; line-height: 0; content: ""; } .dl-horizontal:after { clear: both; } .dl-horizontal dt { float: left; width: 160px; overflow: hidden; clear: left; text-align: right; text-overflow: ellipsis; white-space: nowrap; } .dl-horizontal dd { margin-left: 180px; } hr { margin: 20px 0; border: 0; border-top: 1px solid #eeeeee; border-bottom: 1px solid #ffffff; } abbr[title] { cursor: help; border-bottom: 1px dotted #999999; } abbr.initialism { font-size: 90%; text-transform: uppercase; } blockquote { padding: 0 0 0 15px; margin: 0 0 20px; border-left: 5px solid #eeeeee; } blockquote p { margin-bottom: 0; font-size: 16px; font-weight: 300; line-height: 25px; } blockquote small { display: block; line-height: 20px; color: #999999; } blockquote small:before { content: '\2014 \00A0'; } blockquote.pull-right { float: right; padding-right: 15px; padding-left: 0; border-right: 5px solid #eeeeee; border-left: 0; } blockquote.pull-right p, blockquote.pull-right small { text-align: right; } blockquote.pull-right small:before { content: ''; } blockquote.pull-right small:after { content: '\00A0 \2014'; } q:before, q:after, blockquote:before, blockquote:after { content: ""; } address { display: block; margin-bottom: 20px; font-style: normal; line-height: 20px; } code, pre { padding: 0 3px 2px; font-family: Monaco, Menlo, Consolas, "Courier New", monospace; font-size: 12px; color: #333333; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } code { padding: 2px 4px; color: #d14; background-color: #f7f7f9; border: 1px solid #e1e1e8; } pre { display: block; padding: 9.5px; margin: 0 0 10px; font-size: 13px; line-height: 20px; word-break: break-all; word-wrap: break-word; white-space: pre; white-space: pre-wrap; background-color: #f5f5f5; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.15); -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } pre.prettyprint { margin-bottom: 20px; } pre code { padding: 0; color: inherit; background-color: transparent; border: 0; } .pre-scrollable { max-height: 340px; overflow-y: scroll; } form { margin: 0 0 20px; } fieldset { padding: 0; margin: 0; border: 0; } legend { display: block; width: 100%; padding: 0; margin-bottom: 20px; font-size: 21px; line-height: 40px; color: #333333; border: 0; border-bottom: 1px solid #e5e5e5; } legend small { font-size: 15px; color: #999999; } label, input, button, select, textarea { font-size: 14px; font-weight: normal; line-height: 20px; } input, button, select, textarea { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } label { display: block; margin-bottom: 5px; } select, textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"], .uneditable-input { display: inline-block; height: 20px; padding: 4px 6px; margin-bottom: 9px; font-size: 14px; line-height: 20px; color: #555555; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } input, textarea, .uneditable-input { width: 206px; } textarea { height: auto; } textarea, input[type="text"], input[type="password"], input[type="datetime"], input[type="datetime-local"], input[type="date"], input[type="month"], input[type="time"], input[type="week"], input[type="number"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], input[type="color"], .uneditable-input { background-color: #ffffff; border: 1px solid #cccccc; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; -moz-transition: border linear 0.2s, box-shadow linear 0.2s; -o-transition: border linear 0.2s, box-shadow linear 0.2s; transition: border linear 0.2s, box-shadow linear 0.2s; } textarea:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, .uneditable-input:focus { border-color: rgba(82, 168, 236, 0.8); outline: 0; outline: thin dotted \9; /* IE6-9 */ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); } input[type="radio"], input[type="checkbox"] { margin: 4px 0 0; margin-top: 1px \9; *margin-top: 0; line-height: normal; cursor: pointer; } input[type="file"], input[type="image"], input[type="submit"], input[type="reset"], input[type="button"], input[type="radio"], input[type="checkbox"] { width: auto; } select, input[type="file"] { height: 30px; /* In IE7, the height of the select element cannot be changed by height, only font-size */ *margin-top: 4px; /* For IE7, add top margin to align select with labels */ line-height: 30px; } select { width: 220px; background-color: #ffffff; border: 1px solid #cccccc; } select[multiple], select[size] { height: auto; } select:focus, input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .uneditable-input, .uneditable-textarea { color: #999999; cursor: not-allowed; background-color: #fcfcfc; border-color: #cccccc; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); } .uneditable-input { overflow: hidden; white-space: nowrap; } .uneditable-textarea { width: auto; height: auto; } input:-moz-placeholder, textarea:-moz-placeholder { color: #999999; } input:-ms-input-placeholder, textarea:-ms-input-placeholder { color: #999999; } input::-webkit-input-placeholder, textarea::-webkit-input-placeholder { color: #999999; } .radio, .checkbox { min-height: 18px; padding-left: 18px; } .radio input[type="radio"], .checkbox input[type="checkbox"] { float: left; margin-left: -18px; } .controls > .radio:first-child, .controls > .checkbox:first-child { padding-top: 5px; } .radio.inline, .checkbox.inline { display: inline-block; padding-top: 5px; margin-bottom: 0; vertical-align: middle; } .radio.inline + .radio.inline, .checkbox.inline + .checkbox.inline { margin-left: 10px; } .input-mini { width: 60px; } .input-small { width: 90px; } .input-medium { width: 150px; } .input-large { width: 210px; } .input-xlarge { width: 270px; } .input-xxlarge { width: 530px; } input[class*="span"], select[class*="span"], textarea[class*="span"], .uneditable-input[class*="span"], .row-fluid input[class*="span"], .row-fluid select[class*="span"], .row-fluid textarea[class*="span"], .row-fluid .uneditable-input[class*="span"] { float: none; margin-left: 0; } .input-append input[class*="span"], .input-append .uneditable-input[class*="span"], .input-prepend input[class*="span"], .input-prepend .uneditable-input[class*="span"], .row-fluid input[class*="span"], .row-fluid select[class*="span"], .row-fluid textarea[class*="span"], .row-fluid .uneditable-input[class*="span"], .row-fluid .input-prepend [class*="span"], .row-fluid .input-append [class*="span"] { display: inline-block; } input, textarea, .uneditable-input { margin-left: 0; } .controls-row [class*="span"] + [class*="span"] { margin-left: 20px; } input.span12, textarea.span12, .uneditable-input.span12 { width: 926px; } input.span11, textarea.span11, .uneditable-input.span11 { width: 846px; } input.span10, textarea.span10, .uneditable-input.span10 { width: 766px; } input.span9, textarea.span9, .uneditable-input.span9 { width: 686px; } input.span8, textarea.span8, .uneditable-input.span8 { width: 606px; } input.span7, textarea.span7, .uneditable-input.span7 { width: 526px; } input.span6, textarea.span6, .uneditable-input.span6 { width: 446px; } input.span5, textarea.span5, .uneditable-input.span5 { width: 366px; } input.span4, textarea.span4, .uneditable-input.span4 { width: 286px; } input.span3, textarea.span3, .uneditable-input.span3 { width: 206px; } input.span2, textarea.span2, .uneditable-input.span2 { width: 126px; } input.span1, textarea.span1, .uneditable-input.span1 { width: 46px; } .controls-row { *zoom: 1; } .controls-row:before, .controls-row:after { display: table; line-height: 0; content: ""; } .controls-row:after { clear: both; } .controls-row [class*="span"] { float: left; } input[disabled], select[disabled], textarea[disabled], input[readonly], select[readonly], textarea[readonly] { cursor: not-allowed; background-color: #eeeeee; } input[type="radio"][disabled], input[type="checkbox"][disabled], input[type="radio"][readonly], input[type="checkbox"][readonly] { background-color: transparent; } .control-group.warning > label, .control-group.warning .help-block, .control-group.warning .help-inline { color: #c09853; } .control-group.warning .checkbox, .control-group.warning .radio, .control-group.warning input, .control-group.warning select, .control-group.warning textarea { color: #c09853; } .control-group.warning input, .control-group.warning select, .control-group.warning textarea { border-color: #c09853; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { border-color: #a47e3c; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; } .control-group.warning .input-prepend .add-on, .control-group.warning .input-append .add-on { color: #c09853; background-color: #fcf8e3; border-color: #c09853; } .control-group.error > label, .control-group.error .help-block, .control-group.error .help-inline { color: #b94a48; } .control-group.error .checkbox, .control-group.error .radio, .control-group.error input, .control-group.error select, .control-group.error textarea { color: #b94a48; } .control-group.error input, .control-group.error select, .control-group.error textarea { border-color: #b94a48; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { border-color: #953b39; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; } .control-group.error .input-prepend .add-on, .control-group.error .input-append .add-on { color: #b94a48; background-color: #f2dede; border-color: #b94a48; } .control-group.success > label, .control-group.success .help-block, .control-group.success .help-inline { color: #468847; } .control-group.success .checkbox, .control-group.success .radio, .control-group.success input, .control-group.success select, .control-group.success textarea { color: #468847; } .control-group.success input, .control-group.success select, .control-group.success textarea { border-color: #468847; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { border-color: #356635; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; } .control-group.success .input-prepend .add-on, .control-group.success .input-append .add-on { color: #468847; background-color: #dff0d8; border-color: #468847; } .control-group.info > label, .control-group.info .help-block, .control-group.info .help-inline { color: #3a87ad; } .control-group.info .checkbox, .control-group.info .radio, .control-group.info input, .control-group.info select, .control-group.info textarea { color: #3a87ad; } .control-group.info input, .control-group.info select, .control-group.info textarea { border-color: #3a87ad; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } .control-group.info input:focus, .control-group.info select:focus, .control-group.info textarea:focus { border-color: #2d6987; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; } .control-group.info .input-prepend .add-on, .control-group.info .input-append .add-on { color: #3a87ad; background-color: #d9edf7; border-color: #3a87ad; } input:focus:required:invalid, textarea:focus:required:invalid, select:focus:required:invalid { color: #b94a48; border-color: #ee5f5b; } input:focus:required:invalid:focus, textarea:focus:required:invalid:focus, select:focus:required:invalid:focus { border-color: #e9322d; -webkit-box-shadow: 0 0 6px #f8b9b7; -moz-box-shadow: 0 0 6px #f8b9b7; box-shadow: 0 0 6px #f8b9b7; } .form-actions { padding: 19px 20px 20px; margin-top: 20px; margin-bottom: 20px; background-color: #f5f5f5; border-top: 1px solid #e5e5e5; *zoom: 1; } .form-actions:before, .form-actions:after { display: table; line-height: 0; content: ""; } .form-actions:after { clear: both; } .help-block, .help-inline { color: #595959; } .help-block { display: block; margin-bottom: 10px; } .help-inline { display: inline-block; *display: inline; padding-left: 5px; vertical-align: middle; *zoom: 1; } .input-append, .input-prepend { margin-bottom: 5px; font-size: 0; white-space: nowrap; } .input-append input, .input-prepend input, .input-append select, .input-prepend select, .input-append .uneditable-input, .input-prepend .uneditable-input { position: relative; margin-bottom: 0; *margin-left: 0; font-size: 14px; vertical-align: top; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .input-append input:focus, .input-prepend input:focus, .input-append select:focus, .input-prepend select:focus, .input-append .uneditable-input:focus, .input-prepend .uneditable-input:focus { z-index: 2; } .input-append .add-on, .input-prepend .add-on { display: inline-block; width: auto; height: 20px; min-width: 16px; padding: 4px 5px; font-size: 14px; font-weight: normal; line-height: 20px; text-align: center; text-shadow: 0 1px 0 #ffffff; background-color: #eeeeee; border: 1px solid #ccc; } .input-append .add-on, .input-prepend .add-on, .input-append .btn, .input-prepend .btn { vertical-align: top; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .input-append .active, .input-prepend .active { background-color: #a9dba9; border-color: #46a546; } .input-prepend .add-on, .input-prepend .btn { margin-right: -1px; } .input-prepend .add-on:first-child, .input-prepend .btn:first-child { -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-append input, .input-append select, .input-append .uneditable-input { -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-append .add-on, .input-append .btn { margin-left: -1px; } .input-append .add-on:last-child, .input-append .btn:last-child { -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .input-prepend.input-append input, .input-prepend.input-append select, .input-prepend.input-append .uneditable-input { -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .input-prepend.input-append .add-on:first-child, .input-prepend.input-append .btn:first-child { margin-right: -1px; -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .input-prepend.input-append .add-on:last-child, .input-prepend.input-append .btn:last-child { margin-left: -1px; -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } input.search-query { padding-right: 14px; padding-right: 4px \9; padding-left: 14px; padding-left: 4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */ margin-bottom: 0; -webkit-border-radius: 15px; -moz-border-radius: 15px; border-radius: 15px; } /* Allow for input prepend/append in search forms */ .form-search .input-append .search-query, .form-search .input-prepend .search-query { -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .form-search .input-append .search-query { -webkit-border-radius: 14px 0 0 14px; -moz-border-radius: 14px 0 0 14px; border-radius: 14px 0 0 14px; } .form-search .input-append .btn { -webkit-border-radius: 0 14px 14px 0; -moz-border-radius: 0 14px 14px 0; border-radius: 0 14px 14px 0; } .form-search .input-prepend .search-query { -webkit-border-radius: 0 14px 14px 0; -moz-border-radius: 0 14px 14px 0; border-radius: 0 14px 14px 0; } .form-search .input-prepend .btn { -webkit-border-radius: 14px 0 0 14px; -moz-border-radius: 14px 0 0 14px; border-radius: 14px 0 0 14px; } .form-search input, .form-inline input, .form-horizontal input, .form-search textarea, .form-inline textarea, .form-horizontal textarea, .form-search select, .form-inline select, .form-horizontal select, .form-search .help-inline, .form-inline .help-inline, .form-horizontal .help-inline, .form-search .uneditable-input, .form-inline .uneditable-input, .form-horizontal .uneditable-input, .form-search .input-prepend, .form-inline .input-prepend, .form-horizontal .input-prepend, .form-search .input-append, .form-inline .input-append, .form-horizontal .input-append { display: inline-block; *display: inline; margin-bottom: 0; vertical-align: middle; *zoom: 1; } .form-search .hide, .form-inline .hide, .form-horizontal .hide { display: none; } .form-search label, .form-inline label, .form-search .btn-group, .form-inline .btn-group { display: inline-block; } .form-search .input-append, .form-inline .input-append, .form-search .input-prepend, .form-inline .input-prepend { margin-bottom: 0; } .form-search .radio, .form-search .checkbox, .form-inline .radio, .form-inline .checkbox { padding-left: 0; margin-bottom: 0; vertical-align: middle; } .form-search .radio input[type="radio"], .form-search .checkbox input[type="checkbox"], .form-inline .radio input[type="radio"], .form-inline .checkbox input[type="checkbox"] { float: left; margin-right: 3px; margin-left: 0; } .control-group { margin-bottom: 10px; } legend + .control-group { margin-top: 20px; -webkit-margin-top-collapse: separate; } .form-horizontal .control-group { margin-bottom: 20px; *zoom: 1; } .form-horizontal .control-group:before, .form-horizontal .control-group:after { display: table; line-height: 0; content: ""; } .form-horizontal .control-group:after { clear: both; } .form-horizontal .control-label { float: left; width: 160px; padding-top: 5px; text-align: right; } .form-horizontal .controls { *display: inline-block; *padding-left: 20px; margin-left: 180px; *margin-left: 0; } .form-horizontal .controls:first-child { *padding-left: 180px; } .form-horizontal .help-block { margin-bottom: 0; } .form-horizontal input + .help-block, .form-horizontal select + .help-block, .form-horizontal textarea + .help-block { margin-top: 10px; } .form-horizontal .form-actions { padding-left: 180px; } table { max-width: 100%; background-color: transparent; border-collapse: collapse; border-spacing: 0; } .table { width: 100%; margin-bottom: 20px; } .table th, .table td { padding: 8px; line-height: 20px; text-align: left; vertical-align: top; border-top: 1px solid #dddddd; } .table th { font-weight: bold; } .table thead th { vertical-align: bottom; } .table caption + thead tr:first-child th, .table caption + thead tr:first-child td, .table colgroup + thead tr:first-child th, .table colgroup + thead tr:first-child td, .table thead:first-child tr:first-child th, .table thead:first-child tr:first-child td { border-top: 0; } .table tbody + tbody { border-top: 2px solid #dddddd; } .table-condensed th, .table-condensed td { padding: 4px 5px; } .table-bordered { border: 1px solid #dddddd; border-collapse: separate; *border-collapse: collapse; border-left: 0; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .table-bordered th, .table-bordered td { border-left: 1px solid #dddddd; } .table-bordered caption + thead tr:first-child th, .table-bordered caption + tbody tr:first-child th, .table-bordered caption + tbody tr:first-child td, .table-bordered colgroup + thead tr:first-child th, .table-bordered colgroup + tbody tr:first-child th, .table-bordered colgroup + tbody tr:first-child td, .table-bordered thead:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child th, .table-bordered tbody:first-child tr:first-child td { border-top: 0; } .table-bordered thead:first-child tr:first-child th:first-child, .table-bordered tbody:first-child tr:first-child td:first-child { -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; } .table-bordered thead:first-child tr:first-child th:last-child, .table-bordered tbody:first-child tr:first-child td:last-child { -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-topright: 4px; } .table-bordered thead:last-child tr:last-child th:first-child, .table-bordered tbody:last-child tr:last-child td:first-child, .table-bordered tfoot:last-child tr:last-child td:first-child { -webkit-border-radius: 0 0 0 4px; -moz-border-radius: 0 0 0 4px; border-radius: 0 0 0 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomleft: 4px; } .table-bordered thead:last-child tr:last-child th:last-child, .table-bordered tbody:last-child tr:last-child td:last-child, .table-bordered tfoot:last-child tr:last-child td:last-child { -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; -moz-border-radius-bottomright: 4px; } .table-bordered caption + thead tr:first-child th:first-child, .table-bordered caption + tbody tr:first-child td:first-child, .table-bordered colgroup + thead tr:first-child th:first-child, .table-bordered colgroup + tbody tr:first-child td:first-child { -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; } .table-bordered caption + thead tr:first-child th:last-child, .table-bordered caption + tbody tr:first-child td:last-child, .table-bordered colgroup + thead tr:first-child th:last-child, .table-bordered colgroup + tbody tr:first-child td:last-child { -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-topleft: 4px; } .table-striped tbody tr:nth-child(odd) td, .table-striped tbody tr:nth-child(odd) th { background-color: #f9f9f9; } .table-hover tbody tr:hover td, .table-hover tbody tr:hover th { background-color: #f5f5f5; } table [class*=span], .row-fluid table [class*=span] { display: table-cell; float: none; margin-left: 0; } .table .span1 { float: none; width: 44px; margin-left: 0; } .table .span2 { float: none; width: 124px; margin-left: 0; } .table .span3 { float: none; width: 204px; margin-left: 0; } .table .span4 { float: none; width: 284px; margin-left: 0; } .table .span5 { float: none; width: 364px; margin-left: 0; } .table .span6 { float: none; width: 444px; margin-left: 0; } .table .span7 { float: none; width: 524px; margin-left: 0; } .table .span8 { float: none; width: 604px; margin-left: 0; } .table .span9 { float: none; width: 684px; margin-left: 0; } .table .span10 { float: none; width: 764px; margin-left: 0; } .table .span11 { float: none; width: 844px; margin-left: 0; } .table .span12 { float: none; width: 924px; margin-left: 0; } .table .span13 { float: none; width: 1004px; margin-left: 0; } .table .span14 { float: none; width: 1084px; margin-left: 0; } .table .span15 { float: none; width: 1164px; margin-left: 0; } .table .span16 { float: none; width: 1244px; margin-left: 0; } .table .span17 { float: none; width: 1324px; margin-left: 0; } .table .span18 { float: none; width: 1404px; margin-left: 0; } .table .span19 { float: none; width: 1484px; margin-left: 0; } .table .span20 { float: none; width: 1564px; margin-left: 0; } .table .span21 { float: none; width: 1644px; margin-left: 0; } .table .span22 { float: none; width: 1724px; margin-left: 0; } .table .span23 { float: none; width: 1804px; margin-left: 0; } .table .span24 { float: none; width: 1884px; margin-left: 0; } .table tbody tr.success td { background-color: #dff0d8; } .table tbody tr.error td { background-color: #f2dede; } .table tbody tr.warning td { background-color: #fcf8e3; } .table tbody tr.info td { background-color: #d9edf7; } .table-hover tbody tr.success:hover td { background-color: #d0e9c6; } .table-hover tbody tr.error:hover td { background-color: #ebcccc; } .table-hover tbody tr.warning:hover td { background-color: #faf2cc; } .table-hover tbody tr.info:hover td { background-color: #c4e3f3; } [class^="icon-"], [class*=" icon-"] { display: inline-block; width: 14px; height: 14px; margin-top: 1px; *margin-right: .3em; line-height: 14px; vertical-align: text-top; background-image: url("../img/glyphicons-halflings.png"); background-position: 14px 14px; background-repeat: no-repeat; } /* White icons with optional class, or on hover/active states of certain elements */ .icon-white, .nav-tabs > .active > a > [class^="icon-"], .nav-tabs > .active > a > [class*=" icon-"], .nav-pills > .active > a > [class^="icon-"], .nav-pills > .active > a > [class*=" icon-"], .nav-list > .active > a > [class^="icon-"], .nav-list > .active > a > [class*=" icon-"], .navbar-inverse .nav > .active > a > [class^="icon-"], .navbar-inverse .nav > .active > a > [class*=" icon-"], .dropdown-menu > li > a:hover > [class^="icon-"], .dropdown-menu > li > a:hover > [class*=" icon-"], .dropdown-menu > .active > a > [class^="icon-"], .dropdown-menu > .active > a > [class*=" icon-"] { background-image: url("../img/glyphicons-halflings-white.png"); } .icon-glass { background-position: 0 0; } .icon-music { background-position: -24px 0; } .icon-search { background-position: -48px 0; } .icon-envelope { background-position: -72px 0; } .icon-heart { background-position: -96px 0; } .icon-star { background-position: -120px 0; } .icon-star-empty { background-position: -144px 0; } .icon-user { background-position: -168px 0; } .icon-film { background-position: -192px 0; } .icon-th-large { background-position: -216px 0; } .icon-th { background-position: -240px 0; } .icon-th-list { background-position: -264px 0; } .icon-ok { background-position: -288px 0; } .icon-remove { background-position: -312px 0; } .icon-zoom-in { background-position: -336px 0; } .icon-zoom-out { background-position: -360px 0; } .icon-off { background-position: -384px 0; } .icon-signal { background-position: -408px 0; } .icon-cog { background-position: -432px 0; } .icon-trash { background-position: -456px 0; } .icon-home { background-position: 0 -24px; } .icon-file { background-position: -24px -24px; } .icon-time { background-position: -48px -24px; } .icon-road { background-position: -72px -24px; } .icon-download-alt { background-position: -96px -24px; } .icon-download { background-position: -120px -24px; } .icon-upload { background-position: -144px -24px; } .icon-inbox { background-position: -168px -24px; } .icon-play-circle { background-position: -192px -24px; } .icon-repeat { background-position: -216px -24px; } .icon-refresh { background-position: -240px -24px; } .icon-list-alt { background-position: -264px -24px; } .icon-lock { background-position: -287px -24px; } .icon-flag { background-position: -312px -24px; } .icon-headphones { background-position: -336px -24px; } .icon-volume-off { background-position: -360px -24px; } .icon-volume-down { background-position: -384px -24px; } .icon-volume-up { background-position: -408px -24px; } .icon-qrcode { background-position: -432px -24px; } .icon-barcode { background-position: -456px -24px; } .icon-tag { background-position: 0 -48px; } .icon-tags { background-position: -25px -48px; } .icon-book { background-position: -48px -48px; } .icon-bookmark { background-position: -72px -48px; } .icon-print { background-position: -96px -48px; } .icon-camera { background-position: -120px -48px; } .icon-font { background-position: -144px -48px; } .icon-bold { background-position: -167px -48px; } .icon-italic { background-position: -192px -48px; } .icon-text-height { background-position: -216px -48px; } .icon-text-width { background-position: -240px -48px; } .icon-align-left { background-position: -264px -48px; } .icon-align-center { background-position: -288px -48px; } .icon-align-right { background-position: -312px -48px; } .icon-align-justify { background-position: -336px -48px; } .icon-list { background-position: -360px -48px; } .icon-indent-left { background-position: -384px -48px; } .icon-indent-right { background-position: -408px -48px; } .icon-facetime-video { background-position: -432px -48px; } .icon-picture { background-position: -456px -48px; } .icon-pencil { background-position: 0 -72px; } .icon-map-marker { background-position: -24px -72px; } .icon-adjust { background-position: -48px -72px; } .icon-tint { background-position: -72px -72px; } .icon-edit { background-position: -96px -72px; } .icon-share { background-position: -120px -72px; } .icon-check { background-position: -144px -72px; } .icon-move { background-position: -168px -72px; } .icon-step-backward { background-position: -192px -72px; } .icon-fast-backward { background-position: -216px -72px; } .icon-backward { background-position: -240px -72px; } .icon-play { background-position: -264px -72px; } .icon-pause { background-position: -288px -72px; } .icon-stop { background-position: -312px -72px; } .icon-forward { background-position: -336px -72px; } .icon-fast-forward { background-position: -360px -72px; } .icon-step-forward { background-position: -384px -72px; } .icon-eject { background-position: -408px -72px; } .icon-chevron-left { background-position: -432px -72px; } .icon-chevron-right { background-position: -456px -72px; } .icon-plus-sign { background-position: 0 -96px; } .icon-minus-sign { background-position: -24px -96px; } .icon-remove-sign { background-position: -48px -96px; } .icon-ok-sign { background-position: -72px -96px; } .icon-question-sign { background-position: -96px -96px; } .icon-info-sign { background-position: -120px -96px; } .icon-screenshot { background-position: -144px -96px; } .icon-remove-circle { background-position: -168px -96px; } .icon-ok-circle { background-position: -192px -96px; } .icon-ban-circle { background-position: -216px -96px; } .icon-arrow-left { background-position: -240px -96px; } .icon-arrow-right { background-position: -264px -96px; } .icon-arrow-up { background-position: -289px -96px; } .icon-arrow-down { background-position: -312px -96px; } .icon-share-alt { background-position: -336px -96px; } .icon-resize-full { background-position: -360px -96px; } .icon-resize-small { background-position: -384px -96px; } .icon-plus { background-position: -408px -96px; } .icon-minus { background-position: -433px -96px; } .icon-asterisk { background-position: -456px -96px; } .icon-exclamation-sign { background-position: 0 -120px; } .icon-gift { background-position: -24px -120px; } .icon-leaf { background-position: -48px -120px; } .icon-fire { background-position: -72px -120px; } .icon-eye-open { background-position: -96px -120px; } .icon-eye-close { background-position: -120px -120px; } .icon-warning-sign { background-position: -144px -120px; } .icon-plane { background-position: -168px -120px; } .icon-calendar { background-position: -192px -120px; } .icon-random { width: 16px; background-position: -216px -120px; } .icon-comment { background-position: -240px -120px; } .icon-magnet { background-position: -264px -120px; } .icon-chevron-up { background-position: -288px -120px; } .icon-chevron-down { background-position: -313px -119px; } .icon-retweet { background-position: -336px -120px; } .icon-shopping-cart { background-position: -360px -120px; } .icon-folder-close { background-position: -384px -120px; } .icon-folder-open { width: 16px; background-position: -408px -120px; } .icon-resize-vertical { background-position: -432px -119px; } .icon-resize-horizontal { background-position: -456px -118px; } .icon-hdd { background-position: 0 -144px; } .icon-bullhorn { background-position: -24px -144px; } .icon-bell { background-position: -48px -144px; } .icon-certificate { background-position: -72px -144px; } .icon-thumbs-up { background-position: -96px -144px; } .icon-thumbs-down { background-position: -120px -144px; } .icon-hand-right { background-position: -144px -144px; } .icon-hand-left { background-position: -168px -144px; } .icon-hand-up { background-position: -192px -144px; } .icon-hand-down { background-position: -216px -144px; } .icon-circle-arrow-right { background-position: -240px -144px; } .icon-circle-arrow-left { background-position: -264px -144px; } .icon-circle-arrow-up { background-position: -288px -144px; } .icon-circle-arrow-down { background-position: -312px -144px; } .icon-globe { background-position: -336px -144px; } .icon-wrench { background-position: -360px -144px; } .icon-tasks { background-position: -384px -144px; } .icon-filter { background-position: -408px -144px; } .icon-briefcase { background-position: -432px -144px; } .icon-fullscreen { background-position: -456px -144px; } .dropup, .dropdown { position: relative; } .dropdown-toggle { *margin-bottom: -3px; } .dropdown-toggle:active, .open .dropdown-toggle { outline: 0; } .caret { display: inline-block; width: 0; height: 0; vertical-align: top; border-top: 4px solid #000000; border-right: 4px solid transparent; border-left: 4px solid transparent; content: ""; } .dropdown .caret { margin-top: 8px; margin-left: 2px; } .dropdown-menu { position: absolute; top: 100%; left: 0; z-index: 1000; display: none; float: left; min-width: 160px; padding: 5px 0; margin: 2px 0 0; list-style: none; background-color: #ffffff; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); *border-right-width: 2px; *border-bottom-width: 2px; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; } .dropdown-menu.pull-right { right: 0; left: auto; } .dropdown-menu .divider { *width: 100%; height: 1px; margin: 9px 1px; *margin: -5px 0 5px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; } .dropdown-menu a { display: block; padding: 3px 20px; clear: both; font-weight: normal; line-height: 20px; color: #333333; white-space: nowrap; } .dropdown-menu li > a:hover, .dropdown-menu li > a:focus, .dropdown-submenu:hover > a { color: #ffffff; text-decoration: none; background-color: #0088cc; background-color: #0081c2; background-image: -moz-linear-gradient(top, #0088cc, #0077b3); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); background-image: -o-linear-gradient(top, #0088cc, #0077b3); background-image: linear-gradient(to bottom, #0088cc, #0077b3); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); } .dropdown-menu .active > a, .dropdown-menu .active > a:hover { color: #ffffff; text-decoration: none; background-color: #0088cc; background-color: #0081c2; background-image: linear-gradient(to bottom, #0088cc, #0077b3); background-image: -moz-linear-gradient(top, #0088cc, #0077b3); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); background-image: -o-linear-gradient(top, #0088cc, #0077b3); background-repeat: repeat-x; outline: 0; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); } .dropdown-menu .disabled > a, .dropdown-menu .disabled > a:hover { color: #999999; } .dropdown-menu .disabled > a:hover { text-decoration: none; cursor: default; background-color: transparent; } .open { *z-index: 1000; } .open > .dropdown-menu { display: block; } .pull-right > .dropdown-menu { right: 0; left: auto; } .dropup .caret, .navbar-fixed-bottom .dropdown .caret { border-top: 0; border-bottom: 4px solid #000000; content: ""; } .dropup .dropdown-menu, .navbar-fixed-bottom .dropdown .dropdown-menu { top: auto; bottom: 100%; margin-bottom: 1px; } .dropdown-submenu { position: relative; } .dropdown-submenu > .dropdown-menu { top: 0; left: 100%; margin-top: -6px; margin-left: -1px; -webkit-border-radius: 0 6px 6px 6px; -moz-border-radius: 0 6px 6px 6px; border-radius: 0 6px 6px 6px; } .dropdown-submenu:hover > .dropdown-menu { display: block; } .dropdown-submenu > a:after { display: block; float: right; width: 0; height: 0; margin-top: 5px; margin-right: -10px; border-color: transparent; border-left-color: #cccccc; border-style: solid; border-width: 5px 0 5px 5px; content: " "; } .dropdown-submenu:hover > a:after { border-left-color: #ffffff; } .dropdown .dropdown-menu .nav-header { padding-right: 20px; padding-left: 20px; } .typeahead { margin-top: 2px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .well { min-height: 20px; padding: 19px; margin-bottom: 20px; background-color: #f5f5f5; border: 1px solid #e3e3e3; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); } .well blockquote { border-color: #ddd; border-color: rgba(0, 0, 0, 0.15); } .well-large { padding: 24px; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .well-small { padding: 9px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .fade { opacity: 0; -webkit-transition: opacity 0.15s linear; -moz-transition: opacity 0.15s linear; -o-transition: opacity 0.15s linear; transition: opacity 0.15s linear; } .fade.in { opacity: 1; } .collapse { position: relative; height: 0; overflow: hidden; -webkit-transition: height 0.35s ease; -moz-transition: height 0.35s ease; -o-transition: height 0.35s ease; transition: height 0.35s ease; } .collapse.in { height: auto; } .close { float: right; font-size: 20px; font-weight: bold; line-height: 20px; color: #000000; text-shadow: 0 1px 0 #ffffff; opacity: 0.2; filter: alpha(opacity=20); } .close:hover { color: #000000; text-decoration: none; cursor: pointer; opacity: 0.4; filter: alpha(opacity=40); } button.close { padding: 0; cursor: pointer; background: transparent; border: 0; -webkit-appearance: none; } .btn { display: inline-block; *display: inline; padding: 4px 14px; margin-bottom: 0; *margin-left: .3em; font-size: 14px; line-height: 20px; *line-height: 20px; color: #333333; text-align: center; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); vertical-align: middle; cursor: pointer; background-color: #f5f5f5; *background-color: #e6e6e6; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; border: 1px solid #bbbbbb; *border: 0; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border-color: #e6e6e6 #e6e6e6 #bfbfbf; border-bottom-color: #a2a2a2; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); *zoom: 1; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } .btn:hover, .btn:active, .btn.active, .btn.disabled, .btn[disabled] { color: #333333; background-color: #e6e6e6; *background-color: #d9d9d9; } .btn:active, .btn.active { background-color: #cccccc \9; } .btn:first-child { *margin-left: 0; } .btn:hover { color: #333333; text-decoration: none; background-color: #e6e6e6; *background-color: #d9d9d9; /* Buttons in IE7 don't get borders, so darken on hover */ background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; -o-transition: background-position 0.1s linear; transition: background-position 0.1s linear; } .btn:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline-offset: -2px; } .btn.active, .btn:active { background-color: #e6e6e6; background-color: #d9d9d9 \9; background-image: none; outline: 0; -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); } .btn.disabled, .btn[disabled] { cursor: default; background-color: #e6e6e6; background-image: none; opacity: 0.65; filter: alpha(opacity=65); -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } .btn-large { padding: 9px 14px; font-size: 16px; line-height: normal; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .btn-large [class^="icon-"] { margin-top: 2px; } .btn-small { padding: 3px 9px; font-size: 12px; line-height: 18px; } .btn-small [class^="icon-"] { margin-top: 0; } .btn-mini { padding: 2px 6px; font-size: 11px; line-height: 17px; } .btn-block { display: block; width: 100%; padding-right: 0; padding-left: 0; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; } .btn-block + .btn-block { margin-top: 5px; } input[type="submit"].btn-block, input[type="reset"].btn-block, input[type="button"].btn-block { width: 100%; } .btn-primary.active, .btn-warning.active, .btn-danger.active, .btn-success.active, .btn-info.active, .btn-inverse.active { color: rgba(255, 255, 255, 0.75); } .btn { border-color: #c5c5c5; border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); } .btn-primary { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #006dcc; *background-color: #0044cc; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(to bottom, #0088cc, #0044cc); background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-primary:hover, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, .btn-primary[disabled] { color: #ffffff; background-color: #0044cc; *background-color: #003bb3; } .btn-primary:active, .btn-primary.active { background-color: #003399 \9; } .btn-warning { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #faa732; *background-color: #f89406; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); background-image: -webkit-linear-gradient(top, #fbb450, #f89406); background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(to bottom, #fbb450, #f89406); background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-repeat: repeat-x; border-color: #f89406 #f89406 #ad6704; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-warning:hover, .btn-warning:active, .btn-warning.active, .btn-warning.disabled, .btn-warning[disabled] { color: #ffffff; background-color: #f89406; *background-color: #df8505; } .btn-warning:active, .btn-warning.active { background-color: #c67605 \9; } .btn-danger { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #da4f49; *background-color: #bd362f; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); background-repeat: repeat-x; border-color: #bd362f #bd362f #802420; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-danger:hover, .btn-danger:active, .btn-danger.active, .btn-danger.disabled, .btn-danger[disabled] { color: #ffffff; background-color: #bd362f; *background-color: #a9302a; } .btn-danger:active, .btn-danger.active { background-color: #942a25 \9; } .btn-success { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #5bb75b; *background-color: #51a351; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); background-image: -webkit-linear-gradient(top, #62c462, #51a351); background-image: -o-linear-gradient(top, #62c462, #51a351); background-image: linear-gradient(to bottom, #62c462, #51a351); background-image: -moz-linear-gradient(top, #62c462, #51a351); background-repeat: repeat-x; border-color: #51a351 #51a351 #387038; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-success:hover, .btn-success:active, .btn-success.active, .btn-success.disabled, .btn-success[disabled] { color: #ffffff; background-color: #51a351; *background-color: #499249; } .btn-success:active, .btn-success.active { background-color: #408140 \9; } .btn-info { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #49afcd; *background-color: #2f96b4; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); background-repeat: repeat-x; border-color: #2f96b4 #2f96b4 #1f6377; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-info:hover, .btn-info:active, .btn-info.active, .btn-info.disabled, .btn-info[disabled] { color: #ffffff; background-color: #2f96b4; *background-color: #2a85a0; } .btn-info:active, .btn-info.active { background-color: #24748c \9; } .btn-inverse { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #363636; *background-color: #222222; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); background-image: -webkit-linear-gradient(top, #444444, #222222); background-image: -o-linear-gradient(top, #444444, #222222); background-image: linear-gradient(to bottom, #444444, #222222); background-image: -moz-linear-gradient(top, #444444, #222222); background-repeat: repeat-x; border-color: #222222 #222222 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .btn-inverse:hover, .btn-inverse:active, .btn-inverse.active, .btn-inverse.disabled, .btn-inverse[disabled] { color: #ffffff; background-color: #222222; *background-color: #151515; } .btn-inverse:active, .btn-inverse.active { background-color: #080808 \9; } button.btn, input[type="submit"].btn { *padding-top: 3px; *padding-bottom: 3px; } button.btn::-moz-focus-inner, input[type="submit"].btn::-moz-focus-inner { padding: 0; border: 0; } button.btn.btn-large, input[type="submit"].btn.btn-large { *padding-top: 7px; *padding-bottom: 7px; } button.btn.btn-small, input[type="submit"].btn.btn-small { *padding-top: 3px; *padding-bottom: 3px; } button.btn.btn-mini, input[type="submit"].btn.btn-mini { *padding-top: 1px; *padding-bottom: 1px; } .btn-link, .btn-link:active, .btn-link[disabled] { background-color: transparent; background-image: none; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } .btn-link { color: #0088cc; cursor: pointer; border-color: transparent; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .btn-link:hover { color: #005580; text-decoration: underline; background-color: transparent; } .btn-link[disabled]:hover { color: #333333; text-decoration: none; } .btn-group { position: relative; *margin-left: .3em; font-size: 0; white-space: nowrap; vertical-align: middle; } .btn-group:first-child { *margin-left: 0; } .btn-group + .btn-group { margin-left: 5px; } .btn-toolbar { margin-top: 10px; margin-bottom: 10px; font-size: 0; } .btn-toolbar .btn-group { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; } .btn-toolbar .btn + .btn, .btn-toolbar .btn-group + .btn, .btn-toolbar .btn + .btn-group { margin-left: 5px; } .btn-group > .btn { position: relative; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .btn-group > .btn + .btn { margin-left: -1px; } .btn-group > .btn, .btn-group > .dropdown-menu { font-size: 14px; } .btn-group > .btn-mini { font-size: 11px; } .btn-group > .btn-small { font-size: 12px; } .btn-group > .btn-large { font-size: 16px; } .btn-group > .btn:first-child { margin-left: 0; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -moz-border-radius-topleft: 4px; } .btn-group > .btn:last-child, .btn-group > .dropdown-toggle { -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; -moz-border-radius-topright: 4px; -moz-border-radius-bottomright: 4px; } .btn-group > .btn.large:first-child { margin-left: 0; -webkit-border-bottom-left-radius: 6px; border-bottom-left-radius: 6px; -webkit-border-top-left-radius: 6px; border-top-left-radius: 6px; -moz-border-radius-bottomleft: 6px; -moz-border-radius-topleft: 6px; } .btn-group > .btn.large:last-child, .btn-group > .large.dropdown-toggle { -webkit-border-top-right-radius: 6px; border-top-right-radius: 6px; -webkit-border-bottom-right-radius: 6px; border-bottom-right-radius: 6px; -moz-border-radius-topright: 6px; -moz-border-radius-bottomright: 6px; } .btn-group > .btn:hover, .btn-group > .btn:focus, .btn-group > .btn:active, .btn-group > .btn.active { z-index: 2; } .btn-group .dropdown-toggle:active, .btn-group.open .dropdown-toggle { outline: 0; } .btn-group > .btn + .dropdown-toggle { *padding-top: 5px; padding-right: 8px; *padding-bottom: 5px; padding-left: 8px; -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } .btn-group > .btn-mini + .dropdown-toggle { *padding-top: 2px; padding-right: 5px; *padding-bottom: 2px; padding-left: 5px; } .btn-group > .btn-small + .dropdown-toggle { *padding-top: 5px; *padding-bottom: 4px; } .btn-group > .btn-large + .dropdown-toggle { *padding-top: 7px; padding-right: 12px; *padding-bottom: 7px; padding-left: 12px; } .btn-group.open .dropdown-toggle { background-image: none; -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); } .btn-group.open .btn.dropdown-toggle { background-color: #e6e6e6; } .btn-group.open .btn-primary.dropdown-toggle { background-color: #0044cc; } .btn-group.open .btn-warning.dropdown-toggle { background-color: #f89406; } .btn-group.open .btn-danger.dropdown-toggle { background-color: #bd362f; } .btn-group.open .btn-success.dropdown-toggle { background-color: #51a351; } .btn-group.open .btn-info.dropdown-toggle { background-color: #2f96b4; } .btn-group.open .btn-inverse.dropdown-toggle { background-color: #222222; } .btn .caret { margin-top: 8px; margin-left: 0; } .btn-mini .caret, .btn-small .caret, .btn-large .caret { margin-top: 6px; } .btn-large .caret { border-top-width: 5px; border-right-width: 5px; border-left-width: 5px; } .dropup .btn-large .caret { border-top: 0; border-bottom: 5px solid #000000; } .btn-primary .caret, .btn-warning .caret, .btn-danger .caret, .btn-info .caret, .btn-success .caret, .btn-inverse .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; } .btn-group-vertical { display: inline-block; *display: inline; /* IE7 inline-block hack */ *zoom: 1; } .btn-group-vertical .btn { display: block; float: none; width: 100%; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .btn-group-vertical .btn + .btn { margin-top: -1px; margin-left: 0; } .btn-group-vertical .btn:first-child { -webkit-border-radius: 4px 4px 0 0; -moz-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; } .btn-group-vertical .btn:last-child { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } .btn-group-vertical .btn-large:first-child { -webkit-border-radius: 6px 6px 0 0; -moz-border-radius: 6px 6px 0 0; border-radius: 6px 6px 0 0; } .btn-group-vertical .btn-large:last-child { -webkit-border-radius: 0 0 6px 6px; -moz-border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px; } .alert { padding: 8px 35px 8px 14px; margin-bottom: 20px; color: #c09853; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); background-color: #fcf8e3; border: 1px solid #fbeed5; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .alert h4 { margin: 0; } .alert .close { position: relative; top: -2px; right: -21px; line-height: 20px; } .alert-success { color: #468847; background-color: #dff0d8; border-color: #d6e9c6; } .alert-danger, .alert-error { color: #b94a48; background-color: #f2dede; border-color: #eed3d7; } .alert-info { color: #3a87ad; background-color: #d9edf7; border-color: #bce8f1; } .alert-block { padding-top: 14px; padding-bottom: 14px; } .alert-block > p, .alert-block > ul { margin-bottom: 0; } .alert-block p + p { margin-top: 5px; } .nav { margin-bottom: 20px; margin-left: 0; list-style: none; } .nav > li > a { display: block; } .nav > li > a:hover { text-decoration: none; background-color: #eeeeee; } .nav > .pull-right { float: right; } .nav-header { display: block; padding: 3px 15px; font-size: 11px; font-weight: bold; line-height: 20px; color: #999999; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); text-transform: uppercase; } .nav li + .nav-header { margin-top: 9px; } .nav-list { padding-right: 15px; padding-left: 15px; margin-bottom: 0; } .nav-list > li > a, .nav-list .nav-header { margin-right: -15px; margin-left: -15px; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); } .nav-list > li > a { padding: 3px 15px; } .nav-list > .active > a, .nav-list > .active > a:hover { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); background-color: #0088cc; } .nav-list [class^="icon-"] { margin-right: 2px; } .nav-list .divider { *width: 100%; height: 1px; margin: 9px 1px; *margin: -5px 0 5px; overflow: hidden; background-color: #e5e5e5; border-bottom: 1px solid #ffffff; } .nav-tabs, .nav-pills { *zoom: 1; } .nav-tabs:before, .nav-pills:before, .nav-tabs:after, .nav-pills:after { display: table; line-height: 0; content: ""; } .nav-tabs:after, .nav-pills:after { clear: both; } .nav-tabs > li, .nav-pills > li { float: left; } .nav-tabs > li > a, .nav-pills > li > a { padding-right: 12px; padding-left: 12px; margin-right: 2px; line-height: 14px; } .nav-tabs { border-bottom: 1px solid #ddd; } .nav-tabs > li { margin-bottom: -1px; } .nav-tabs > li > a { padding-top: 8px; padding-bottom: 8px; line-height: 20px; border: 1px solid transparent; -webkit-border-radius: 4px 4px 0 0; -moz-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; } .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #dddddd; } .nav-tabs > .active > a, .nav-tabs > .active > a:hover { color: #555555; cursor: default; background-color: #ffffff; border: 1px solid #ddd; border-bottom-color: transparent; } .nav-pills > li > a { padding-top: 8px; padding-bottom: 8px; margin-top: 2px; margin-bottom: 2px; -webkit-border-radius: 5px; -moz-border-radius: 5px; border-radius: 5px; } .nav-pills > .active > a, .nav-pills > .active > a:hover { color: #ffffff; background-color: #0088cc; } .nav-stacked > li { float: none; } .nav-stacked > li > a { margin-right: 0; } .nav-tabs.nav-stacked { border-bottom: 0; } .nav-tabs.nav-stacked > li > a { border: 1px solid #ddd; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .nav-tabs.nav-stacked > li:first-child > a { -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -moz-border-radius-topleft: 4px; } .nav-tabs.nav-stacked > li:last-child > a { -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -moz-border-radius-bottomleft: 4px; } .nav-tabs.nav-stacked > li > a:hover { z-index: 2; border-color: #ddd; } .nav-pills.nav-stacked > li > a { margin-bottom: 3px; } .nav-pills.nav-stacked > li:last-child > a { margin-bottom: 1px; } .nav-tabs .dropdown-menu { -webkit-border-radius: 0 0 6px 6px; -moz-border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px; } .nav-pills .dropdown-menu { -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .nav .dropdown-toggle .caret { margin-top: 6px; border-top-color: #0088cc; border-bottom-color: #0088cc; } .nav .dropdown-toggle:hover .caret { border-top-color: #005580; border-bottom-color: #005580; } /* move down carets for tabs */ .nav-tabs .dropdown-toggle .caret { margin-top: 8px; } .nav .active .dropdown-toggle .caret { border-top-color: #fff; border-bottom-color: #fff; } .nav-tabs .active .dropdown-toggle .caret { border-top-color: #555555; border-bottom-color: #555555; } .nav > .dropdown.active > a:hover { cursor: pointer; } .nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > li.dropdown.open.active > a:hover { color: #ffffff; background-color: #999999; border-color: #999999; } .nav li.dropdown.open .caret, .nav li.dropdown.open.active .caret, .nav li.dropdown.open a:hover .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; opacity: 1; filter: alpha(opacity=100); } .tabs-stacked .open > a:hover { border-color: #999999; } .tabbable { *zoom: 1; } .tabbable:before, .tabbable:after { display: table; line-height: 0; content: ""; } .tabbable:after { clear: both; } .tab-content { overflow: auto; } .tabs-below > .nav-tabs, .tabs-right > .nav-tabs, .tabs-left > .nav-tabs { border-bottom: 0; } .tab-content > .tab-pane, .pill-content > .pill-pane { display: none; } .tab-content > .active, .pill-content > .active { display: block; } .tabs-below > .nav-tabs { border-top: 1px solid #ddd; } .tabs-below > .nav-tabs > li { margin-top: -1px; margin-bottom: 0; } .tabs-below > .nav-tabs > li > a { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } .tabs-below > .nav-tabs > li > a:hover { border-top-color: #ddd; border-bottom-color: transparent; } .tabs-below > .nav-tabs > .active > a, .tabs-below > .nav-tabs > .active > a:hover { border-color: transparent #ddd #ddd #ddd; } .tabs-left > .nav-tabs > li, .tabs-right > .nav-tabs > li { float: none; } .tabs-left > .nav-tabs > li > a, .tabs-right > .nav-tabs > li > a { min-width: 74px; margin-right: 0; margin-bottom: 3px; } .tabs-left > .nav-tabs { float: left; margin-right: 19px; border-right: 1px solid #ddd; } .tabs-left > .nav-tabs > li > a { margin-right: -1px; -webkit-border-radius: 4px 0 0 4px; -moz-border-radius: 4px 0 0 4px; border-radius: 4px 0 0 4px; } .tabs-left > .nav-tabs > li > a:hover { border-color: #eeeeee #dddddd #eeeeee #eeeeee; } .tabs-left > .nav-tabs .active > a, .tabs-left > .nav-tabs .active > a:hover { border-color: #ddd transparent #ddd #ddd; *border-right-color: #ffffff; } .tabs-right > .nav-tabs { float: right; margin-left: 19px; border-left: 1px solid #ddd; } .tabs-right > .nav-tabs > li > a { margin-left: -1px; -webkit-border-radius: 0 4px 4px 0; -moz-border-radius: 0 4px 4px 0; border-radius: 0 4px 4px 0; } .tabs-right > .nav-tabs > li > a:hover { border-color: #eeeeee #eeeeee #eeeeee #dddddd; } .tabs-right > .nav-tabs .active > a, .tabs-right > .nav-tabs .active > a:hover { border-color: #ddd #ddd #ddd transparent; *border-left-color: #ffffff; } .nav > .disabled > a { color: #999999; } .nav > .disabled > a:hover { text-decoration: none; cursor: default; background-color: transparent; } .navbar { *position: relative; *z-index: 2; margin-bottom: 20px; overflow: visible; color: #777777; } .navbar-inner { min-height: 40px; padding-right: 20px; padding-left: 20px; background-color: #fafafa; background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); background-repeat: repeat-x; border: 1px solid #d4d4d4; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); *zoom: 1; -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); } .navbar-inner:before, .navbar-inner:after { display: table; line-height: 0; content: ""; } .navbar-inner:after { clear: both; } .navbar .container { width: auto; } .nav-collapse.collapse { height: auto; } .navbar .brand { display: block; float: left; padding: 10px 20px 10px; margin-left: -20px; font-size: 20px; font-weight: 200; color: #777777; text-shadow: 0 1px 0 #ffffff; } .navbar .brand:hover { text-decoration: none; } .navbar-text { margin-bottom: 0; line-height: 40px; } .navbar-link { color: #777777; } .navbar-link:hover { color: #333333; } .navbar .divider-vertical { height: 40px; margin: 0 9px; border-right: 1px solid #ffffff; border-left: 1px solid #f2f2f2; } .navbar .btn, .navbar .btn-group { margin-top: 5px; } .navbar .btn-group .btn, .navbar .input-prepend .btn, .navbar .input-append .btn { margin-top: 0; } .navbar-form { margin-bottom: 0; *zoom: 1; } .navbar-form:before, .navbar-form:after { display: table; line-height: 0; content: ""; } .navbar-form:after { clear: both; } .navbar-form input, .navbar-form select, .navbar-form .radio, .navbar-form .checkbox { margin-top: 5px; } .navbar-form input, .navbar-form select, .navbar-form .btn { display: inline-block; margin-bottom: 0; } .navbar-form input[type="image"], .navbar-form input[type="checkbox"], .navbar-form input[type="radio"] { margin-top: 3px; } .navbar-form .input-append, .navbar-form .input-prepend { margin-top: 6px; white-space: nowrap; } .navbar-form .input-append input, .navbar-form .input-prepend input { margin-top: 0; } .navbar-search { position: relative; float: left; margin-top: 5px; margin-bottom: 0; } .navbar-search .search-query { padding: 4px 14px; margin-bottom: 0; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 13px; font-weight: normal; line-height: 1; -webkit-border-radius: 15px; -moz-border-radius: 15px; border-radius: 15px; } .navbar-static-top { position: static; width: 100%; margin-bottom: 0; } .navbar-static-top .navbar-inner { -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .navbar-fixed-top, .navbar-fixed-bottom { position: fixed; right: 0; left: 0; z-index: 1030; margin-bottom: 0; } .navbar-fixed-top .navbar-inner, .navbar-static-top .navbar-inner { border-width: 0 0 1px; } .navbar-fixed-bottom .navbar-inner { border-width: 1px 0 0; } .navbar-fixed-top .navbar-inner, .navbar-fixed-bottom .navbar-inner { padding-right: 0; padding-left: 0; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container { width: 940px; } .navbar-fixed-top { top: 0; } .navbar-fixed-top .navbar-inner, .navbar-static-top .navbar-inner { -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); } .navbar-fixed-bottom { bottom: 0; } .navbar-fixed-bottom .navbar-inner { -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); } .navbar .nav { position: relative; left: 0; display: block; float: left; margin: 0 10px 0 0; } .navbar .nav.pull-right { float: right; margin-right: 0; } .navbar .nav > li { float: left; } .navbar .nav > li > a { float: none; padding: 10px 15px 10px; color: #777777; text-decoration: none; text-shadow: 0 1px 0 #ffffff; } .navbar .nav .dropdown-toggle .caret { margin-top: 8px; } .navbar .nav > li > a:focus, .navbar .nav > li > a:hover { color: #333333; text-decoration: none; background-color: transparent; } .navbar .nav > .active > a, .navbar .nav > .active > a:hover, .navbar .nav > .active > a:focus { color: #555555; text-decoration: none; background-color: #e5e5e5; -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); } .navbar .btn-navbar { display: none; float: right; padding: 7px 10px; margin-right: 5px; margin-left: 5px; color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #ededed; *background-color: #e5e5e5; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); background-repeat: repeat-x; border-color: #e5e5e5 #e5e5e5 #bfbfbf; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); } .navbar .btn-navbar:hover, .navbar .btn-navbar:active, .navbar .btn-navbar.active, .navbar .btn-navbar.disabled, .navbar .btn-navbar[disabled] { color: #ffffff; background-color: #e5e5e5; *background-color: #d9d9d9; } .navbar .btn-navbar:active, .navbar .btn-navbar.active { background-color: #cccccc \9; } .navbar .btn-navbar .icon-bar { display: block; width: 18px; height: 2px; background-color: #f5f5f5; -webkit-border-radius: 1px; -moz-border-radius: 1px; border-radius: 1px; -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); } .btn-navbar .icon-bar + .icon-bar { margin-top: 3px; } .navbar .nav > li > .dropdown-menu:before { position: absolute; top: -7px; left: 9px; display: inline-block; border-right: 7px solid transparent; border-bottom: 7px solid #ccc; border-left: 7px solid transparent; border-bottom-color: rgba(0, 0, 0, 0.2); content: ''; } .navbar .nav > li > .dropdown-menu:after { position: absolute; top: -6px; left: 10px; display: inline-block; border-right: 6px solid transparent; border-bottom: 6px solid #ffffff; border-left: 6px solid transparent; content: ''; } .navbar-fixed-bottom .nav > li > .dropdown-menu:before { top: auto; bottom: -7px; border-top: 7px solid #ccc; border-bottom: 0; border-top-color: rgba(0, 0, 0, 0.2); } .navbar-fixed-bottom .nav > li > .dropdown-menu:after { top: auto; bottom: -6px; border-top: 6px solid #ffffff; border-bottom: 0; } .navbar .nav li.dropdown.open > .dropdown-toggle, .navbar .nav li.dropdown.active > .dropdown-toggle, .navbar .nav li.dropdown.open.active > .dropdown-toggle { color: #555555; background-color: #e5e5e5; } .navbar .nav li.dropdown > .dropdown-toggle .caret { border-top-color: #777777; border-bottom-color: #777777; } .navbar .nav li.dropdown.open > .dropdown-toggle .caret, .navbar .nav li.dropdown.active > .dropdown-toggle .caret, .navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { border-top-color: #555555; border-bottom-color: #555555; } .navbar .pull-right > li > .dropdown-menu, .navbar .nav > li > .dropdown-menu.pull-right { right: 0; left: auto; } .navbar .pull-right > li > .dropdown-menu:before, .navbar .nav > li > .dropdown-menu.pull-right:before { right: 12px; left: auto; } .navbar .pull-right > li > .dropdown-menu:after, .navbar .nav > li > .dropdown-menu.pull-right:after { right: 13px; left: auto; } .navbar .pull-right > li > .dropdown-menu .dropdown-menu, .navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { right: 100%; left: auto; margin-right: -1px; margin-left: 0; -webkit-border-radius: 6px 0 6px 6px; -moz-border-radius: 6px 0 6px 6px; border-radius: 6px 0 6px 6px; } .navbar-inverse { color: #999999; } .navbar-inverse .navbar-inner { background-color: #1b1b1b; background-image: -moz-linear-gradient(top, #222222, #111111); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); background-image: -webkit-linear-gradient(top, #222222, #111111); background-image: -o-linear-gradient(top, #222222, #111111); background-image: linear-gradient(to bottom, #222222, #111111); background-repeat: repeat-x; border-color: #252525; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); } .navbar-inverse .brand, .navbar-inverse .nav > li > a { color: #999999; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .navbar-inverse .brand:hover, .navbar-inverse .nav > li > a:hover { color: #ffffff; } .navbar-inverse .nav > li > a:focus, .navbar-inverse .nav > li > a:hover { color: #ffffff; background-color: transparent; } .navbar-inverse .nav .active > a, .navbar-inverse .nav .active > a:hover, .navbar-inverse .nav .active > a:focus { color: #ffffff; background-color: #111111; } .navbar-inverse .navbar-link { color: #999999; } .navbar-inverse .navbar-link:hover { color: #ffffff; } .navbar-inverse .divider-vertical { border-right-color: #222222; border-left-color: #111111; } .navbar-inverse .nav li.dropdown.open > .dropdown-toggle, .navbar-inverse .nav li.dropdown.active > .dropdown-toggle, .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { color: #ffffff; background-color: #111111; } .navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { border-top-color: #999999; border-bottom-color: #999999; } .navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, .navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, .navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; } .navbar-inverse .navbar-search .search-query { color: #ffffff; background-color: #515151; border-color: #111111; -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); -webkit-transition: none; -moz-transition: none; -o-transition: none; transition: none; } .navbar-inverse .navbar-search .search-query:-moz-placeholder { color: #cccccc; } .navbar-inverse .navbar-search .search-query:-ms-input-placeholder { color: #cccccc; } .navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { color: #cccccc; } .navbar-inverse .navbar-search .search-query:focus, .navbar-inverse .navbar-search .search-query.focused { padding: 5px 15px; color: #333333; text-shadow: 0 1px 0 #ffffff; background-color: #ffffff; border: 0; outline: 0; -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); } .navbar-inverse .btn-navbar { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #0e0e0e; *background-color: #040404; background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); background-image: -webkit-linear-gradient(top, #151515, #040404); background-image: -o-linear-gradient(top, #151515, #040404); background-image: linear-gradient(to bottom, #151515, #040404); background-image: -moz-linear-gradient(top, #151515, #040404); background-repeat: repeat-x; border-color: #040404 #040404 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); filter: progid:dximagetransform.microsoft.gradient(enabled=false); } .navbar-inverse .btn-navbar:hover, .navbar-inverse .btn-navbar:active, .navbar-inverse .btn-navbar.active, .navbar-inverse .btn-navbar.disabled, .navbar-inverse .btn-navbar[disabled] { color: #ffffff; background-color: #040404; *background-color: #000000; } .navbar-inverse .btn-navbar:active, .navbar-inverse .btn-navbar.active { background-color: #000000 \9; } .breadcrumb { padding: 8px 15px; margin: 0 0 20px; list-style: none; background-color: #f5f5f5; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .breadcrumb li { display: inline-block; *display: inline; text-shadow: 0 1px 0 #ffffff; *zoom: 1; } .breadcrumb .divider { padding: 0 5px; color: #ccc; } .breadcrumb .active { color: #999999; } .pagination { height: 40px; margin: 20px 0; } .pagination ul { display: inline-block; *display: inline; margin-bottom: 0; margin-left: 0; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; *zoom: 1; -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } .pagination ul > li { display: inline; } .pagination ul > li > a, .pagination ul > li > span { float: left; padding: 0 14px; line-height: 38px; text-decoration: none; background-color: #ffffff; border: 1px solid #dddddd; border-left-width: 0; } .pagination ul > li > a:hover, .pagination ul > .active > a, .pagination ul > .active > span { background-color: #f5f5f5; } .pagination ul > .active > a, .pagination ul > .active > span { color: #999999; cursor: default; } .pagination ul > .disabled > span, .pagination ul > .disabled > a, .pagination ul > .disabled > a:hover { color: #999999; cursor: default; background-color: transparent; } .pagination ul > li:first-child > a, .pagination ul > li:first-child > span { border-left-width: 1px; -webkit-border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; border-radius: 3px 0 0 3px; } .pagination ul > li:last-child > a, .pagination ul > li:last-child > span { -webkit-border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; border-radius: 0 3px 3px 0; } .pagination-centered { text-align: center; } .pagination-right { text-align: right; } .pager { margin: 20px 0; text-align: center; list-style: none; *zoom: 1; } .pager:before, .pager:after { display: table; line-height: 0; content: ""; } .pager:after { clear: both; } .pager li { display: inline; } .pager a, .pager span { display: inline-block; padding: 5px 14px; background-color: #fff; border: 1px solid #ddd; -webkit-border-radius: 15px; -moz-border-radius: 15px; border-radius: 15px; } .pager a:hover { text-decoration: none; background-color: #f5f5f5; } .pager .next a, .pager .next span { float: right; } .pager .previous a { float: left; } .pager .disabled a, .pager .disabled a:hover, .pager .disabled span { color: #999999; cursor: default; background-color: #fff; } .modal-open .modal .dropdown-menu { z-index: 2050; } .modal-open .modal .dropdown.open { *z-index: 2050; } .modal-open .modal .popover { z-index: 2060; } .modal-open .modal .tooltip { z-index: 2080; } .modal-backdrop { position: fixed; top: 0; right: 0; bottom: 0; left: 0; z-index: 1040; background-color: #000000; } .modal-backdrop.fade { opacity: 0; } .modal-backdrop, .modal-backdrop.fade.in { opacity: 0.8; filter: alpha(opacity=80); } .modal { position: fixed; top: 50%; left: 50%; z-index: 1050; width: 560px; margin: -250px 0 0 -280px; overflow: auto; background-color: #ffffff; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.3); *border: 1px solid #999; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -webkit-background-clip: padding-box; -moz-background-clip: padding-box; background-clip: padding-box; } .modal.fade { top: -25%; -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; -moz-transition: opacity 0.3s linear, top 0.3s ease-out; -o-transition: opacity 0.3s linear, top 0.3s ease-out; transition: opacity 0.3s linear, top 0.3s ease-out; } .modal.fade.in { top: 50%; } .modal-header { padding: 9px 15px; border-bottom: 1px solid #eee; } .modal-header .close { margin-top: 2px; } .modal-header h3 { margin: 0; line-height: 30px; } .modal-body { max-height: 400px; padding: 15px; overflow-y: auto; } .modal-form { margin-bottom: 0; } .modal-footer { padding: 14px 15px 15px; margin-bottom: 0; text-align: right; background-color: #f5f5f5; border-top: 1px solid #ddd; -webkit-border-radius: 0 0 6px 6px; -moz-border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px; *zoom: 1; -webkit-box-shadow: inset 0 1px 0 #ffffff; -moz-box-shadow: inset 0 1px 0 #ffffff; box-shadow: inset 0 1px 0 #ffffff; } .modal-footer:before, .modal-footer:after { display: table; line-height: 0; content: ""; } .modal-footer:after { clear: both; } .modal-footer .btn + .btn { margin-bottom: 0; margin-left: 5px; } .modal-footer .btn-group .btn + .btn { margin-left: -1px; } .tooltip { position: absolute; z-index: 1030; display: block; padding: 5px; font-size: 11px; opacity: 0; filter: alpha(opacity=0); visibility: visible; } .tooltip.in { opacity: 0.8; filter: alpha(opacity=80); } .tooltip.top { margin-top: -3px; } .tooltip.right { margin-left: 3px; } .tooltip.bottom { margin-top: 3px; } .tooltip.left { margin-left: -3px; } .tooltip-inner { max-width: 200px; padding: 3px 8px; color: #ffffff; text-align: center; text-decoration: none; background-color: #000000; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .tooltip-arrow { position: absolute; width: 0; height: 0; border-color: transparent; border-style: solid; } .tooltip.top .tooltip-arrow { bottom: 0; left: 50%; margin-left: -5px; border-top-color: #000000; border-width: 5px 5px 0; } .tooltip.right .tooltip-arrow { top: 50%; left: 0; margin-top: -5px; border-right-color: #000000; border-width: 5px 5px 5px 0; } .tooltip.left .tooltip-arrow { top: 50%; right: 0; margin-top: -5px; border-left-color: #000000; border-width: 5px 0 5px 5px; } .tooltip.bottom .tooltip-arrow { top: 0; left: 50%; margin-left: -5px; border-bottom-color: #000000; border-width: 0 5px 5px; } .popover { position: absolute; top: 0; left: 0; z-index: 1010; display: none; width: 236px; padding: 1px; background-color: #ffffff; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); -webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box; } .popover.top { margin-bottom: 10px; } .popover.right { margin-left: 10px; } .popover.bottom { margin-top: 10px; } .popover.left { margin-right: 10px; } .popover-title { padding: 8px 14px; margin: 0; font-size: 14px; font-weight: normal; line-height: 18px; background-color: #f7f7f7; border-bottom: 1px solid #ebebeb; -webkit-border-radius: 5px 5px 0 0; -moz-border-radius: 5px 5px 0 0; border-radius: 5px 5px 0 0; } .popover-content { padding: 9px 14px; } .popover-content p, .popover-content ul, .popover-content ol { margin-bottom: 0; } .popover .arrow, .popover .arrow:after { position: absolute; display: inline-block; width: 0; height: 0; border-color: transparent; border-style: solid; } .popover .arrow:after { z-index: -1; content: ""; } .popover.top .arrow { bottom: -10px; left: 50%; margin-left: -10px; border-top-color: #ffffff; border-width: 10px 10px 0; } .popover.top .arrow:after { bottom: -1px; left: -11px; border-top-color: rgba(0, 0, 0, 0.25); border-width: 11px 11px 0; } .popover.right .arrow { top: 50%; left: -10px; margin-top: -10px; border-right-color: #ffffff; border-width: 10px 10px 10px 0; } .popover.right .arrow:after { bottom: -11px; left: -1px; border-right-color: rgba(0, 0, 0, 0.25); border-width: 11px 11px 11px 0; } .popover.bottom .arrow { top: -10px; left: 50%; margin-left: -10px; border-bottom-color: #ffffff; border-width: 0 10px 10px; } .popover.bottom .arrow:after { top: -1px; left: -11px; border-bottom-color: rgba(0, 0, 0, 0.25); border-width: 0 11px 11px; } .popover.left .arrow { top: 50%; right: -10px; margin-top: -10px; border-left-color: #ffffff; border-width: 10px 0 10px 10px; } .popover.left .arrow:after { right: -1px; bottom: -11px; border-left-color: rgba(0, 0, 0, 0.25); border-width: 11px 0 11px 11px; } .thumbnails { margin-left: -20px; list-style: none; *zoom: 1; } .thumbnails:before, .thumbnails:after { display: table; line-height: 0; content: ""; } .thumbnails:after { clear: both; } .row-fluid .thumbnails { margin-left: 0; } .thumbnails > li { float: left; margin-bottom: 20px; margin-left: 20px; } .thumbnail { display: block; padding: 4px; line-height: 20px; border: 1px solid #ddd; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); -webkit-transition: all 0.2s ease-in-out; -moz-transition: all 0.2s ease-in-out; -o-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } a.thumbnail:hover { border-color: #0088cc; -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); } .thumbnail > img { display: block; max-width: 100%; margin-right: auto; margin-left: auto; } .thumbnail .caption { padding: 9px; color: #555555; } .label, .badge { font-size: 11.844px; font-weight: bold; line-height: 14px; color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); white-space: nowrap; vertical-align: baseline; background-color: #999999; } .label { padding: 1px 4px 2px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .badge { padding: 1px 9px 2px; -webkit-border-radius: 9px; -moz-border-radius: 9px; border-radius: 9px; } a.label:hover, a.badge:hover { color: #ffffff; text-decoration: none; cursor: pointer; } .label-important, .badge-important { background-color: #b94a48; } .label-important[href], .badge-important[href] { background-color: #953b39; } .label-warning, .badge-warning { background-color: #f89406; } .label-warning[href], .badge-warning[href] { background-color: #c67605; } .label-success, .badge-success { background-color: #468847; } .label-success[href], .badge-success[href] { background-color: #356635; } .label-info, .badge-info { background-color: #3a87ad; } .label-info[href], .badge-info[href] { background-color: #2d6987; } .label-inverse, .badge-inverse { background-color: #333333; } .label-inverse[href], .badge-inverse[href] { background-color: #1a1a1a; } .btn .label, .btn .badge { position: relative; top: -1px; } .btn-mini .label, .btn-mini .badge { top: 0; } @-webkit-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @-moz-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @-ms-keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } @-o-keyframes progress-bar-stripes { from { background-position: 0 0; } to { background-position: 40px 0; } } @keyframes progress-bar-stripes { from { background-position: 40px 0; } to { background-position: 0 0; } } .progress { height: 20px; margin-bottom: 20px; overflow: hidden; background-color: #f7f7f7; background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); background-repeat: repeat-x; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); } .progress .bar { float: left; width: 0; height: 100%; font-size: 12px; color: #ffffff; text-align: center; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #0e90d2; background-image: -moz-linear-gradient(top, #149bdf, #0480be); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); background-image: -webkit-linear-gradient(top, #149bdf, #0480be); background-image: -o-linear-gradient(top, #149bdf, #0480be); background-image: linear-gradient(to bottom, #149bdf, #0480be); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; -webkit-transition: width 0.6s ease; -moz-transition: width 0.6s ease; -o-transition: width 0.6s ease; transition: width 0.6s ease; } .progress .bar + .bar { -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); } .progress-striped .bar { background-color: #149bdf; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); -webkit-background-size: 40px 40px; -moz-background-size: 40px 40px; -o-background-size: 40px 40px; background-size: 40px 40px; } .progress.active .bar { -webkit-animation: progress-bar-stripes 2s linear infinite; -moz-animation: progress-bar-stripes 2s linear infinite; -ms-animation: progress-bar-stripes 2s linear infinite; -o-animation: progress-bar-stripes 2s linear infinite; animation: progress-bar-stripes 2s linear infinite; } .progress-danger .bar, .progress .bar-danger { background-color: #dd514c; background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); } .progress-danger.progress-striped .bar, .progress-striped .bar-danger { background-color: #ee5f5b; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-success .bar, .progress .bar-success { background-color: #5eb95e; background-image: -moz-linear-gradient(top, #62c462, #57a957); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); background-image: -webkit-linear-gradient(top, #62c462, #57a957); background-image: -o-linear-gradient(top, #62c462, #57a957); background-image: linear-gradient(to bottom, #62c462, #57a957); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); } .progress-success.progress-striped .bar, .progress-striped .bar-success { background-color: #62c462; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-info .bar, .progress .bar-info { background-color: #4bb1cf; background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); background-image: -o-linear-gradient(top, #5bc0de, #339bb9); background-image: linear-gradient(to bottom, #5bc0de, #339bb9); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); } .progress-info.progress-striped .bar, .progress-striped .bar-info { background-color: #5bc0de; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .progress-warning .bar, .progress .bar-warning { background-color: #faa732; background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); background-image: -webkit-linear-gradient(top, #fbb450, #f89406); background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(to bottom, #fbb450, #f89406); background-repeat: repeat-x; filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); } .progress-warning.progress-striped .bar, .progress-striped .bar-warning { background-color: #fbb450; background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); } .accordion { margin-bottom: 20px; } .accordion-group { margin-bottom: 2px; border: 1px solid #e5e5e5; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .accordion-heading { border-bottom: 0; } .accordion-heading .accordion-toggle { display: block; padding: 8px 15px; } .accordion-toggle { cursor: pointer; } .accordion-inner { padding: 9px 15px; border-top: 1px solid #e5e5e5; } .carousel { position: relative; margin-bottom: 20px; line-height: 1; } .carousel-inner { position: relative; width: 100%; overflow: hidden; } .carousel .item { position: relative; display: none; -webkit-transition: 0.6s ease-in-out left; -moz-transition: 0.6s ease-in-out left; -o-transition: 0.6s ease-in-out left; transition: 0.6s ease-in-out left; } .carousel .item > img { display: block; line-height: 1; } .carousel .active, .carousel .next, .carousel .prev { display: block; } .carousel .active { left: 0; } .carousel .next, .carousel .prev { position: absolute; top: 0; width: 100%; } .carousel .next { left: 100%; } .carousel .prev { left: -100%; } .carousel .next.left, .carousel .prev.right { left: 0; } .carousel .active.left { left: -100%; } .carousel .active.right { left: 100%; } .carousel-control { position: absolute; top: 40%; left: 15px; width: 40px; height: 40px; margin-top: -20px; font-size: 60px; font-weight: 100; line-height: 30px; color: #ffffff; text-align: center; background: #222222; border: 3px solid #ffffff; -webkit-border-radius: 23px; -moz-border-radius: 23px; border-radius: 23px; opacity: 0.5; filter: alpha(opacity=50); } .carousel-control.right { right: 15px; left: auto; } .carousel-control:hover { color: #ffffff; text-decoration: none; opacity: 0.9; filter: alpha(opacity=90); } .carousel-caption { position: absolute; right: 0; bottom: 0; left: 0; padding: 15px; background: #333333; background: rgba(0, 0, 0, 0.75); } .carousel-caption h4, .carousel-caption p { line-height: 20px; color: #ffffff; } .carousel-caption h4 { margin: 0 0 5px; } .carousel-caption p { margin-bottom: 0; } .hero-unit { padding: 60px; margin-bottom: 30px; background-color: #eeeeee; -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; } .hero-unit h1 { margin-bottom: 0; font-size: 60px; line-height: 1; letter-spacing: -1px; color: inherit; } .hero-unit p { font-size: 18px; font-weight: 200; line-height: 30px; color: inherit; } .pull-right { float: right; } .pull-left { float: left; } .hide { display: none; } .show { display: block; } .invisible { visibility: hidden; } .affix { position: fixed; } unbescape-unbescape-1.1.5.RELEASE/src/site/css/bootstrap.min.css000066400000000000000000002775651311410233600243610ustar00rootroot00000000000000/*! * Bootstrap v2.1.1 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Designed and built with all the love in the world @twitter by @mdo and @fat. */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}.text-warning{color:#c09853}.text-error{color:#b94a48}.text-info{color:#3a87ad}.text-success{color:#468847}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:1;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1{font-size:36px;line-height:40px}h2{font-size:30px;line-height:40px}h3{font-size:24px;line-height:40px}h4{font-size:18px;line-height:20px}h5{font-size:14px;line-height:20px}h6{font-size:12px;line-height:20px}h1 small{font-size:24px}h2 small{font-size:18px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:9px;font-size:14px;line-height:20px;color:#555;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal;cursor:pointer}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:18px;padding-left:18px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"]{float:left}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info>label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;font-size:14px;vertical-align:top;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append .add-on,.input-append .btn{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topleft:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5}table [class*=span],.row-fluid table [class*=span]{display:table-cell;float:none;margin-left:0}.table .span1{float:none;width:44px;margin-left:0}.table .span2{float:none;width:124px;margin-left:0}.table .span3{float:none;width:204px;margin-left:0}.table .span4{float:none;width:284px;margin-left:0}.table .span5{float:none;width:364px;margin-left:0}.table .span6{float:none;width:444px;margin-left:0}.table .span7{float:none;width:524px;margin-left:0}.table .span8{float:none;width:604px;margin-left:0}.table .span9{float:none;width:684px;margin-left:0}.table .span10{float:none;width:764px;margin-left:0}.table .span11{float:none;width:844px;margin-left:0}.table .span12{float:none;width:924px;margin-left:0}.table .span13{float:none;width:1004px;margin-left:0}.table .span14{float:none;width:1084px;margin-left:0}.table .span15{float:none;width:1164px;margin-left:0}.table .span16{float:none;width:1244px;margin-left:0}.table .span17{float:none;width:1324px;margin-left:0}.table .span18{float:none;width:1404px;margin-left:0}.table .span19{float:none;width:1484px;margin-left:0}.table .span20{float:none;width:1564px;margin-left:0}.table .span21{float:none;width:1644px;margin-left:0}.table .span22{float:none;width:1724px;margin-left:0}.table .span23{float:none;width:1804px;margin-left:0}.table .span24{float:none;width:1884px;margin-left:0}.table tbody tr.success td{background-color:#dff0d8}.table tbody tr.error td{background-color:#f2dede}.table tbody tr.warning td{background-color:#fcf8e3}.table tbody tr.info td{background-color:#d9edf7}.table-hover tbody tr.success:hover td{background-color:#d0e9c6}.table-hover tbody tr.error:hover td{background-color:#ebcccc}.table-hover tbody tr.warning:hover td{background-color:#faf2cc}.table-hover tbody tr.info:hover td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-tabs>.active>a>[class^="icon-"],.nav-tabs>.active>a>[class*=" icon-"],.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#08c;background-color:#0081c2;background-image:linear-gradient(to bottom,#08c,#0077b3);background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999}.dropdown-menu .disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 14px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #bbb;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:16px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.btn-large [class^="icon-"]{margin-top:2px}.btn-small{padding:3px 9px;font-size:12px;line-height:18px}.btn-small [class^="icon-"]{margin-top:0}.btn-mini{padding:2px 6px;font-size:11px;line-height:17px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#c5c5c5;border-color:rgba(0,0,0,0.15) rgba(0,0,0,0.15) rgba(0,0,0,0.25)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-image:-moz-linear-gradient(top,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-image:-moz-linear-gradient(top,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover{color:#333;text-decoration:none}.btn-group{position:relative;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1}.btn-toolbar .btn+.btn,.btn-toolbar .btn-group+.btn,.btn-toolbar .btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px}.btn-group>.btn-mini{font-size:11px}.btn-group>.btn-small{font-size:12px}.btn-group>.btn-large{font-size:16px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-top:0;border-bottom:5px solid #000}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical .btn{display:block;float:none;width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical .btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical .btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical .btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical .btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical .btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;color:#c09853;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible;color:#777}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px}.navbar-link{color:#777}.navbar-link:hover{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;width:100%;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.1),0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1);box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse{color:#999}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#fff}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-image:-moz-linear-gradient(top,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#ccc}.breadcrumb .active{color:#999}.pagination{height:40px;margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:0 14px;line-height:38px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager a,.pager span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next a,.pager .next span{float:right}.pager .previous a{float:left}.pager .disabled a,.pager .disabled a:hover,.pager .disabled span{color:#999;cursor:default;background-color:#fff}.modal-open .modal .dropdown-menu{z-index:2050}.modal-open .modal .dropdown.open{*z-index:2050}.modal-open .modal .popover{z-index:2060}.modal-open .modal .tooltip{z-index:2080}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;overflow:auto;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1030;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px}.tooltip.right{margin-left:3px}.tooltip.bottom{margin-top:3px}.tooltip.left{margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-bottom:10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-right:10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0}.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow:after{z-index:-1;content:""}.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-top-color:#fff;border-width:10px 10px 0}.popover.top .arrow:after{bottom:-1px;left:-11px;border-top-color:rgba(0,0,0,0.25);border-width:11px 11px 0}.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-right-color:#fff;border-width:10px 10px 10px 0}.popover.right .arrow:after{bottom:-11px;left:-1px;border-right-color:rgba(0,0,0,0.25);border-width:11px 11px 11px 0}.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-bottom-color:#fff;border-width:0 10px 10px}.popover.bottom .arrow:after{top:-1px;left:-11px;border-bottom-color:rgba(0,0,0,0.25);border-width:0 11px 11px}.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-left-color:#fff;border-width:10px 0 10px 10px}.popover.left .arrow:after{right:-1px;bottom:-11px;border-left-color:rgba(0,0,0,0.25);border-width:11px 0 11px 11px}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.label,.badge{font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .item>img{display:block;line-height:1}.carousel .active,.carousel .next,.carousel .prev{display:block}.carousel .active{left:0}.carousel .next,.carousel .prev{position:absolute;top:0;width:100%}.carousel .next{left:100%}.carousel .prev{left:-100%}.carousel .next.left,.carousel .prev.right{left:0}.carousel .active.left{left:-100%}.carousel .active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit p{font-size:18px;font-weight:200;line-height:30px;color:inherit}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} unbescape-unbescape-1.1.5.RELEASE/src/site/css/google-code-prettify/000077500000000000000000000000001311410233600250525ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/site/css/google-code-prettify/prettify.css000066400000000000000000000014611311410233600274340ustar00rootroot00000000000000.com { color: #93a1a1; } .lit { color: #195f91; } .pun, .opn, .clo { color: #93a1a1; } .fun { color: #dc322f; } .str, .atv { color: #D14; } .kwd, .prettyprint .tag { color: #1e347b; } .typ, .atn, .dec, .var { color: teal; } .pln { color: #48484c; } .prettyprint { padding: 8px; background-color: #f7f7f9; border: 1px solid #e1e1e8; } .prettyprint.linenums { -webkit-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; -moz-box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; box-shadow: inset 40px 0 0 #fbfbfc, inset 41px 0 0 #ececf0; } /* Specify class=linenums on a pre to get line numbering */ ol.linenums { margin: 0 0 0 33px; /* IE indents via margin-left */ } ol.linenums li { padding-left: 12px; color: #bebec5; line-height: 20px; text-shadow: 0 1px 0 #fff; }unbescape-unbescape-1.1.5.RELEASE/src/site/download.html000066400000000000000000000141221311410233600227270ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

Current version

Current version is 1.1.4.RELEASE (27 September 2016) ChangeLog

Maven info

  • groupId: org.unbescape
  • artifactId: unbescape
  • version: 1.1.4.RELEASE

Binary distribution

Binaries are distributed through the Sonatype Central Repository for Maven/Gradle/Ivy users.

Binary and source distributions can also be downloaded from GitHub.

Source distribution

You can download the latest source distribution of unbescape from GitHub.

Dependencies

unbescape requires Java SE 5.0 or newer. No additional dependencies are required.


unbescape-unbescape-1.1.5.RELEASE/src/site/faq.html000066400000000000000000000250441311410233600216740ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

Frequently Asked Questions


About unbescape


Where does unbescape come from? Is it made or backed by any software company?

unbescape is Open Source Software created in his spare time by a Spanish Software Engineer called Daniel Fernández, who's also the author of other popular java libraries like thymeleaf, attoparser, jasypt, op4j or javatuples.

It is neither made nor backed by any software (or any other type of) company, and it is offered to the public totally free of charge, both in binary and in source code forms, under the Apache License 2.0.


Does unbescape offer any type of commercial support?

No, it does not. Commercial support is not offered at the moment, but there is an issue tracking system at your disposal.


Is it stable? Can it be considered production-ready?

Yes, all stable (non-beta) releases can be considered production-ready.


How can I contribute to unbescape?

In many ways:

  • You can write in the issue tracking system (or directly to the Team) with your ideas for improving unbescape.
  • You can contribute some code, write a patch for a new feature or behaviour (please, tell the project admins first about your idea so that effort can be adequately coordinated).
  • You can write articles, reviews, blog posts, etc. about unbescape, showing how it works or how it integrates with other technologies.
  • You can promote unbescape in your company/work and among your colleague developers.

If you want to contribute some code to unbescape, please read first the page on Contributing to unbescape.


General


How can I use a SNAPSHOT release of unbescape?

From time to time, unbescape will produce a snapshot release that will allow you to test new or being-developed features. These are non production ready releases, but will be stable enough for most testing purposes, and will enable you to try new features before they are generally available.

In order to use snapshot releases, you need to add the Sonatype OSS Snapshots repository in your Maven pom.xml file, like this:

<repositories>
  <repository>
    <id>sonatype-nexus-snapshots</id>
    <name>Sonatype Nexus Snapshots</name>
    <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    <snapshots>
      <enabled>true</enabled>
    </snapshots>
  </repository>
</repositories>

Also, you will have to modify your unbescape dependency/ies to use a snapshot version, which usually consists of the version number of the next release (not the current one), followed by -SNAPSHOT. For example, meanwhile 1.1.4.RELEASE is the latest published stable release, snapshots will probably appear under the 1.1.5-SNAPSHOT or maybe 1.2.0-SNAPSHOT version numbers:

<dependency>
  <groupId>org.unbescape</groupId>
  <artifactId>unbescape</artifactId>
  <version>1.1.5-SNAPSHOT</version>
  <scope>compile</scope>
</dependency>

unbescape-unbescape-1.1.5.RELEASE/src/site/img/000077500000000000000000000000001311410233600210065ustar00rootroot00000000000000unbescape-unbescape-1.1.5.RELEASE/src/site/img/glyphicons-halflings-white.png000066400000000000000000000211111311410233600267520ustar00rootroot00000000000000PNG  IHDRӳ{PLTEmmmⰰᒒttt󻻻bbbeeeggg𶶶xxx󛛛Ƽ몪֢UUU鿿rOtRNS#_ /oS?C kDOS_6>4!~a @1_'onҋM3BQjp&%!l"Xqr; A[<`am}43/0IPCM!6(*gK&YQGDP,`{VP-x)h7e1]W$1bzSܕcO]U;Zi'y"؆K 64Y*.v@c.};tN%DI !ZЏ5LH26 ɯ" -bE,,)ʏ B>mn6pmRO wm@V#?'CȑZ#qb|$:)/E%nRqChn%i̓}lm ?idd",`H"r.z~(bQU&)5X#EMR<*p[[%.Ọk7lIoJF lV!̡ăuH`&,zRk$|$lXbjߪdU?Σ$HW$U'HE3*խU\}( zhVk}guRk$%|T|ck獳"D_W+.Q)@ƽHbslTDR2Xm#a 3lYzj㒚#! 4J8(cvt]aT D ΅Q?^-_^$:\V $N|=(vZ'q6Z׆B5V!y3K㱿bv4xR]al!IoP@tVyL٪mlڿIUb|[*lke'*WddDӝ}\W_WߝrN?vޫ۲X%0uoui*JVƦb%}i5IYlNE-wςf_W3mI-mQ)S kTC7m<"܌bT|'$ҘR&>O p6tSN\ׯLm\r@3uT b7t.5.q3r0=8TiJ\6uF R32^'ŪxI F8O{%8kJMSȴdBEdWCYO:/ON/I_=xFE! =i:o~ y?''[͓[͓[͓[͓[ͭ.U>$PƦc%]\c:| ,eSZ,oXrX!R@Zv 0>?* <|N60;{ad2v+D^t[q!۞V}fۨϏYeॗ)Vyl|" fUq@Ǽ4Y-Y-!6aB:o%JIUQ|UKO`=\ :0x Pau@!KPdxhw1>$j΍vZdxSUA&[URd7øzk/rU^w:I.VǮc>q.!zSr&2)Wg R -iQ 8Pa\ОU%iݡU_=p Lu(N?0?Æ:]άtB%U|NsorNf ,P !v" Y6hL_@@bscqgv4||0lϟ$S9bʱj#~?o}}7sAPm:IV=n !{{hEࢪ8suoLT$;VscqD3 ༂3.DBB4&V' T `D6Ϸqyj8V*X%@s\jrN$|=5Ά 'mUiKi%CI:ssaƅ`*`=l)>u՘MeuSI_OL_}o&jzp{lu:O)s%Q@$<]f xO%PCbhr2PKpf5Në3^o]eJiB464^tuٲU֌:G4'22YpuG'/Py4?.SBP_>I 1t3ΓBɭɭɭɭVVVVVs]!67(g y@ 4>Q VF}^Xׇڼje26 L%YGh lC})< !EEPZWZV+@†R 5{@ouɐ4&H6ey V݀VťcqZޒrJyByFzFN$Hb*+jՏqэ ګkݿUXle1d0d^-B%} {Y%r*j5Ak5u",:~ҸY~ hSA~6 fulՇf{ȵQtATHZkƭ/_Sn u']b]|m`BāJ,O$du]Zs FL:aǙT4o~by?wpj滥A(x]†f~an֧/^dڲcՇ,!1i&xi_VK@ip̓9Vi%a; L?0J*Ū5U'x^6V[^ {eU|:0=0d۫o*Jq%[YN.sQLud[29I:WnmXlڃ6!lNlVէKUjV\J%UߊBLcKfb>a=b~R]aG%[js@/9MطݘU>yɲX@} Ftg^vO\Ӹwvpz3K5i!$P>ā'VƛL2r@UMKZ6tw맟¦bm1h||]}~0MjA(JJP68C&yr׉e}j_cJ?I0k>šW |Bޝ."TEXd 8!cw*E(J)![W"j_ТeX_XB;oO0~?:PC (.[!Wq%*leY)E<^KZT60.#A\5;Rmtkd/8)5~^0 #Ckgey)ͶԺ6ĥ<(?&uAVm0^h.txR*a':,H|ō l5z;8+e#b'#|}2w(|KcJ l6 w^Տoi3H R ̔9,YgPְ:N [5SR![)]i}`mN4Хv`|;f(FltL8÷Z#AO%Y)NU5YedJE3dZذݣHT1 ;8MjnʏӤqp 1h^<<>yt{?|'j)}YUU{@V/J1F+7䀉[OWO[ yUY!?BD%DWj>-Ai6xz)U R7 d@g\so)a4zf[W+> P> |qLG8vȣlj2Zt+VA6gT *ʆUz(m)CD `He/.:zN9pgo &NC׃އ>Wհ_Hj)Xe6F7pm-`'c.AZ=^e8F;{Rtn(z!S7o Iew3]bܗ85|iϠRJkʱZRO+8U&:]ZieR(JMޗ7Z@5a^\GzsρU*rMezT^:ɬͦX=>$ bi>U&XQoybbGk8 Ҙn).Սo ^MmdZi$soo*{4eLbLٳ""mx:`:mk[geTެ)'0*TB{!I ''''[͓[͓[͓[͓[]Zj Q.e '/yvQ71(Z&X?(_Z){tڀmZWϏ)-C jqn,̋"IvUL!h꛿skAcrN佚фVE40yX~4zʸV㳰%,)fqtpu~  *^0:ܲ33JO(ZB?K^ v]unlWi0p6[착C_5X#[wX3b廫R{NKAe Se|wxso>P\儔ԕ6;nVmfI$V͓J-J%֌0UwYЎSnum藮xz˗VƫIvnW_qLZ"_Xz 8]Ap?C543zw({7e*Ȳ`۰!AQ:KUnz]1yVGaCm0PY ٚUx6TT&hV9V ӬzÑ 1[XzZ9erqJND/gX*9oN6D` {I%Mz9—TQ7f\"j_3~xB'ܷY]*KЌ%"5"qxq~ƕ=jS>jV&~]2xzF1X_yD<#NRB}K/iy !V^˿eJ}/FkA7 S+.(ecJ:zWZ몖wQ~ä́p6,e5,+,tv%O^OO}ן -O7>ekC6wa_C |9*WA)UJg8=:mjUvqysܒLglC6+[FSWg9wV31A ND<$5e(s[ ۨbaF.]KIENDB`unbescape-unbescape-1.1.5.RELEASE/src/site/img/glyphicons-halflings.png000066400000000000000000000307771311410233600256560ustar00rootroot00000000000000PNG  IHDRtEXtSoftwareAdobe ImageReadyqe<1IDATx}ml\EW^ɺD$|nw';vю8m0kQSnSV;1KGsԩ>UoTU1cƖYuּca&#C,pؚ>kں ULW -sn3Vq~NocI~L{- H8%_M£wB6EW,ĢpY2+(Y@&A/3kXhߍ-aA<>P'\J;(}#Qz:4%m?nfntK*l9J+DIYu1YZ^(]YYEf@ОlXz]Ut u &5-PW}@t|#LY=s܂,w#+R+?Ƌax X0"ea)tG*ԡwVwV^rf%xB(qּ4>WG#lWU<ЁXJVѶlR$kDVrI7:X%X1NEzw;y9z9O%~~uɗ*=Ixcy}Y(ou ±N$^j e\iX񝜬];Y-rѲ&>!zlYaVHVN԰9=]=mRMdOUC JUiT}rWW'ڹu)ʢF"YU#P׾&ܑЅROwyzm$Os? +^FTIEq%&~ >M}]ԖwA? [Nteexn(措BdMTpʥnqqS?bWXmW6x*{V_!VjΧsVL^j XkQjU6sk̩n~[qǸ-` O:G7l"ksRe2vQ=QƼJUX`gQy~ ďKȰE]#P:td\T/u;س:Jc-%'e q ?j"/yh48Zi1|JUu>_N;hxwNU JQU7\j̮bT:B?6oJ1Ί%I UY-Ii4{=rǤ7@)HKJ+f4X8Cd?'j1 N< 39EWo VTGzg# %D0#ܠ3[tiآ( U,]125|Ṋfw7w u+Š]Db]K xbW ՛7|ВX㕛{UcGXk¬|(h)IUa)lp 3luPU]D)/7~4Wt5J}V X0z VM;>Gԙ^|gF:jaZ^)74C#jwr,еSlGu;1vm><)}ZQՖ&mZ:1UMB~ a:/᜗:KWWOҠ&Y2f7cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘g*3fF5LbN2#Tf=C`!ZGUe꣇e2V<1mkS4iϗ*.{N8Xaj~ڀnAx,%fE:|YDVj ¢lg6(:k~MM5?4 ]WO>诋WZiG|QGJeK[YcյpmjE\f/ǎ8&OQ3 .3tt2'-V8pXSrY#J!Q ",ub@FK:u^iy[]<.Cw+W\)b kr-.MtڀMqʄ۰#$^X$"V`T4m~w%Pp1|+&UxY8*r8:k7QЃҀT$Ўƙ S>~Sjs:5q.w&_Z.X=:ވbw` _kd{'0:ds#qi!224nq\9-KUTsSUuVo@;Uz>^=Np>oPO @I@'Gj5o*U>^*ew>ͫʧ᫠Q5 ̈́<$#5Jٻj6e)_ d]2B:^(*:8JYS鬆Kݗ ]U4_rj{5ׇaǑ/yV?GtGb@xPU7O3|鍪 IQ5QGw *(;wf0*PUU<YƔvbt5{2!,}Ҧ:)j2OkΪ' ֊0I.q\(%ojQĖՇa<ԍexAgt'[d;׸`rcdjPFU$UeJI6T&Z}z(z vfuz {}ۿߝݞlxUZ謊.Y岟b%nw@ǩS9|źs%>_o#9\EU~/ځt(r[QZuOo;!MrU]0TcpDő?.cPuF;L_Sb}R/J_+h2$ai UǩS9>Є}76rzu~国4oĨ 1J ^̘~iC޸55G׹]gwsn zTuO=?/zƲc>Οb#7ֻcgkޛTUj*-T=]uu}>ݨNЭ [ ]:%/_ Sz]6D.mD7Uƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1c>J4hPP+A;'G_XKmL5I.},wFFum$S-E-;Õ C3I-`BRx1ғTJݕ;hΊ8 DYJo;Yš5MKɰM;%Pd9KhnD[zgVh,'C p!^M(WK2X>UQ%^p8 ˽^#Ζ؄+.@gCz%ɔ-Pr KX n>=ՔѨeSvRLz5%9UQS \WիK'hp)ô Jrh M0F (f_R5///G+x 1"eS 5 :Tf=+7Qɧ\TEs༬rYs8&k#pSՊ5MTbD܊[Ng5Q\s5PB@[8ɨV1&4Wsy[Ǿ wU2V77jމd^~YfC_h;a.&M i UWpzs`>/"'OI۲y:BzdTq£=йb:"m/-/PWDQǴ͐57m`H%AV!Hԛ׿@"Qzދ|ߒT-*OU^Ҧ6!Cwk|h&Hd5LEYy'ƣ7%*{=)Z%ٝP *G]/8Lw$?8M)\į/#7Ufd7'6\h1 vIfEIr=1w\WKVZHKgZ͡$mx % `j}TuTQJZ*H>*QxkLFTyU-)ôbiA|q`F'+ 4^Qy xH)#t^?@]^`ARSqjgB:rK۷l<2-4YKhgQLxVwP~M Φ0l 3ƅaŊITȀhwJmxIMչ|U7xˆS~2ߕ?kW1kC3];YnSґAeXYz8,'x< k7Kx]$x$vgT#w;o@ z_Vmn|HֵhZg-^TAn- )@4[*9xKƋj>!,Vt:eqn8%ohS(2\Q^aigF3vTUDVlQꅧWc%Ueq4ҝº/U $_Q!>t| ,țG<tC[xTXmf|Q%d#jUՆ|; H[bά#,Ws7NT1~m&ǻ{' \㟾 bBKJo8%!$Qj:/RX)$Sy޳ 䍧RDUg_D軦J\jN֖SU;~?Ohssdƣ}6(T <_4b5 ^N N%8QejF7toMyө`)g[/|?өJuGL坕/=CTܠhdifHcǞG4,`D՞{'xG_p/5@m +$jVH3a"*ũ,,HJҵȸT^Qyo&IÉJUVwWLeM~3tA6rwɤ6տ \0HL%LX5c@HHÃZ|NV+7WM{cig*ȸU7iÉбzd * ?gtX8̝OX:]2ɍ]p^++>AVڛE{ DB.&/56ArxY#ܕy)cKQtȪ~! ;C}ʃtf{6$NVsj wupZ)zŁ|-wg+nMVj/d+U~ͯi:_ix whqr>駃-x뼬)ݷyR=! ì:J/lIkV@n74758Z KJ(Uxz1w)^\ԣzȪ󲦨c2f؍v+6f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘2N oC\F1ִ UZJV̚\4Mgq1z{&YT ,HX~D u\g}x>+YdN̮ol ZX+F[/j+S~2/jV8Jr^ԉ]J}J*ۏ<2԰&JݣjOM@ѯ#0O[SXB^ uze\]dd./xXE f'vO_H${%;kt7ށmő|d{aފ^ǛڎE5ʋBr]W=_SAf(0 oU5q ,_\luz˪uz㻲o=Yi~| 0+=VJت /ލzM\zCL[U:|k*^8"\Wٚ\ .XTjX5 SkFu\1 q'mģ/QUؕ*AɽDNZ׮?_[# ˍ4:^j|5LG ||øBW{6[uQF.1$qF9IHg)\5>C#uXZ$#*<ߐsRv1Tj>Jm>*#( [Fhsש5*jQʼ&&&P犛L[Q1* ;X}Iΰ[Q?qQZ Hݙ֞VEsBCZ9JTK tup˷ /O,.kUdsOHMg4=-)+ؿh2Nw/r|WQn=GIU;'j,vfdzpe$V GTYsBZO1pj:r"nTUSCgr veAۘ˜FC+Ֆ#[JTe'v9-3 Dmӻuuz?0 o hxuY &_54=f07kלU0]D:jdw/+PGUVS<\2uatc^zYRąmC+7#,|:iNw*|^sm|X>Ъ^1\#͹ &%{,2U>ݎ.c05z# ogNO+Q쓭 ,˗-%K\[S_`y+b_94"U+Ύap}I[M,B.NtwHj漬E L߀ 0DX(kڵ NoU{gquz RwkէRx'uZ[3'zyyד%sƕ3jYF\s=m1&VAɼ?k\+]6yモ1gtOIW7al|1 >$]e 7؝WIe?ަL#>| ҭ] pM5MUdI61ԠeǼYGhOn3խR:^k_'Yuuq#p# J2xl>OjcY馃!ڡ+sZ/ D}2AY mpc#<'xSKx`*W[,e|6BH)㶤kjpDU(2qzx9*tqa/, Z[ 0>Ө֜xN)fă@qըFU՝w(a;ˋ>|Tc|w2eiT]*!_\WG{ ]^݅Z5t|6oYHaO@= my^akE.uz]#٥hWv(:,6A߉JFa\ wWex>vetuMYA>).,;ɦCbwjE)W Fӫ@s4e6^Q9oI}4x<.B?B߫#$Hx.x9,a!RTpgd5xBe.L7@* AsduttSVUaRU|I xG߃$T񭟬#_IFMŒ_X@foQIDII?|%$r {ENĸwޕqq?Dؽ}}o/`ӣCTi /ywO rD 9YUD] Ή@s]+'UaL} hrU'7:sU|k)H@hNq#ϵ8y˭Xű#w 1!흉R'7fuד0p!WÖW+Nmp\-ioD$g٠˅%%ÐmV]̱rw*Z}y+L Nouj}xt)lStuqxmNyKUOnDbhf}k>6ufT%{ <񐮸mjFcmUïc;w8@dGFUA& =nq5]iP}z:k⼶-ʓ Κl*'UzaxWFdZzTNRs+# wzgi:MBqtM l#^'Gߣ*^t{=rERnQ$adJl02%Tڊ^<~g?Of*U^?:N+o[PUs|QR']V-L)H K䐞 mYn\4}YVD hR;g-'3aסM Dh}1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌ3f̘1cƌk*Ț4`L$b U4\dt'>HȄ|.+Y+/Gy2OCWv3v,'kia W O6߯E=Hv $LlxI躍/}^]x\3 ɮ5 QT&G9Ay^i}O[5ޱwq4,s JJI.myE^%'VB~dׯ}*j* ~uTk\fKЬ*Y]_v'I˨鑩6Xo'j&uɧngT]oڌ9\*wVHӖ| >:5EF'J ɝ`!A e~_;5ױϊ镋m_&OVi<}"靍hW9X6KPƣ G"ƭ?/O^hCHLciPj)}QQզ#tMg9 xGw~d;_J+RỲ<;e 5/Qs/5N[!a+NPb+ѺI}-t_qU=MKʞY5no*vvbʊ{]| ~ Z{-끇^FVviϵ3Ya=6ndS;-ʹ^;uꪪ^ |=_w+"i&4l#wir|W3U$"J~O@]~tRJVMHw:̦@?>O?vdrtS*$&~1>Z}^nL(]f*&*QaIꝄ|3*O?r?*4Gyz[k/tkQϖWCCKk/x5|S*`ϹγQEwy o KYqTb$-/PtsZNKQ*>ݢU@Џ"JQ;¹& Lx;+T /+O赟> (T?ķD^N*'p$IW֐W~ =J|_UTe7ְP`;CYjk=sU[mߙ-;};2|wo1p0~>0m @Jrǟcٷ4͜?q\UUIV?2L/+Шꄾ< ܇^T ?tj\JrҀB*=km X,n}aՒIadp׷ll{\6v8RꅟҲf1F|Տ;e=\D ,D:ψrxQT◎*|{nS 9~=}ӕG~%j:Dj<ឫ:jO% $T8!jvm|'OЗ¹➱z\vsIv`Ȕʨj-^$-^G Q{m`T#c֞㸝|n.ߪN$O JUVʼt,jg-mסּNV z:(Ι*|1Ux=Yk*t MNNDUhK ؞X(刄Rv!#B_cxRŹoE5Dg>?fXQQ˔|@"աMveC>mO$H#]Y I=)_`k* :a>!X!W^wҒl'<;vwgIt_?Jh`#E:fdx=6Wu<Ӌd2di˂c#h¬c4?<HFYoVpN;ݷJ\ >` (t3{>⦊;;qFx4YcS$w.da*k|Q,+xs^K߫P^nO֮L5mIwl?-.ʲJ8 F B.-:2Ȕ!/A#b_m%I($|PZ[1G{^#o>3mw?'cx[^:Wk/`'=~֥W(gQbfv7UzM3+؍K:4|GCtA+Kʨ{@Ɩ [05E|yn4MIENDB`unbescape-unbescape-1.1.5.RELEASE/src/site/img/unbescape.png000066400000000000000000000041111311410233600234560ustar00rootroot00000000000000PNG  IHDRh|HsBIT|d pHYsxxtEXtSoftwarewww.inkscape.org<IDATX{Uu?spx#7$$!̨TpPtPJF tHɰ I 3^!N%-PV(w|p805Ú{~k[}DS@z;iO T`ʆS q\쏣d8 ƝӠ[NڬڤÙ@gAO w4>8 o_x*~D%mr˿ ,:)A8 ލ`r+blB`60?cZԥ`*>ʠ?ڜDڡQcumeX XB`>SB<T1&O&[Np B] Iq\X*zbQ`U (m~$]QR(Unp[D@H"nG0NK%LSUܲTT_u%nBC4G>p2]SmԩhEtI]l.vvJYD_hC% pz H.h$mw{KlQϊ?oG_%\U0`J'^q6p#f׾ {*= <= -:{H\fdn xeL@a`p0*͚=%EwV]hl*i k@w;0l^"u`T) \l6i02MˋW*S ^woXz ̜u"1L&@cZgg0X̠۾ua `Sl[bnG`lɻ6`x:_rwxX\Y 6sM>vfB/_vs ˏf 8 j̠Mq3\N !3`| v5>Qȍ[m09KP,lm^l|ө3fO݀9@W`3pm*ғ bENc*p#%z}8 .-g؊ 0"z@_` n8 *mlK^Ȁ.1B6!S@r `du.j)G UA]m WKp[z unh-E|YS-}L\L` TG7{ $r^~]?# i Q']FJdO<o׎l$noMLPӢ1 t of/P;AZNHœblyވ͊YH?aBާ9s]-(sϣ ˁECiqN|ˀ ``2+YP Xc9hPur}ZIU(==5U) 傋~9| 5ӑr+J.@7l; <6s4C/t{o>dd7C+쐰&P9h d/ ~/IENDB`unbescape-unbescape-1.1.5.RELEASE/src/site/img/unbescape_motto.png000066400000000000000000000114211311410233600247020ustar00rootroot00000000000000PNG  IHDRsBIT|d pHYs  ԥ$tEXtSoftwarewww.inkscape.org<IDATxy_?IH$CbLLW<KjH҆5T(!TcWj(mҚy H绝}vsreoy}Z-\-h,$w_67=*,-Sv$_ i{@1-"MDR(k"baQɻVN/ҳ#K#%?ڐ0"));$"N+|s%݂/MG`y`e|y>zHz+޳z=pzzB{; \FIჱ"z"⟋1ou~ ף{15S?ED=48x:= :5!iYB|Vi,1"iLa=r|Vcj Lv'>`)"p$<\wE_ mNgoIc62*[@7>I=#Tp37qgroV^w0RRh$pg'dI06pl׹V2jev`_`-3p0'%f,iS`4ˌ2V-nGyM\16=ojf<_I!^鿧qWa\_J:vf^BЫUQ'oXbqJbMx)פ75!+ DMc&&bccdaFK:`rgW=/z)+ QDi>)++knI>gs<^h 9"^h\ڮ=W@x=/1/;2xN uMc="5cU $uٹwiJޑ<$ gXCʗvk2 {_'gcy6] ),7n*舘[{wQ~cFl <-iψxGD*{eFlIx}KI;KhJIԷoբV$ Jl^&4$̞ύgelQ[\{xvLJ)/{UwvB5_L <#i4-b#b8pKmSs`ջPv:{A1C҅~7WwgIEG}H_"bp+!=IҐx.Fks 0ΏS0 I}G~7-ɐ 덿55]_8 DչgqXIӀ r‚x,f!2Xsǿ'6,(M"5I`z|ڷw~B|.sG3%T|IFDܘ9MkWE '"浮xy7 ;w151 6] 23%t/`Sa֖YOŴQM[l/Riiإo=A3W/6_H$Y( BR4ZU$ 4X^.4`{RnI`32af_klT_N$!be`sBRd=DRc% [QPczuwLY6uOm(xz>76F_ 됤z`**LB ,IRЊouKS@a.c],+C`'c+]|V׉x~U8 tI %dO#+i̙8<) Ӏ"jiP.s+)'/_o>7J:L&62WΘ>\$@IYq" a 3f8x1"NTO{ꄚAiୀ+SrBHoԠ?$VaxB_ރ͵ceDʲ=656H}3Rd3zasCj5H7[sSpd4t9`'lL07 c1SvGļ\?Pt$]%Mk[1l:Ed{{`7~w{ZOo wxL.Qr.Ί#r)0:V8 Y;86Y=p<$p\D7a#ܘVgb6J*".w~bD/VQrB?Db 1,HPW^tr|_2B n <o;<1W}cj(d$<*Ee.">k~3_tL/fubh0C%x/s c FBVD܉tI&8$`EZYVJ 5oE.+"""Mm֧Υ=Vj,ć3g`-#b!"vכ%mz [=$b{L[cOSKy|kD1!"g&BL]]U'a 擻GĠ*"Fb1Iy~{.D,cE sL'v3<0X$U@ByG={sr&i .—)߭>x`ſݒFLmnkKD̎_bch^R8ϩ555<gyRt'% ;"?zg8mU4"9D=xx锌Ԫck""$>8{dZ=3-"F`Ef*06j#;"h,c15~Pz48.t. ,Τ8 TDĻU; LM.&K`G ׼ l-WV ֥.^E{P.ł5J<:GDw?lm7[ժ d%O MuW"uimX(^B`'Ǔ<~qRŸR]MD%84.qu՝1j4=ZcgFJsO`?0Ńv1ݭہSp:ofd B3I?Še!N)r/țlQ!0&_03r^ֽyM/E]QZZy^0^6Ae̺(bC%) ܏ eNUa-JE1KN& u^tNYUKEoiJ0276P| m> y9GBz p`>Po3sODLIҤ{8=4ȋAT{U})O SE 8d@*x%wVjX:ksE̋oYA 6;7sLVAn2NG9?wgl}^k {<q9uwI`.<ֈB'8yྜ2de5a*DayV;G}|!ǔ(?T^/aG;e^a(e / mF_`(|,g!Hc+7 KD-IoDO -hC[ЂFE-h2%ԇY-hAc/х*\ovIENDB`unbescape-unbescape-1.1.5.RELEASE/src/site/index.html000066400000000000000000000701061311410233600222330ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

What is unbescape?

unbescape is a Java library aimed at performing fully-featured and high-performance escape and unescape operations for:

  • HTML (HTML5 and HTML 4)
  • XML (XML 1.0 and XML 1.1)
  • JavaScript
  • JSON
  • URI / URL (both paths and query parameters)
  • CSS (both identifiers and string literals)
  • CSV (Comma-Separated Values)
  • Java literals
  • Java .properties files (both keys and values)

Its goals are:

  • To be easy to use. Few lines of code needed. No additional dependencies.
  • To be fast. Faster and lighter than most other options available in Java.
  • To be versatile. Provides different escaping types and levels in order to better adapt to different scenarios and contexts.
  • To be feature-complete. Includes full HTML5 support, careful implementation of the JavaScript, JSON, Java, etc specifications, streaming support...

What does it look like? Why should I use it?

Performing an unescape operation on HTML code is as easy as:

final String unescapedText = HtmlEscape.unescapeHtml(escapedText);

Note this includes support for unescaping HTML5's more than 2,300 entities or named character references (like &tcedil; = 'ţ'). And also decimal/hexadecimal references (like &#225; or &#xE1; = 'á'). And the full Unicode character set, including codepoints > U+FFFF (like &#x20000; = '𠀀'). And even performing a good amount of magic included in the HTML5 specification (like allowing some references not to end in a semicolon, like &aacute = 'á'). So this text:

In order to have full HTML support, escape tools should provide
complete support for characters like the Czech letter '&Tcaron;'
or the Chinese symbol '&#x200AD;'. And implement some legacy
compatibility rules like displaying an &ldquo;A with an acute
accent&rdquo; like '&aacute' or an EURO symbol like '&#x80;'.

...will be unescaped as:

In order to have full HTML support, escape tools should provide
complete support for characters like the Czech letter 'Ť' or the
Chinese symbol '𠂭'. And implement some legacy-compatibility rules
like displaying an “A with an acute accent” like 'á' or an EURO
symbol like '€'.

(If you don't believe the code above is valid HTML5, just click View Source on your HTML5-enabled browser and look for "HTML5-SAMPLE" ;))

Escape operations are also extremely powerful, allowing you to (optionally) determine the type and level of escape you want. For example, this:

final String escapedText =
        HtmlEscape.escapeHtml(
                unescapedText,
                HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);

...will perform an HTML escape operation using the HTML 4 set of entities (named character references), defaulting to decimal escapes when needed. But because the established level is 1, only the markup significant characters will be escaped: &lt;, &gt;, &amp;, &quot; and &#39; (there is no &apos; in HTML 4, only in HTML5).

Easy, preconfigured methods are already provided, in fact the above call is equivalent to:

final String escapedText = HtmlEscape.escapeHtml4Xml(unescapedText);

This kind of escape is called HTML4-XML because is mimics the behaviour of the escapeXml attribute in JSP <c:out /> tags.

Want to ensure your escaped text is ASCII-only? Easy: use level 2 and the results will be entirely composed of characters under U+007F —bye-bye complex encoding issues!—. Let's try this time with HTML5:

final String escapedText =
        HtmlEscape.escapeHtml(
                unescapedText,
                HtmlEscapeType.HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL,
                HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);

Which in fact is the same as the preconfigured:

final String escapedText = HtmlEscape.escapeHtml5(unescapedText);
But of course, Unbescape is much more than HTML: XML, JavaScript, JSON, CSS... have a look at the large feature list below to know more.

The features

High performance
  • No unneeded String or char[] objects are created, and specific optimizations are applied in order to provide maximum performance and reduce Garbage Collector latency (e.g. if a String has the same content after escaping/unescaping, exactly the same String object is returned, no copy is made).
  • Support is provided for escape and unescape operations in streaming mode, so that input can be directly read from a java.io.Reader, escaped/unescaped and then output to a java.io.Writer without the need to store potentially large chunks of text in memory. Especially useful in web application environments where the escaped/unescaped text can be directly written to the response writer (and thus sent to the browser/client) as soon as it is produced.
  • See (and execute) the benchmark.sh script in the unbescape-tests repository for specific figures.
Highly configurable
  • Most escaped languages allow specifying the type of escape to be performed: based on literals, on decimal numbers, hexadecimal, octal, etc.
  • Most escaped languages allow specifying the level of escape to be performed: only escape the basic set, escape all non-ASCII characters, escape all non-alphanumeric, etc.
  • Provides sensible defaults and pre-configured, easy-to-use methods.
Documented API
  • Includes full JavaDoc API documentation for all public classes, explaining each escape and unescape operation in detail.
  • See the JavaDoc API Documentation.
Unicode
  • All escape and unescape operations support the whole Unicode character set: U+0000 to U+10FFFF, including characters not representable by only one char in Java (>U+FFFF).
HTML
  • Whole HTML5 NCR (Named Character Reference) set supported, if required: &rsqb;,&NewLine;, etc. (HTML 4 set available too).
  • Mixed named and numerical (decimal or hexa) character references supported.
  • Ability to default to numerical (decimal or hexa) references when an applicable NCR does not exist (depending on the selected operation level).
  • Support for unescape of double-char NCRs in HTML5: &fjlig;fj.
  • Support for a set of HTML5 unescape tweaks included in the HTML5 specification:
    • Unescape of numerical character references not ending in semi-colon (e.g. &#x23ac).
    • Unescape of specific NCRs not ending in semi-colon (e.g. &aacute).
    • Unescape of specific numerical character references wrongly specified by their Windows-1252 codepage code instead of the Unicode one (e.g. &#x80; for (&euro;) instead of &#x20ac;).
XML
  • Support for both XML 1.0 and XML 1.1 escape/unescape operations.
  • No support for DTD-defined or user-defined entities. Only the five predefined XML character entities are supported: &lt;, &gt;, &amp;, &quot; and &apos;.
  • Automatic escaping of allowed control characters.
JavaScript
  • Support for the JavaScript basic escape set: \0, \b, \t, \n, \v, \f, \r, \", \', \\. Note that \v (U+000B) will not be used in escape operations (only unescape) because it is not supported by Microsoft Internet Explorer versions < 9.
  • Automatic escape of / (as \/ if possible) when it appears after <, as in </something>.
  • Support for escaping non-displayable, control characters: U+0001 to U+001F and U+007F to U+009F.
  • Support for X-based hexadecimal escapes (a.k.a. hexadecimal escapes) both in escape and unescape operations: \xE1.
  • Support for U-based hexadecimal escapes (a.k.a. unicode escapes) both in escape and unescape operations: \u00E1.
  • Support for Octal escapes, though only in unescape operations: \071. Not supported in escape operations (octal escapes were deprecated in version 5 of the ECMAScript specification).
JSON
  • Support for the JSON basic escape set: \b, \t, \n, \f, \r, \", \\.
  • Automatic escape of / (as \/ if possible) when it appears after <, as in </something>.
  • Support for escaping non-displayable, control characters: U+0000 to U+001F and U+007F to U+009F.
  • Support for U-based hexadecimal escapes (a.k.a. unicode escapes) both in escape and unescape operations: \u00E1.
URI / URL
  • Support for escape operations using percent-encoding (%HH).
  • Escape URI paths, path fragments, query parameters and fragment identifiers.
CSS
  • Complete set of CSS Backslash Escapes supported (e.g. \+, \;, \(, \), etc.).
  • Full set of escape syntax rules supported, both for CSS identifiers and CSS Strings (or literals).
  • Non-standard tweaks supported: \: not used because of lacking support in Internet Explorer < 8, \_ escaped at the beginning of identifiers for better Internet Explorer 6 support, etc.
  • Hexadecimal escapes (a.k.a. unicode escapes) are supported both in escape and unescape operations, and both in compact (\E1 ) and six-digit forms (\0000E1).
  • Support for unescaping unicode characters >\uFFFF both when represented in standard form (one char, \20000) and non-standard (surrogate pair, \D840\DC00, used by older WebKit browsers).
CSV (Comma-Separated Values)
  • Works according to the rules specified in RFC4180 (there is no CSV standard as such).
  • Encloses escaped values in double-quotes ("value") if they contain any non-alphanumeric characters.
  • Escapes double-quote characters (") by writing them twice: "".
  • Honors rules for maximum compatibility with Microsoft Excel.
Java literals
  • Support for the Java basic escape set: \b, \t, \n, \f, \r, \", \', \\. Note \' will not be used in escaping levels < 3 (= all but alphanumeric) because escaping the apostrophe is not really required in Java String literals (only in Character literals).
  • Support for escaping non-displayable, control characters: U+0001 to U+001F and U+007F to U+009F.
  • Support for U-based hexadecimal escapes (a.k.a. unicode escapes) both in escape and unescape operations: \u00E1.
  • Support for Octal escapes, though only in unescape operations: \071. Not supported in escape operations (use of octal escapes is not recommended by the Java Language Specification).
Java .properties files
  • Support for the Java Properties basic escape set: \t, \n, \f, \r, \\. When escaping .properties keys (not values) \ , \: and \= will be applied too.
  • Support for escaping non-displayable, control characters: U+0001 to U+001F and U+007F to U+009F.
  • Support for U-based hexadecimal escapes (a.k.a. unicode escapes) both in escape and unescape operations: \u00E1.

How is it distributed?

unbescape is Open Source Software, and it is distributed under the terms of the Apache License 2.0.

Project status

unbescape is stable and production-ready. Current version is 1.1.4.RELEASE.


unbescape-unbescape-1.1.5.RELEASE/src/site/issuetracking.html000066400000000000000000000117521311410233600240010ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

Issue tracking

Bugs, discussions and enhancement requests are managed at GitHub: https://github.com/unbescape/unbescape/issues


unbescape-unbescape-1.1.5.RELEASE/src/site/javadoc.html000066400000000000000000000121411311410233600225260ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

JavaDoc API

Current version

Version 1.1.4.RELEASE: unbescape 1.1.4.RELEASE API

Older versions

Version 1.0: unbescape 1.0 API


unbescape-unbescape-1.1.5.RELEASE/src/site/license.html000066400000000000000000000376021311410233600225520ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

Apache License 2.0


                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


unbescape-unbescape-1.1.5.RELEASE/src/site/team.html000066400000000000000000000137551311410233600220610ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

Team

The team is comprised of Members and Contributors. Members have direct access to the source of a project and actively evolve the code-base. Contributors improve the project through submission of patches and suggestions to the Members. The number of Contributors to the project is unbounded. Get involved today. All contributions to the project are greatly appreciated!

Members

GitHub ID Name Location Email Role
danielfernandez Daniel Fernández Spain daniel.fernandez AT 11thlabs.org Lead Developer (Project founder)

unbescape-unbescape-1.1.5.RELEASE/src/site/usingunbescape.html000066400000000000000000000601161311410233600241370ustar00rootroot00000000000000 unbescape: powerful, fast and easy escape/unescape operations for Java

HTML

Escape/unescape utility class: org.unbescape.html.HtmlEscape

Configuration
  • Escape Types: org.unbescape.html.HtmlEscapeType
    • HTML4_NAMED_REFERENCES_DEFAULT_TO_DECIMAL
    • HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA
    • HTML5_NAMED_REFERENCES_DEFAULT_TO_DECIMAL
    • HTML5_NAMED_REFERENCES_DEFAULT_TO_HEXA
    • DECIMAL_REFERENCES
    • HEXADECIMAL_REFERENCES
  • Escape Levels: org.unbescape.html.HtmlEscapeLevel
    • LEVEL_0_ONLY_MARKUP_SIGNIFICANT_EXCEPT_APOS
    • LEVEL_1_ONLY_MARKUP_SIGNIFICANT
    • LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT
    • LEVEL_3_ALL_NON_ALPHANUMERIC
    • LEVEL_4_ALL_CHARACTERS
Escaping

Some sample code (see the javadoc for more detail):

final String escaped = HtmlEscape.escapeHtml5(text);
final String escaped = HtmlEscape.escapeHtml4Xml(text);
final String escaped =
        HtmlEscape.escapeHtml(
             text,
             HtmlEscapeType.HTML4_NAMED_REFERENCES_DEFAULT_TO_HEXA,
             HtmlEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = HtmlEscape.unescapeHtml(text);

XML

Escape/unescape utility class: org.unbescape.xml.XmlEscape

Configuration
  • Escape Types: org.unbescape.xml.XmlEscapeType
    • CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_DECIMAL
    • CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_HEXA
    • DECIMAL_REFERENCES
    • HEXADECIMAL_REFERENCES
  • Escape Levels: org.unbescape.xml.XmlEscapeLevel
    • LEVEL_1_ONLY_MARKUP_SIGNIFICANT
    • LEVEL_2_ALL_NON_ASCII_PLUS_MARKUP_SIGNIFICANT
    • LEVEL_3_ALL_NON_ALPHANUMERIC
    • LEVEL_4_ALL_CHARACTERS
Escaping

Some sample code (see the javadoc for more detail):

final String escaped = XmlEscape.escapeXml11(text);
final String escaped = XmlEscape.escapeXml10Minimal(text);
final String escaped =
        XmlEscape.escapeXml11(
             text,
             XmlEscapeType.CHARACTER_ENTITY_REFERENCES_DEFAULT_TO_DECIMAL,
             XmlEscapeLevel.LEVEL_3_ALL_NON_ALPHANUMERIC);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = XmlEscape.unescapeXml(text);

JavaScript

Escape/unescape utility class: org.unbescape.javascript.JavaScriptEscape

Configuration
  • Escape Types: org.unbescape.javascript.JavaScriptEscapeType
    • SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA
    • SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA
    • XHEXA_DEFAULT_TO_UHEXA
    • UHEXA
  • Escape Levels: org.unbescape.javascript.JavaScriptEscapeLevel
    • LEVEL_1_BASIC_ESCAPE_SET
    • LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET
    • LEVEL_3_ALL_NON_ALPHANUMERIC
    • LEVEL_4_ALL_CHARACTERS
Escaping

Some sample code (see the javadoc for more detail):

final String escaped = JavaScriptEscape.escapeJavaScript(text);
final String escaped =
        JavaScriptEscape.escapeJavaScript(
             text,
             JavaScriptEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO_XHEXA_AND_UHEXA,
             JavaScriptEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = JavaScriptEscape.unescapeJavaScript(text);

JSON

Escape/unescape utility class: org.unbescape.json.JsonEscape

Configuration
  • Escape Types: org.json.javascript.JsonEscapeType
    • SINGLE_ESCAPE_CHARS_DEFAULT_TO_UHEXA
    • UHEXA
  • Escape Levels: org.json.javascript.JsonEscapeLevel
    • LEVEL_1_BASIC_ESCAPE_SET
    • LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET
    • LEVEL_3_ALL_NON_ALPHANUMERIC
    • LEVEL_4_ALL_CHARACTERS
Escaping

Some sample code (see the javadoc for more detail):

final String escaped = JsonEscape.escapeJson(text);
final String escaped =
        JsonEscape.escapeJson(
             text,
             JsonEscapeType.SINGLE_ESCAPE_CHARS_DEFAULT_TO__UHEXA,
             JsonEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = JsonEscape.unescapeJson(text);

URI/URL

Escape/unescape utility class: org.unbescape.uri.UriEscape

Escaping

Some sample code (see the javadoc for more detail):

final String escapedPath = UriEscape.escapeUriPath(text);
final String escapedPathSegment = UriEscape.escapeUriPathSegment(text);
final String escapedQueryParam = UriEscape.escapeUriQueryParam(text);
final String escapedFragmentId = UriEscape.escapeUriFragmentId(text);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescapedPath = UriEscape.unescapeUriPath(text);
final String unescapedPathSegment = UriEscape.unescapeUriPathSegment(text);
final String unescapedQueryParam = UriEscape.unescapeUriQueryParam(text);
final String unescapedFragmentId = UriEscape.unescapeUriFragmentId(text);

CSS

Escape/unescape utility class: org.unbescape.css.CssEscape

Configuration
  • Escape Types: org.unbescape.css.CssIdentifierEscapeType / org.unbescape.css.CssStringEscapeType
    • BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA
    • BACKSLASH_ESCAPES_DEFAULT_TO_SIX_DIGIT_HEXA
    • COMPACT_HEXA
    • SIX_DIGIT_HEXA
  • Escape Levels: org.unbescape.css.CssIdentifierEscapeLevel / org.unbescape.css.CssStringEscapeLevel
    • LEVEL_1_BASIC_ESCAPE_SET
    • LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET
    • LEVEL_3_ALL_NON_ALPHANUMERIC
    • LEVEL_4_ALL_CHARACTERS
Escaping

Some sample code (see the javadoc for more detail):

final String escapedIdentifier = CssEscape.escapeCssIdentifier(text);
final String escapedString = CssEscape.escapeCssString(text);
final String escapedIdentifier =
        CssEscape.escapeCssIdentifier(
             text,
             CssIdentifierEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_SIX_DIGIT_HEXA,
             CssIdentifierEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET);
final String escapedString =
        CssEscape.escapeCssString(
             text,
             CssStringEscapeType.BACKSLASH_ESCAPES_DEFAULT_TO_COMPACT_HEXA,
             CssStringEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = CssEscape.unescapeCss(escapedIdentifierOrString);

CSV (Comma-Separated Values)

Escape/unescape utility class: org.unbescape.csv.CsvEscape

Escaping

Some sample code (see the javadoc for more detail):

final String escaped = CsvEscape.escapeCsv(text);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = CsvEscape.unescapeCsv(text);

Java literals

Escape/unescape utility class: org.unbescape.java.JavaEscape

Configuration
  • Escape Levels: org.unbescape.java.JavaEscapeLevel
    • LEVEL_1_BASIC_ESCAPE_SET
    • LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET
    • LEVEL_3_ALL_NON_ALPHANUMERIC
    • LEVEL_4_ALL_CHARACTERS
Escaping

Some sample code (see the javadoc for more detail):

final String escaped = JavaEscape.escapeJava(text);
final String escaped =
        JavaEscape.escapeJava(
             text,
             JavaEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = JavaEscape.unescapeJava(escaped);

Java .properties files

Escape/unescape utility class: org.unbescape.properties.PropertiesEscape

Configuration
  • Escape Levels: org.unbescape.properties.PropertiesKeyEscapeLevel / org.unbescape.properties.PropertiesValueEscapeLevel
    • LEVEL_1_BASIC_ESCAPE_SET
    • LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET
    • LEVEL_3_ALL_NON_ALPHANUMERIC
    • LEVEL_4_ALL_CHARACTERS
Escaping

Some sample code (see the javadoc for more detail):

final String escapedKey = PropertiesEscape.escapePropertiesKey(text);
final String escapedString = PropertiesEscape.escapePropertiesValue(text);
final String escapedKey =
        PropertiesEscape.escapePropertiesKey(
             keyText, PropertiesKeyEscapeLevel.LEVEL_2_ALL_NON_ASCII_PLUS_BASIC_ESCAPE_SET);
final String escapedValue =
        PropertiesEscape.escapePropertiesValue(
             valueText, PropertiesValueEscapeLevel.LEVEL_1_BASIC_ESCAPE_SET);
Unescaping

Some sample code (see the javadoc for more detail):

final String unescaped = PropertiesEscape.unescapeProperties(escapedKeyOrValue);