diff --git a/xmlbeans/CHANGES.txt b/xmlbeans/CHANGES.txt index 4140cddc33..9afc32488b 100644 --- a/xmlbeans/CHANGES.txt +++ b/xmlbeans/CHANGES.txt @@ -1,3 +1,20 @@ +Changes in V2.6.4 since V2.6.3 + +* Remove Piccolo support +* Apply XML Entity Expansion security checks + +Changes in V2.6.3 since V2.6.2 + +* ArrayIndexOutOfBoundsException when writing CDATA (https://issues.apache.org/jira/browse/XMLBEANS-404) + +Changes in V2.6.2 since V2.6.1 + +* Duplicate classes in jar (https://issues.apache.org/jira/browse/XMLBEANS-499) + +Changes in V2.6.1 since V2.6.0 + +* Fix for Unicode Surrogate chars being lost when writing XML (https://bz.apache.org/bugzilla/show_bug.cgi?id=54084 & https://issues.apache.org/jira/browse/XMLBEANS-332) + Changes in V2.6.0 since V2.5.0 * Add new xml option CopyUseNewSynchronizationDomain used for copy. diff --git a/xmlbeans/README.md b/xmlbeans/README.md new file mode 100644 index 0000000000..17453f8544 --- /dev/null +++ b/xmlbeans/README.md @@ -0,0 +1,24 @@ +# xmlbeans + +[![Build Status](https://travis-ci.org/pjfanning/xmlbeans.svg?branch=trunk)](https://travis-ci.org/pjfanning/xmlbeans) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.pjfanning/xmlbeans/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.pjfanning/xmlbeans) + +Latest source from ```http://svn.apache.org/repos/asf/xmlbeans/trunk/```. Some changes have been made to get the build working. + +The core use case is to help users of Apache Poi, which depends on the no longer maintained Apache XMLBeans library. + +* Release 2.6.1 includes a fix for an issue where Unicode Surrogate chars were replaced with `?` chars ?when outputting files - https://bz.apache.org/bugzilla/show_bug.cgi?id=54084 +* fixes an issue affecting usage on Android: https://issues.apache.org/jira/browse/XMLBEANS-499 + +## Sample + +https://github.com/pjfanning/poi-xmlbeans-patch-test + +## Build +``` +./xbeanenv.sh +ant +ant checkintest +``` + +Output jar is found at ```build/lib/xbean.jar``` diff --git a/xmlbeans/build.xml b/xmlbeans/build.xml index 2505a36dde..e7c27f5316 100644 --- a/xmlbeans/build.xml +++ b/xmlbeans/build.xml @@ -15,11 +15,11 @@ --> - - - + + + - + @@ -128,39 +128,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -353,12 +320,8 @@ - - - - @@ -488,7 +451,7 @@ store.classes, saaj_api.classes, marshal.classes, xpath.classes, oldxbean.jar, xsdschema.classes, xmlinputstream.classes, resolver.jar, xbean_xpath.jar, - piccolo.classes, tools.classes, jamsupport.classes"> + tools.classes, jamsupport.classes"> @@ -509,7 +472,6 @@ - @@ -523,10 +485,6 @@ - - - @@ -545,12 +503,10 @@ - + - - - + @@ -586,7 +542,6 @@ - @@ -597,11 +552,10 @@ - + - @@ -639,7 +593,7 @@ + configschema.classes, toolschema.classes, jam.classes"> @@ -655,7 +609,6 @@ - @@ -681,7 +634,6 @@ - @@ -691,17 +643,17 @@ + - + - @@ -738,17 +690,15 @@ + depends="dirs, common.classes, xmlpublic.classes, typestore.classes, saaj_api.classes"> - - @@ -756,18 +706,16 @@ - - @@ -784,13 +732,11 @@ - - @@ -834,7 +780,7 @@ - + @@ -919,7 +865,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/xmlbeans/external/lib/piccolo.LICENSE.txt b/xmlbeans/external/lib/piccolo.LICENSE.txt deleted file mode 100644 index 57bc88a15a..0000000000 --- a/xmlbeans/external/lib/piccolo.LICENSE.txt +++ /dev/null @@ -1,202 +0,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. - diff --git a/xmlbeans/external/lib/piccolo_apache_dist_20040629.jar b/xmlbeans/external/lib/piccolo_apache_dist_20040629.jar deleted file mode 100644 index 7113ab63ce..0000000000 Binary files a/xmlbeans/external/lib/piccolo_apache_dist_20040629.jar and /dev/null differ diff --git a/xmlbeans/external/lib/piccolo_apache_dist_20040629_v2.jar b/xmlbeans/external/lib/piccolo_apache_dist_20040629_v2.jar deleted file mode 100644 index 66f4e24844..0000000000 Binary files a/xmlbeans/external/lib/piccolo_apache_dist_20040629_v2.jar and /dev/null differ diff --git a/xmlbeans/external/lib/piccolo_apache_dist_20040711.jar b/xmlbeans/external/lib/piccolo_apache_dist_20040711.jar deleted file mode 100644 index 4db79cfbd4..0000000000 Binary files a/xmlbeans/external/lib/piccolo_apache_dist_20040711.jar and /dev/null differ diff --git a/xmlbeans/external/lib/piccolo_apache_dist_20040711_v2.jar b/xmlbeans/external/lib/piccolo_apache_dist_20040711_v2.jar deleted file mode 100644 index 5e546189a5..0000000000 Binary files a/xmlbeans/external/lib/piccolo_apache_dist_20040711_v2.jar and /dev/null differ diff --git a/xmlbeans/external/lib/saxonb9-0-0-4j.zip b/xmlbeans/external/lib/saxonb9-0-0-4j.zip new file mode 100644 index 0000000000..c0cea2481a Binary files /dev/null and b/xmlbeans/external/lib/saxonb9-0-0-4j.zip differ diff --git a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Cur.java b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Cur.java index 2a865d31d2..fcb8bfe261 100755 --- a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Cur.java +++ b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Cur.java @@ -3466,28 +3466,36 @@ final class Cur String s = CharUtil.getString( src, off, cch ); - for ( int i = 0 ; i < s.length() ; i++ ) + for ( int i = 0 ; i < s.length(); ) { - if (i== 36) + if (i == 36) { o.print( "..." ); break; } - char ch = s.charAt( i ); - - if (ch >= 32 && ch < 127) - o.print( ch ); - else if (ch == '\n') - o.print( "\\n" ); - else if (ch == '\r') - o.print( "\\r" ); - else if (ch == '\t') - o.print( "\\t" ); - else if (ch == '\"') - o.print( "\\\"" ); - else - o.print( "<#" + ((int) ch) + ">" ); + int codePoint = s.codePointAt( i ); + char[] chars = Character.toChars(codePoint); + + if ( chars.length == 1 ) { + char ch = chars[0]; + if (ch >= 32 && ch < 127) + o.print( ch ); + else if (ch == '\n') + o.print( "\\n" ); + else if (ch == '\r') + o.print( "\\r" ); + else if (ch == '\t') + o.print( "\\t" ); + else if (ch == '\"') + o.print( "\\\"" ); + else + o.print( "<#" + ((int) ch) + ">" ); + } else { + o.print( "<#" + codePoint + ">" ); + } + + i += Character.charCount(codePoint); } o.print( "\"" ); diff --git a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Locale.java b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Locale.java index 531f8763e5..b5a1cc433f 100755 --- a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Locale.java +++ b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Locale.java @@ -1,4 +1,4 @@ -/* Copyright 2004 The Apache Software Foundation +/* Copyright 2004-2017 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,6 @@ import org.xml.sax.InputSource; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.ext.DeclHandler; import org.xml.sax.SAXParseException; -import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.SAXException; import org.xml.sax.DTDHandler; @@ -38,8 +37,6 @@ import java.lang.ref.Reference; import java.lang.ref.PhantomReference; import java.lang.ref.SoftReference; -import java.lang.reflect.Method; - import java.io.InputStream; import java.io.Reader; import java.io.StringReader; @@ -106,9 +103,6 @@ import org.apache.xmlbeans.impl.values.TypeStore; import org.apache.xmlbeans.impl.values.TypeStoreUser; import org.apache.xmlbeans.impl.values.TypeStoreUserFactory; -import org.apache.xmlbeans.impl.piccolo.xml.Piccolo; -import org.apache.xmlbeans.impl.piccolo.io.FileFormatException; - public final class Locale implements DOMImplementation, SaajCallback, XmlLocale { @@ -3035,18 +3029,7 @@ public final class Locale } } - private static SaxLoader getPiccoloSaxLoader() - { - SaxLoader piccoloLoader = (SaxLoader) SystemCache.get().getSaxLoader(); - if (piccoloLoader == null) - { - piccoloLoader = PiccoloSaxLoader.newInstance(); - SystemCache.get().setSaxLoader(piccoloLoader); - } - return piccoloLoader; - } - - private static SaxLoader getSaxLoader(XmlOptions options) + private static SaxLoader getSaxLoader(XmlOptions options) throws XmlException { options = XmlOptions.maskNull(options); @@ -3063,31 +3046,23 @@ public final class Locale er = new DefaultEntityResolver(); } - SaxLoader sl; + XMLReader xr = (XMLReader) options.get( + XmlOptions.LOAD_USE_XMLREADER); - if (options.hasOption(XmlOptions.LOAD_USE_XMLREADER)) - { - XMLReader xr = (XMLReader) options.get( - XmlOptions.LOAD_USE_XMLREADER); - - if (xr == null) - throw new IllegalArgumentException("XMLReader is null"); - - sl = new XmlReaderSaxLoader(xr); - - // I've noticed that most XMLReaders don't like a null EntityResolver... - - if (er != null) - xr.setEntityResolver(er); + if (xr == null) { + try { + xr = SAXHelper.newXMLReader(); + } catch(Exception e) { + throw new XmlException("Problem creating XMLReader", e); + } } - else - { - sl = getPiccoloSaxLoader(); - // Piccolo doesnot mind a null entity resolver ... + SaxLoader sl = new XmlReaderSaxLoader(xr); - sl.setEntityResolver(er); - } + // I've noticed that most XMLReaders don't like a null EntityResolver... + + if (er != null) + xr.setEntityResolver(er); return sl; } @@ -3101,34 +3076,6 @@ public final class Locale } } - private static class PiccoloSaxLoader - extends SaxLoader - { - private PiccoloSaxLoader(Piccolo p) - { - super(p, p.getStartLocator()); - - _piccolo = p; - } - - static PiccoloSaxLoader newInstance() - { - return new PiccoloSaxLoader(new Piccolo()); - } - - void postLoad(Cur c) - { - XmlDocumentProperties props = getDocProps(c, true); - - props.setEncoding(_piccolo.getEncoding()); - props.setVersion(_piccolo.getVersion()); - - super.postLoad(c); - } - - private Piccolo _piccolo; - } - private static abstract class SaxHandler implements ContentHandler, LexicalHandler , DeclHandler, DTDHandler { @@ -3183,7 +3130,7 @@ public final class Locale if (local.length() == 0) local = qName; - // Out current parser (Piccolo) does not error when a + // Out current parser does not error when a // namespace is used and not defined. Check for these here if (qName.indexOf(':') >= 0 && uri.length() == 0) @@ -3473,12 +3420,6 @@ public final class Locale return c; } - catch (FileFormatException e) - { - _context.abort(); - - throw new XmlException(e.getMessage(), e); - } catch (XmlRuntimeException e) { _context.abort(); diff --git a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/NullLogger.java b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/NullLogger.java new file mode 100644 index 0000000000..aca8d1d5ff --- /dev/null +++ b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/NullLogger.java @@ -0,0 +1,81 @@ +/* Copyright 2017 The Apache Software Foundation + * + * 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.apache.xmlbeans.impl.store; + +/** + * A logger class that strives to make it as easy as possible for + * developers to write log calls, while simultaneously making those + * calls as cheap as possible by performing lazy evaluation of the log + * message.

+ */ +public class NullLogger extends XBLogger { + @Override + public void initialize(final String cat) { + // do nothing + } + + /** + * Log a message + * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + * @param obj1 The object to log. + */ + + @Override + protected void _log(final int level, final Object obj1) { + // do nothing + } + + /** + * Log a message + * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + * @param obj1 The object to log. This is converted to a string. + * @param exception An exception to be logged + */ + @Override + protected void _log(int level, Object obj1, final Throwable exception) { + // do nothing + } + + /** + * Log a message. Lazily appends Object parameters together. + * If the last parameter is a {@link Throwable} it is logged specially. + * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + * @param objs the objects to place in the message + */ + @Override + public void log(int level, Object... objs) { + // do nothing + } + + + /** + * Check if a logger is enabled to log at the specified level + * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + */ + @Override + public boolean check(final int level) { + return false; + } +} + + + + + diff --git a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/SAXHelper.java b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/SAXHelper.java new file mode 100644 index 0000000000..67fb3a0e9f --- /dev/null +++ b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/SAXHelper.java @@ -0,0 +1,99 @@ +/* Copyright 2017 The Apache Software Foundation + * + * 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.apache.xmlbeans.impl.store; + +import java.io.IOException; +import java.io.StringReader; +import java.lang.reflect.Method; +import java.util.concurrent.TimeUnit; + +import javax.xml.XMLConstants; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; + +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/** + * Provides handy methods for working with SAX parsers and readers + */ +public final class SAXHelper { + private static final XBLogger logger = XBLogFactory.getLogger(SAXHelper.class); + private static long lastLog; + + private SAXHelper() {} + + /** + * Creates a new SAX XMLReader, with sensible defaults + */ + public static synchronized XMLReader newXMLReader() throws SAXException, ParserConfigurationException { + XMLReader xmlReader = saxFactory.newSAXParser().getXMLReader(); + xmlReader.setEntityResolver(IGNORING_ENTITY_RESOLVER); + trySetSAXFeature(xmlReader, XMLConstants.FEATURE_SECURE_PROCESSING); + trySetXercesSecurityManager(xmlReader); + return xmlReader; + } + + static final EntityResolver IGNORING_ENTITY_RESOLVER = new EntityResolver() { + @Override + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException, IOException { + return new InputSource(new StringReader("")); + } + }; + + private static final SAXParserFactory saxFactory; + static { + saxFactory = SAXParserFactory.newInstance(); + saxFactory.setValidating(false); + saxFactory.setNamespaceAware(true); + } + + private static void trySetSAXFeature(XMLReader xmlReader, String feature) { + try { + xmlReader.setFeature(feature, true); + } catch (Exception e) { + logger.log(XBLogger.WARN, "SAX Feature unsupported", feature, e); + } catch (AbstractMethodError ame) { + logger.log(XBLogger.WARN, "Cannot set SAX feature because outdated XML parser in classpath", feature, ame); + } + } + + private static void trySetXercesSecurityManager(XMLReader xmlReader) { + // Try built-in JVM one first, standalone if not + for (String securityManagerClassName : new String[] { + "com.sun.org.apache.xerces.internal.util.SecurityManager", + "org.apache.xerces.util.SecurityManager" + }) { + try { + Object mgr = Class.forName(securityManagerClassName).newInstance(); + Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE); + setLimit.invoke(mgr, 4096); + xmlReader.setProperty("http://apache.org/xml/properties/security-manager", mgr); + // Stop once one can be setup without error + return; + } catch (Throwable e) { // NOSONAR - also catch things like NoClassDefError here + // throttle the log somewhat as it can spam the log otherwise + if(System.currentTimeMillis() > lastLog + TimeUnit.MINUTES.toMillis(5)) { + logger.log(XBLogger.WARN, "SAX Security Manager could not be setup [log suppressed for 5 minutes]", e); + lastLog = System.currentTimeMillis(); + } + } + } + } +} diff --git a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Saver.java b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Saver.java index 1344aaacfc..c7832aa2fc 100755 --- a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Saver.java +++ b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/Saver.java @@ -275,7 +275,23 @@ abstract class Saver end.moveToCur( c ); end.toEnd(); } - + + /** + * Test if a character is valid in xml character content. See + * http://www.w3.org/TR/REC-xml#NT-Char + */ + static boolean isBadChar ( char ch ) + { + return ! ( + Character.isHighSurrogate(ch) || + Character.isLowSurrogate(ch) || + (ch >= 0x20 && ch <= 0xD7FF ) || + (ch >= 0xE000 && ch <= 0xFFFD) || + (ch >= 0x10000 && ch <= 0x10FFFF) || + (ch == 0x9) || (ch == 0xA) || (ch == 0xD) + ); + } + protected boolean saveNamespacesFirst ( ) { return _saveNamespacesFirst; @@ -1387,7 +1403,7 @@ abstract class Saver if (++i == _buf.length) i = 0; - for ( int cch = _lastEmitCch ; cch > 0 ; cch-- ) + for ( int cch = _lastEmitCch - 2 ; cch > 0 ; cch-- ) { char ch = _buf[ i ]; @@ -1551,21 +1567,6 @@ abstract class Saver } } - /** - * Test if a character is valid in xml character content. See - * http://www.w3.org/TR/REC-xml#NT-Char - */ - - private boolean isBadChar ( char ch ) - { - return ! ( - (ch >= 0x20 && ch <= 0xD7FF ) || - (ch >= 0xE000 && ch <= 0xFFFD) || - (ch >= 0x10000 && ch <= 0x10FFFF) || - (ch == 0x9) || (ch == 0xA) || (ch == 0xD) - ); - } - /** * Test if a character is to be replaced with an escaped value */ @@ -2190,20 +2191,6 @@ abstract class Saver } } - /** - * Test if a character is valid in xml character content. See - * http://www.w3.org/TR/REC-xml#NT-Char - */ - private boolean isBadChar ( char ch ) - { - return ! ( - (ch >= 0x20 && ch <= 0xD7FF ) || - (ch >= 0xE000 && ch <= 0xFFFD) || - (ch >= 0x10000 && ch <= 0x10FFFF) || - (ch == 0x9) || (ch == 0xA) || (ch == 0xD) - ); - } - private void emitLiteral ( String literal ) { // TODO: systemId production http://www.w3.org/TR/REC-xml/#NT-SystemLiteral diff --git a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/XBLogFactory.java b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/XBLogFactory.java new file mode 100644 index 0000000000..f31d4db7bc --- /dev/null +++ b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/XBLogFactory.java @@ -0,0 +1,119 @@ +/* Copyright 2017 The Apache Software Foundation + * + * 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.apache.xmlbeans.impl.store; + +import java.util.HashMap; +import java.util.Map; + +/** + * Provides logging without clients having to mess with + * configuration/initialization. + * + * @author Andrew C. Oliver (acoliver at apache dot org) + * @author Marc Johnson (mjohnson at apache dot org) + * @author Nicola Ken Barozzi (nicolaken at apache.org) + */ +public final class XBLogFactory { + /** + * Map of XBLogger instances, with classes as keys + */ + private static final Map _loggers = new HashMap(); + + /** + * A common instance of NullLogger, as it does nothing + * we only need the one + */ + private static final XBLogger _nullLogger = new NullLogger(); + /** + * The name of the class to use. Initialised the + * first time we need it + */ + static String _loggerClassName = null; + + /** + * Construct a XBLogFactory. + */ + private XBLogFactory() {} + + /** + * Get a logger, based on a class name + * + * @param theclass the class whose name defines the log + * + * @return a XBLogger for the specified class + */ + public static XBLogger getLogger(final Class theclass) { + return getLogger(theclass.getName()); + } + + /** + * Get a logger, based on a String + * + * @param cat the String that defines the log + * + * @return a XBLogger for the specified class + */ + public static XBLogger getLogger(final String cat) { + // If we haven't found out what logger to use yet, + // then do so now + // Don't look it up until we're first asked, so + // that our users can set the system property + // between class loading and first use + if(_loggerClassName == null) { + try { + _loggerClassName = System.getProperty("org.apache.xmlbeans.impl.store.XBLogger"); + } catch(Exception e) { + // ignore any exception here + } + + // Use the default logger if none specified, + // or none could be fetched + if(_loggerClassName == null) { + _loggerClassName = _nullLogger.getClass().getName(); + } + } + + // Short circuit for the null logger, which + // ignores all categories + if(_loggerClassName.equals(_nullLogger.getClass().getName())) { + return _nullLogger; + } + + + // Fetch the right logger for them, creating + // it if that's required + XBLogger logger = _loggers.get(cat); + if (logger == null) { + try { + @SuppressWarnings("unchecked") + Class loggerClass = + (Class) Class.forName(_loggerClassName); + logger = loggerClass.newInstance(); + logger.initialize(cat); + } catch(Exception e) { + // Give up and use the null logger + logger = _nullLogger; + _loggerClassName = _nullLogger.getClass().getName(); + } + + // Save for next time + _loggers.put(cat, logger); + } + return logger; + } +} + + diff --git a/xmlbeans/src/store/org/apache/xmlbeans/impl/store/XBLogger.java b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/XBLogger.java new file mode 100644 index 0000000000..fa605112f0 --- /dev/null +++ b/xmlbeans/src/store/org/apache/xmlbeans/impl/store/XBLogger.java @@ -0,0 +1,115 @@ +/* Copyright 2017 The Apache Software Foundation + * + * 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.apache.xmlbeans.impl.store; + +/** + * A logger interface that strives to make it as easy as possible for + * developers to write log calls, while simultaneously making those + * calls as cheap as possible by performing lazy evaluation of the log + * message.

+ */ +public abstract class XBLogger { + + public static final int DEBUG = 1; + public static final int INFO = 3; + public static final int WARN = 5; + public static final int ERROR = 7; + public static final int FATAL = 9; + + /** Short strings for numeric log level. Use level as array index. */ + protected static final String LEVEL_STRINGS_SHORT[] = {"?", "D", "?", "I", "?", "W", "?", "E", "?", "F", "?"}; + /** Long strings for numeric log level. Use level as array index. */ + protected static final String LEVEL_STRINGS[] = {"?0?", "DEBUG", "?2?", "INFO", "?4?", "WARN", "?6?", "ERROR", "?8?", "FATAL", "?10+?"}; + + + /** + * package scope so it cannot be instantiated outside of the util + * package. You need a XBLogger? Go to the XBLogFactory for one + */ + XBLogger() { + // no fields to initialize + } + + abstract public void initialize(String cat); + + /** + * Log a message + * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + * @param obj1 The object to log. This is converted to a string. + */ + abstract protected void _log(int level, Object obj1); + + /** + * Log a message + * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + * @param obj1 The object to log. This is converted to a string. + * @param exception An exception to be logged + */ + abstract protected void _log(int level, Object obj1, final Throwable exception); + + + /** + * Check if a logger is enabled to log at the specified level + * This allows code to avoid building strings or evaluating functions in + * the arguments to log. + * + * An example: + *

+     * if (logger.check(XBLogger.INFO)) {
+     *     logger.log(XBLogger.INFO, "Avoid concatenating " + " strings and evaluating " + functions());
+     * }
+     * 
+ * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + */ + abstract public boolean check(int level); + + /** + * Log a message. Lazily appends Object parameters together. + * If the last parameter is a {@link Throwable} it is logged specially. + * + * @param level One of DEBUG, INFO, WARN, ERROR, FATAL + * @param objs the objects to place in the message + */ + public void log(int level, Object... objs) { + if (!check(level)) return; + StringBuilder sb = new StringBuilder(32); + Throwable lastEx = null; + for (int i=0; iQName class represents the value of a qualified name - * as specified in XML - * Schema Part2: Datatypes specification. - *

- * The value of a QName contains a namespaceURI, a localPart and a prefix. - * The localPart provides the local part of the qualified name. The - * namespaceURI is a URI reference identifying the namespace. - * - * @version 1.1 - */ -public class QName implements Serializable { - - private static final long serialVersionUID = -9120448754896609940L; - - /** comment/shared empty string */ - private static final String emptyString = "".intern(); - - /** Field namespaceURI */ - private String namespaceURI; - - /** Field localPart */ - private String localPart; - - /** Field prefix */ - private String prefix; - - /** - * Constructor for the QName. - * - * @param localPart Local part of the QName - */ - public QName(String localPart) { - this(emptyString, localPart, emptyString); - } - - /** - * Constructor for the QName. - * - * @param namespaceURI Namespace URI for the QName - * @param localPart Local part of the QName. - */ - public QName(String namespaceURI, String localPart) { - this(namespaceURI, localPart, emptyString); - } - - /** - * Constructor for the QName. - * - * @param namespaceURI Namespace URI for the QName - * @param localPart Local part of the QName. - * @param prefix Prefix of the QName. - */ - public QName(String namespaceURI, String localPart, String prefix) { - this.namespaceURI = (namespaceURI == null) - ? emptyString - : namespaceURI.intern(); - if (localPart == null) { - throw new IllegalArgumentException("invalid QName local part"); - } else { - this.localPart = localPart.intern(); - } - - if (prefix == null) { - throw new IllegalArgumentException("invalid QName prefix"); - } else { - this.prefix = prefix.intern(); - } - } - - /** - * Gets the Namespace URI for this QName - * - * @return Namespace URI - */ - public String getNamespaceURI() { - return namespaceURI; - } - - /** - * Gets the Local part for this QName - * - * @return Local part - */ - public String getLocalPart() { - return localPart; - } - - /** - * Gets the Prefix for this QName - * - * @return Prefix - */ - public String getPrefix() { - return prefix; - } - - /** - * Returns a string representation of this QName - * - * @return a string representation of the QName - */ - public String toString() { - - return ((namespaceURI == emptyString) - ? localPart - : '{' + namespaceURI + '}' + localPart); - } - - /** - * Tests this QName for equality with another object. - *

- * If the given object is not a QName or is null then this method - * returns false. - *

- * For two QNames to be considered equal requires that both - * localPart and namespaceURI must be equal. This method uses - * String.equals to check equality of localPart - * and namespaceURI. Any class that extends QName is required - * to satisfy this equality contract. - *

- * This method satisfies the general contract of the Object.equals method. - * - * @param obj the reference object with which to compare - * - * @return true if the given object is identical to this - * QName: false otherwise. - */ - public final boolean equals(Object obj) { - - if (obj == this) { - return true; - } - - if (!(obj instanceof QName)) { - return false; - } - - if ((namespaceURI == ((QName) obj).namespaceURI) - && (localPart == ((QName) obj).localPart)) { - return true; - } - - return false; - } - - /** - * Returns a QName holding the value of the specified String. - *

- * The string must be in the form returned by the QName.toString() - * method, i.e. "{namespaceURI}localPart", with the "{namespaceURI}" - * part being optional. - *

- * This method doesn't do a full validation of the resulting QName. - * In particular, it doesn't check that the resulting namespace URI - * is a legal URI (per RFC 2396 and RFC 2732), nor that the resulting - * local part is a legal NCName per the XML Namespaces specification. - * - * @param s the string to be parsed - * @throws java.lang.IllegalArgumentException If the specified String cannot be parsed as a QName - * @return QName corresponding to the given String - */ - public static QName valueOf(String s) { - - if ((s == null) || s.equals("")) { - throw new IllegalArgumentException("invalid QName literal"); - } - - if (s.charAt(0) == '{') { - int i = s.indexOf('}'); - - if (i == -1) { - throw new IllegalArgumentException("invalid QName literal"); - } - - if (i == s.length() - 1) { - throw new IllegalArgumentException("invalid QName literal"); - } else { - return new QName(s.substring(1, i), s.substring(i + 1)); - } - } else { - return new QName(s); - } - } - - /** - * Returns a hash code value for this QName object. The hash code - * is based on both the localPart and namespaceURI parts of the - * QName. This method satisfies the general contract of the - * Object.hashCode method. - * - * @return a hash code value for this Qname object - */ - public final int hashCode() { - return namespaceURI.hashCode() ^ localPart.hashCode(); - } - - /** - * Ensure that deserialization properly interns the results. - * @param in the ObjectInputStream to be read - */ - private void readObject(ObjectInputStream in) throws - IOException, ClassNotFoundException { - in.defaultReadObject(); - - namespaceURI = namespaceURI.intern(); - localPart = localPart.intern(); - prefix = prefix.intern(); - } -} diff --git a/xmlbeans/test/src/xmlcursor/checkin/StoreTests.java b/xmlbeans/test/src/xmlcursor/checkin/StoreTests.java index ac0ec29465..80ab820ba3 100755 --- a/xmlbeans/test/src/xmlcursor/checkin/StoreTests.java +++ b/xmlbeans/test/src/xmlcursor/checkin/StoreTests.java @@ -1112,7 +1112,7 @@ public class StoreTests extends TestCase throws Exception { XmlCursor c = XmlObject.Factory.parse( xml ).newCursor(); - Assert.assertTrue( c.xmlText().equals( xml ) ); + Assert.assertEquals( xml, c.xmlText() ); } private void doSaveTest ( String xml ) @@ -1121,6 +1121,16 @@ public class StoreTests extends TestCase doSaverTest( xml ); } + public void testCDATA() throws Exception + { + // https://issues.apache.org/jira/browse/XMLBEANS-404 + String xml = "Unable to render embedded object: >>>>>>><<<<<<<<<<<]]>"; + String expected = ">>>>>>><<<<<<<<<<<]]>"; + XmlOptions options = new XmlOptions().setSaveCDataLengthThreshold(0); + XmlCursor c = XmlObject.Factory.parse(xml, options).newCursor(); + Assert.assertEquals( expected, c.xmlText(options) ); + } + public void testSaving ( ) throws Exception { diff --git a/xmlbeans/test/src/xmlobject/checkin/AssortedTests.java b/xmlbeans/test/src/xmlobject/checkin/AssortedTests.java index a6364a81f8..ce4b235219 100755 --- a/xmlbeans/test/src/xmlobject/checkin/AssortedTests.java +++ b/xmlbeans/test/src/xmlobject/checkin/AssortedTests.java @@ -40,7 +40,6 @@ public class AssortedTests extends TestCase // bug 27489 public static void testSaverCharEscaping() throws XmlException { - String newLine = System.getProperty( "line.separator" ); XmlObject xdoc = XmlObject.Factory.parse("something"); XmlCursor cur = xdoc.newCursor(); cur.toFirstChild(); @@ -48,9 +47,14 @@ public class AssortedTests extends TestCase cur.setTextValue(""); Assert.assertEquals("<something or other:\u03C0\uD7FF>", xdoc.toString()); - // invalid chars - control chars, unicode surrogates, FFFF/FFFE, etc - cur.setTextValue(""); - Assert.assertEquals("<something?or?other:\u0045?????\u03C0\uD7FF?>", xdoc.toString()); + // invalid chars - control chars, FFFF/FFFE, etc + cur.setTextValue(""); + Assert.assertEquals("<something?or?other:\u0045?>", xdoc.toString()); + + String greekChars = "\uD835\uDF4A\uD835\uDF4B\uD835\uDF4C\uD835\uDF4D\uD835\uDF4E\uD835\uDF4F\uD835\uDF50\uD835" + + "\uDF51\uD835\uDF52\uD835\uDF53\uD835\uDF54\uD835\uDF55"; + cur.setTextValue(greekChars); + Assert.assertEquals("" + greekChars + "", xdoc.toString()); } // bug 26140/26104 diff --git a/xmlbeans/test/src/xmlobject/checkin/CDataTest.java b/xmlbeans/test/src/xmlobject/checkin/CDataTest.java index 1b64a5283e..791e212111 100644 --- a/xmlbeans/test/src/xmlobject/checkin/CDataTest.java +++ b/xmlbeans/test/src/xmlobject/checkin/CDataTest.java @@ -53,8 +53,8 @@ public class CDataTest throws Exception { String xmlText = ""; - - checkCData(xmlText, xmlText, xmlText); + String resultText = "cdata text"; + checkCData(xmlText, resultText, resultText); } public void testCData2() @@ -64,10 +64,10 @@ public class CDataTest " regular text" + NL + ""; String expected1 = "\n" + - "\n" + + "cdata text regular text\n" + ""; String expected2 = "" + NL + - " " + NL + + " cdata text regular text" + NL + ""; checkCData(xmlText, expected1, expected2); @@ -89,6 +89,23 @@ public class CDataTest checkCData(xmlText, expected1, expected2); } + // https://issues.apache.org/jira/browse/XMLBEANS-404 + public void testXmlBeans404() + throws Exception + { + String xmlText = "\n" + + "text \n" + + ""; + String expected1 = "\n" + + "text cdata text]]\n" + + ""; + String expected2 = "" + NL + + " text cdata text]]" + NL + + ""; + + checkCData(xmlText, expected1, expected2); + } + private void checkCData(String xmlText, String expected1, String expected2) throws XmlException {