diff --git a/jre_emul/Classes/com/google/j2objc/util/PropertiesXmlLoader.java b/jre_emul/Classes/com/google/j2objc/util/PropertiesXmlLoader.java deleted file mode 100644 index 1839cc0cf5..0000000000 --- a/jre_emul/Classes/com/google/j2objc/util/PropertiesXmlLoader.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 com.google.j2objc.util; - -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; -import org.xml.sax.helpers.XMLReaderFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.util.InvalidPropertiesFormatException; -import java.util.Properties; - -/** - * Dynamically loaded implementation for Properties.loadFromXML(). Public so that users can add an - * explicit dependency to force load this class. - */ -public class PropertiesXmlLoader implements XmlLoader { - - public void load(final Properties p, InputStream in) throws IOException, - InvalidPropertiesFormatException { - if (in == null) { - throw new NullPointerException("in == null"); - } - - try { - XMLReader reader = XMLReaderFactory.createXMLReader(); - reader.setContentHandler(new DefaultHandler() { - private String key; - - @Override - public void startElement(String uri, String localName, - String qName, Attributes attributes) throws SAXException { - key = null; - if (qName.equals("entry")) { - key = attributes.getValue("key"); - } - } - - @Override - public void characters(char[] ch, int start, int length) - throws SAXException { - if (key != null) { - String value = new String(ch, start, length); - p.put(key, value); - key = null; - } - } - }); - reader.parse(new InputSource(in)); - } catch (SAXException e) { - throw new InvalidPropertiesFormatException(e); - } - } -} diff --git a/jre_emul/android/platform/libcore/luni/src/main/java/java/nio/NioUtils.java b/jre_emul/android/platform/libcore/luni/src/main/java/java/nio/NioUtils.java index 9ab5b0bf4e..7dbb8ccfd0 100644 --- a/jre_emul/android/platform/libcore/luni/src/main/java/java/nio/NioUtils.java +++ b/jre_emul/android/platform/libcore/luni/src/main/java/java/nio/NioUtils.java @@ -16,24 +16,15 @@ package java.nio; -import dalvik.annotation.compat.UnsupportedAppUsage; +import static libcore.io.OsConstants.O_ACCMODE; +import static libcore.io.OsConstants.O_RDONLY; +import static libcore.io.OsConstants.O_WRONLY; -import com.google.j2objc.LibraryNotLinkedError; -import java.io.Closeable; +import dalvik.annotation.compat.UnsupportedAppUsage; import java.io.FileDescriptor; -import java.io.IOException; import java.nio.channels.FileChannel; -import java.util.Set; - -import sun.misc.Cleaner; -import sun.nio.ch.DirectBuffer; import sun.nio.ch.FileChannelImpl; -import static libcore.io.OsConstants.O_ACCMODE; -import static libcore.io.OsConstants.O_APPEND; -import static libcore.io.OsConstants.O_RDONLY; -import static libcore.io.OsConstants.O_WRONLY; - /** * @hide internal use only */ @@ -64,43 +55,12 @@ public static FileDescriptor getFD(FileChannel fc) { } */ - /** - * Helps bridge between io and nio. - */ - public static FileChannel newFileChannel(Closeable ioObject, FileDescriptor fd, int mode) { - ChannelFactory factory = ChannelFactory.INSTANCE; - if (factory == null) { - throw new LibraryNotLinkedError("Channel support", "jre_channels", - "JavaNioChannelFactoryImpl"); - } - return factory.newFileChannel(ioObject, fd, mode); - } - - public static FileChannel newFileChannelSafe(Object stream, FileDescriptor fd, int mode) { - ChannelFactory factory = ChannelFactory.INSTANCE; - if (factory != null) { - return factory.newFileChannel(stream, fd, mode); - } else { - return null; - } + public FileChannel newFileChannel(Object ioObject, FileDescriptor fd, int mode) { + boolean readable = (mode & O_ACCMODE) != O_WRONLY; + boolean writable = (mode & O_ACCMODE) != O_RDONLY; + return FileChannelImpl.open(fd, null, readable, writable, ioObject); } - static interface ChannelFactory { - FileChannel newFileChannel(Object stream, FileDescriptor fd, int mode); - - static final ChannelFactory INSTANCE = getChannelFactory(); - } - - // Native implementation avoids the use of Class.forName(). This code might end up invoked from - // within the internals of Class.forName(), and re-invoking it causes deadlock. - private static native ChannelFactory getChannelFactory() /*-[ - Class cls = NSClassFromString(@"JavaNioChannelFactoryImpl"); - if (cls) { - return AUTORELEASE([[cls alloc] init]); - } - return nil; - ]-*/; - /** * Exposes the array backing a non-direct ByteBuffer, even if the ByteBuffer is read-only. * Normally, attempting to access the array backing a read-only buffer throws. diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/nio/ChannelFactoryImpl.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/nio/ChannelFactoryImpl.java deleted file mode 100644 index 31165ebd0a..0000000000 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/nio/ChannelFactoryImpl.java +++ /dev/null @@ -1,42 +0,0 @@ -/* Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 java.nio; - -import com.google.j2objc.annotations.ReflectionSupport; -import java.io.FileDescriptor; -import java.nio.channels.FileChannel; -import sun.nio.ch.FileChannelImpl; - -import static com.google.j2objc.annotations.ReflectionSupport.Level.FULL; -import static libcore.io.OsConstants.*; - -/** - * J2ObjC split of NioUtils to move method to jre_channels subset library. - * This class is only referenced by reflection. - */ -@SuppressWarnings("unused") -@ReflectionSupport(FULL) -class ChannelFactoryImpl implements NioUtils.ChannelFactory { - - public FileChannel newFileChannel(Object ioObject, FileDescriptor fd, int mode) { - boolean readable = (mode & O_ACCMODE) != O_WRONLY; - boolean writable = (mode & O_ACCMODE) != O_RDONLY; - boolean append = (mode & O_APPEND) != 0; - - return new FileChannelImpl(fd, null, readable, writable, append, ioObject); - } -} diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java index 2f875ba7c7..18081284a2 100644 --- a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/Properties.java @@ -26,12 +26,8 @@ package java.util; -import com.google.j2objc.LibraryNotLinkedError; -import com.google.j2objc.util.XmlLoader; import java.io.BufferedWriter; import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -39,9 +35,6 @@ import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; -import java.nio.charset.Charset; -import java.nio.charset.IllegalCharsetNameException; -import java.nio.charset.UnsupportedCharsetException; // Android-removed: Dead native2ascii links. // These links are also gone in OpenJDK 9. @@ -910,21 +903,16 @@ private void store0(BufferedWriter bw, String comments, boolean escUnicode) */ public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException { - XmlLoader loader = getXmlLoader(); - if (loader == null) { - throw new LibraryNotLinkedError( - "XML support", "jre_xml", "ComGoogleJ2objcUtilPropertiesXmlLoader"); - } - loader.load(this, in); - } - - private static XmlLoader getXmlLoader() { - try { - Class loaderClass = Class.forName("com.google.j2objc.util.PropertiesXmlLoader"); - return (XmlLoader) loaderClass.newInstance(); - } catch (Exception e) { - return null; - } + // Android-changed: Keep OpenJDK7u40's XmlUtils. + // XmlSupport's system property based XmlPropertiesProvider + // selection does not make sense on Android and has too many + // dependencies on classes that are not available on Android. + // + // Objects.requireNonNull(in); + // PropertiesDefaultHandler handler = new PropertiesDefaultHandler(); + // handler.load(this, in); + XMLUtils.load(this, Objects.requireNonNull(in)); + in.close(); } /** @@ -994,72 +982,23 @@ public void storeToXML(OutputStream os, String comment) */ public void storeToXML(OutputStream os, String comment, String encoding) throws IOException { - if (os == null) { - throw new NullPointerException("os == null"); - } else if (encoding == null) { - throw new NullPointerException("encoding == null"); - } - + // Android-changed: Keep OpenJDK7u40's XmlUtils. + // XmlSupport's system property based XmlPropertiesProvider + // selection does not make sense on Android and has too many + // dependencies on classes that are not available on Android. /* - * We can write to XML file using encoding parameter but note that some - * aliases for encodings are not supported by the XML parser. Thus we - * have to know canonical name for encoding used to store data in XML - * since the XML parser must recognize encoding name used to store data. - */ + Objects.requireNonNull(os); + Objects.requireNonNull(encoding); - String encodingCanonicalName; try { - encodingCanonicalName = Charset.forName(encoding).name(); - } catch (IllegalCharsetNameException e) { - System.out.println("Warning: encoding name " + encoding - + " is illegal, using UTF-8 as default encoding"); - encodingCanonicalName = "UTF-8"; - } catch (UnsupportedCharsetException e) { - System.out.println("Warning: encoding " + encoding - + " is not supported, using UTF-8 as default encoding"); - encodingCanonicalName = "UTF-8"; - } - - PrintStream printStream = new PrintStream(os, false, - encodingCanonicalName); - - printStream.print(""); - - printStream.print(""); - - printStream.println(""); - - if (comment != null) { - printStream.print(""); - printStream.print(substitutePredefinedEntries(comment)); - printStream.println(""); + Charset charset = Charset.forName(encoding); + storeToXML(os, comment, charset); + } catch (IllegalCharsetNameException | UnsupportedCharsetException e) { + throw new UnsupportedEncodingException(encoding); } - - for (Map.Entry entry : entrySet()) { - String keyValue = (String) entry.getKey(); - String entryValue = (String) entry.getValue(); - printStream.print(""); - printStream.print(substitutePredefinedEntries(entryValue)); - printStream.println(""); - } - printStream.println(""); - printStream.flush(); - } - - private String substitutePredefinedEntries(String s) { - // substitution for predefined character entities to use them safely in XML. - s = s.replaceAll("&", "&"); - s = s.replaceAll("<", "<"); - s = s.replaceAll(">", ">"); - s = s.replaceAll("'", "'"); - s = s.replaceAll("\"", """); - return s; + */ + XMLUtils.save(this, Objects.requireNonNull(os), comment, + Objects.requireNonNull(encoding)); } /** diff --git a/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/XMLUtils.java b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/XMLUtils.java new file mode 100644 index 0000000000..8f061e5b7f --- /dev/null +++ b/jre_emul/android/platform/libcore/ojluni/src/main/java/java/util/XMLUtils.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.io.*; +import org.xml.sax.*; +import org.xml.sax.helpers.*; +import org.w3c.dom.*; +import javax.xml.parsers.*; +import javax.xml.transform.*; +import javax.xml.transform.dom.*; +import javax.xml.transform.stream.*; + +/** + * A class used to aid in Properties load and save in XML. Keeping this + * code outside of Properties helps reduce the number of classes loaded + * when Properties is loaded. + * + * @author Michael McCloskey + * @since 1.3 + */ +class XMLUtils { + + // XML loading and saving methods for Properties + + // The required DTD URI for exported properties + private static final String PROPS_DTD_URI = + "http://java.sun.com/dtd/properties.dtd"; + + private static final String PROPS_DTD = + "" + + "" + + ""+ + "" + + "" + + "" + + ""; + + /** + * Version number for the format of exported properties files. + */ + private static final String EXTERNAL_XML_VERSION = "1.0"; + + static void load(Properties props, InputStream in) + throws IOException, InvalidPropertiesFormatException + { + Document doc = null; + try { + doc = getLoadingDoc(in); + } catch (SAXException saxe) { + throw new InvalidPropertiesFormatException(saxe); + } + Element propertiesElement = doc.getDocumentElement(); + String xmlVersion = propertiesElement.getAttribute("version"); + if (xmlVersion.compareTo(EXTERNAL_XML_VERSION) > 0) + throw new InvalidPropertiesFormatException( + "Exported Properties file format version " + xmlVersion + + " is not supported. This java installation can read" + + " versions " + EXTERNAL_XML_VERSION + " or older. You" + + " may need to install a newer version of JDK."); + importProperties(props, propertiesElement); + } + + static Document getLoadingDoc(InputStream in) + throws SAXException, IOException + { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + dbf.setIgnoringElementContentWhitespace(true); + // Android-changed: We don't currently have a validating document builder. + // Revert this if the situation changes. + // + // dbf.setValidating(true); + dbf.setCoalescing(true); + dbf.setIgnoringComments(true); + try { + DocumentBuilder db = dbf.newDocumentBuilder(); + db.setEntityResolver(new Resolver()); + db.setErrorHandler(new EH()); + InputSource is = new InputSource(in); + return db.parse(is); + } catch (ParserConfigurationException x) { + throw new Error(x); + } + } + + static void importProperties(Properties props, Element propertiesElement) { + NodeList entries = propertiesElement.getChildNodes(); + int numEntries = entries.getLength(); + int start = numEntries > 0 && + entries.item(0).getNodeName().equals("comment") ? 1 : 0; + for (int i=start; i