diff options
Diffstat (limited to 'xmerge/source/xmerge/java/org/openoffice/xmerge/util')
17 files changed, 2834 insertions, 0 deletions
diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java new file mode 100644 index 000000000..829963283 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ActiveSyncDriver.java @@ -0,0 +1,143 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileInputStream; +import java.io.IOException; + +import java.util.StringTokenizer; +import java.util.NoSuchElementException; + +import org.openoffice.xmerge.Convert; +import org.openoffice.xmerge.Document; +import org.openoffice.xmerge.ConvertData; +import org.openoffice.xmerge.ConvertException; +import org.openoffice.xmerge.ConverterFactory; +import org.openoffice.xmerge.util.registry.ConverterInfoMgr; +import org.openoffice.xmerge.util.registry.ConverterInfoReader; + +public class ActiveSyncDriver { + public static void main(String[] args) { + if (args.length != 4) { + return; + } + + ActiveSyncDriver asd = new ActiveSyncDriver(); + + try { + // At the moment can't really signal back to the calling DLL + asd.Convert(args[0], args[1], args[2], args[3]); + } + catch (Exception e) { + return; + } + } + + private boolean Convert(String srcMime, String dstMime, String srcFile, + String dstFile) throws Exception { + /* + * The classpath passed in by XMergeSync.dll should contain all of the + * jar files, but at the least it will contain xmerge.jar, so strip off + * the xmerge.jar portion and use the remainder to provide a root for + * the Pocket Word and Pocket Excel plugins. + */ + String ooClassDir = null; + String strClassPath = System.getProperty("java.class.path"); + + StringTokenizer st = new StringTokenizer(strClassPath, ";"); + + // There should be at least one element, but just in case + while (st.hasMoreTokens()) { + String s = st.nextToken(); + + if (s.endsWith("xmerge.jar")) { + ooClassDir = s.substring(0, s.indexOf("xmerge.jar")); + } + } + + if (ooClassDir == null) { + return true; + } + + /* + * The XMergeSync.dll should will have checked for the presence of the + * jars at the same location already. + * + * Because they can be installed separately, though, the MIME types need + * to be check to see which one to load. + */ + File pluginJar; + if (srcMime.equals("staroffice/sxw") || srcMime.equals("application/x-pocket-word")) { + pluginJar = new File(ooClassDir + "pocketWord.jar"); + } else { + if (srcMime.equals("staroffice/sxc") || srcMime.equals("application/x-pocket-excel")) { + pluginJar = new File(ooClassDir + "pexcel.jar"); + } else { + return false; + } + } + + ConverterInfoReader cirPlugin = new ConverterInfoReader(pluginJar.toURI().toURL().toString(), false); + + ConverterInfoMgr.addPlugIn(cirPlugin.getConverterInfoEnumeration()); + + ConverterFactory cf = new ConverterFactory(); + Convert conv = cf.getConverter(srcMime, dstMime); + + if (conv == null) { + return false; + } + + // Everything is registered so do the conversion + boolean bOK = true; + FileInputStream fis = null; + FileOutputStream fos = null; + try { + fis = new FileInputStream(srcFile); + conv.addInputStream(srcFile, fis); + try { + fos = new FileOutputStream(dstFile); + ConvertData dataOut = conv.convert(); + + // Get the document and write it out. + Document doc = (Document)dataOut.getDocumentEnumeration().next(); + doc.write(fos); + fos.flush(); + } finally { + if (fos != null) + fos.close(); + } + } catch (IOException e) { + bOK = false; + } catch (NullPointerException e) { + bOK = false; + } catch (ConvertException e) { + bOK = false; + } catch (NoSuchElementException e) { + bOK = false; + } finally { + if (fis != null) + fis.close(); + } + + return bOK; + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java new file mode 100644 index 000000000..aefb3f966 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/ColourConverter.java @@ -0,0 +1,421 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import java.awt.Color; + +/** + * Utility class mapping RGB colour specifications to the colour indices used + * in the Pocket PC. + * + * <p>The original converter was written for use with Pocket Word it was later + * put into the utils so Pocket excel could use this code also. For this reason + * the default values are those used by Pocket Word but a colour table can be + * passed in through the constructor to map the 16 values to a colour table.</p> + * + * <p>These colour indices are based on the Windows VGA 16 colour palette, which + * later was used as the basis for the named colours in the HTML 3.2 + * specification.</p> + * + * <p>In Pocket Word's case, the match to the VGA 16 palette is not exact as it + * swaps Grey and Silver, with Silver being the darker colour (i.e. having the + * lower RGB value).</p> + */ + +public class ColourConverter { + + /** Colour table index for Black */ + private static final short BLACK = 0; + + /** Colour table index for Silver */ + private static final short SILVER = 1; + + /** Colour table index for Grey */ + private static final short GREY = 2; + + /** Colour table index for White */ + private static final short WHITE = 3; + + /** Colour table index for Red */ + private static final short RED = 4; + + /** Colour table index for Lime */ + private static final short LIME = 5; + + /** Colour table index for Blue */ + private static final short BLUE = 6; + + /** Colour table index for Aqua */ + private static final short AQUA = 7; + + /** Colour table index for Fuchsia */ + private static final short FUCHSIA = 8; + + /** Colour table index for Yellow */ + private static final short YELLOW = 9; + + /** Colour table index for Maroon */ + private static final short MAROON = 10; + + /** Colour table index for Green */ + private static final short GREEN = 11; + + /** Colour table index for Navy */ + private static final short NAVY = 12; + + /** Colour table index for Teal */ + private static final short TEAL = 13; + + /** Colour table index for Purple */ + private static final short PURPLE = 14; + + /** Colour table index for Olive */ + public static final short OLIVE = 15; + + private short tableLookup[] = null; + + /** + * Default constructor used in the case where a lookup table is not required. + */ + public ColourConverter() { + + } + + /** + * Constructor that passes in the colour lookup table. + * + * <p>This is required in cases where the 16 colour values are something + * other than there default values (e.g. in the case of pocket Excel).</p> + * + * @param lookup a 16 bit array mapping the 16 colours to their values. + */ + public ColourConverter(short lookup[]) { + tableLookup = lookup; + } + + /** + * Uses the colour table if it exists to translate default values to values + * in the colorTable. + */ + private short colourLookup(short colour) { + if(tableLookup!=null) { + return tableLookup[colour]; + } else { + return colour; + } + } + + /** + * Uses the colour table if it exists to translate default values to values + * in the colorTable. + */ + private short indexLookup(short index) { + + short result = 0; + + if(tableLookup!=null) { + for(short i = 0;i < tableLookup.length;i++) { + if(tableLookup[i]==index) + result = i; + } + } else { + result = index; + } + + return result; + } + /** + * This method maps a Pocket Word colour index value to an RGB value as used + * by OpenOffice. + * + * @param colour The index into Pocket Word's colour table. + * + * @return A {@code Color} object representing the RGB value of the Pocket + * Word colour. + */ + public Color convertToRGB (short colour) { + + short index = indexLookup(colour); + + int r = 0; + int g = 0; + int b = 0; + + switch (index) { + case SILVER: + r = g = b = 128; + break; + + case GREY: + r = g = b = 192; + break; + + case WHITE: + r = g = b = 255; + break; + + case RED: + r = 255; + break; + + case LIME: + g = 255; + break; + + case BLUE: + b = 255; + break; + + case AQUA: + g = b = 255; + break; + + case FUCHSIA: + r = b = 255; + break; + + case YELLOW: + r = g = 255; + break; + + case MAROON: + r = 128; + break; + + case GREEN: + g = 128; + break; + + case NAVY: + b = 128; + break; + + case TEAL: + b = g = 128; + break; + + case PURPLE: + r = b = 128; + break; + + case OLIVE: + r = g = 128; + break; + + case BLACK: + default: + r = g = b = 0; + break; + } + + return new Color(r, g, b); + } + + /** + * This method approximates an RGB value (as used by Writer) to one of the + * 16 available colours. + * + * <p>Most of the supported colours have their components set to either 0, + * 128 or 255. The exception is 'Grey' which is {@literal 0xC0C0C0}.</p> + * + * @param colour {@code Color} object representing the RGB value of the + * colour. + * + * @return Index into the Pocket Word colour table which represents the + * closest match to the specified colour. + */ + public short convertFromRGB (Color colour) { + int matchedRGB = 0; + short indexColour = 0; + int reducedMap[] = new int[] { 0, 0, 128 }; + + int red = colour.getRed(); + int green = colour.getGreen(); + int blue = colour.getBlue(); + + // We need to convert the pale colours to their base color rather than + // white so we modify the rgb values if the colour is sufficiently white. + if(red>0xC0 && green>0xC0 && blue>0xC0) { + + if(red!=0xFF) + red = getClosest(red, reducedMap); + if(green!=0xFF) + green = getClosest(green, reducedMap); + if(blue!=0xFF) + blue = getClosest(blue, reducedMap); + } + + // Need to derive an RGB value that has been rounded to match the ones + // Pocket Word knows about. + matchedRGB += getClosest(red) << 16; + matchedRGB += getClosest(green) << 8; + matchedRGB += getClosest(blue); + + // The colour map used by Pocket Word doesn't have any combinations of + // values beyond 0 and any other value. A value of 255 in any RGB code + // indicates a dominant colour. Other colours are only modifiers to the + // principal colour(s). Thus, for this conversion, modifiers can be + // dropped. + if ((matchedRGB & 0xFF0000) == 0xFF0000 || (matchedRGB & 0xFF00) == 0xFF00 + || (matchedRGB & 0xFF) == 0xFF) { + if ((matchedRGB & 0xFF0000) == 0x800000) { + matchedRGB ^= 0x800000; + } + if ((matchedRGB & 0xFF00) == 0x8000) { + matchedRGB ^= 0x8000; + } + if ((matchedRGB & 0xFF) == 0x80) { + matchedRGB ^= 0x80; + } + } + + /* + * And now for the actual matching ... + * + * Colours are based on the Windows VGA 16 palette. One difference + * though is that Pocket Word seems to switch the RGB codes for Grey + * and Silver. In Pocket Word Silver is the darker colour leaving Grey + * is closest to White. + * + * Shades of grey will be converted to either Silver or White, where + * Grey may be a more appropriate colour. This is handled specially + * only for Silver and White matches. + */ + switch (matchedRGB) { + case 0x000000: + indexColour = BLACK; + break; + + case 0x808080: + if (!isGrey(colour)) { + indexColour = SILVER; + } + else { + indexColour = GREY; + } + break; + + case 0xFFFFFF: + if (!isGrey(colour)) { + indexColour = WHITE; + } + else { + indexColour = GREY; + } + break; + + case 0xFF0000: + indexColour = RED; + break; + + case 0x00FF00: + indexColour = LIME; + break; + + case 0x0000FF: + indexColour = BLUE; + break; + + case 0x00FFFF: + indexColour = AQUA; + break; + + case 0xFF00FF: + indexColour = FUCHSIA; + break; + + case 0xFFFF00: + indexColour = YELLOW; + break; + + case 0x800000: + indexColour = MAROON; + break; + + case 0x008000: + indexColour = GREEN; + break; + + case 0x000080: + indexColour = NAVY; + break; + + case 0x008080: + indexColour = TEAL; + break; + + case 0x800080: + indexColour = PURPLE; + break; + + case 0x808000: + indexColour = OLIVE; + break; + + default: // Just in case! + indexColour = BLACK; + break; + } + + return colourLookup(indexColour); + } + + /** + * Default implementation, checks for the closest of value to 0, 128 or 255. + */ + private int getClosest(int value) { + int points[] = new int[] { 0, 128, 255 }; + + return getClosest(value, points); + } + + /** + * Utility method that returns the closest of the three points to the value + * supplied. + */ + private int getClosest(int value, int[] points) { + + if (value == points[0] || value == points[1] || value == points[2]) { + return value; + } + + if (value < points[1]) { + int x = value - points[0]; + return (Math.round((float)x / (points[1] - points[0])) == 1 ? points[1] : points[0]); + } + else { + int x = value - points[1]; + return (Math.round((float)x / (points[2] - points[1])) >= 1 ? points[2] : points[1]); + } + } + + /** + * Checks to see if the supplied colour can be considered to be grey. + */ + private boolean isGrey(Color c) { + int matchedRGB = 0; + int points[] = new int[] { 128, 192, 255 }; + + matchedRGB += getClosest(c.getRed(), points) << 16; + matchedRGB += getClosest(c.getGreen(), points) << 8; + matchedRGB += getClosest(c.getBlue(), points); + + return matchedRGB == 0xC0C0C0; + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java new file mode 100644 index 000000000..ed95031f8 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.java @@ -0,0 +1,230 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Writer; +import java.util.Properties; + +/** + * This class is used for logging debug messages. + * + * <p>Currently, there are three types of logging: {@link #INFO}, {@link #TRACE} + * {@literal &} {@link #ERROR}. Use the {@code Debug.properties} file to set or + * unset each type. Also use {@code Debug.properties} to set the writer to + * either {@code System.out}, {@code System.err}, or to a file.</p> + */ +public final class Debug { + + /** Informational messages. */ + public static final int INFO = 0x0001; + /** Error messages. */ + public static final int ERROR = 0x0002; + /** Trace messages. */ + public static final int TRACE = 0x0004; + + /** To set a flag. */ + private static final boolean SET = true; + + private static int flags = 0; + private static PrintWriter writer = null; + + static { + + InputStream is = null; + try { + try { + is = Debug.class.getResourceAsStream("Debug.properties"); + Properties props = new Properties(); + props.load(is); + + String info = props.getProperty("debug.info", "false"); + info = info.toLowerCase(); + + if (info.equals("true")) { + setFlags(Debug.INFO, Debug.SET); + } + + String trace = props.getProperty("debug.trace", "false"); + trace = trace.toLowerCase(); + + if (trace.equals("true")) { + setFlags(Debug.TRACE, Debug.SET); + } + + String error = props.getProperty("debug.error", "false"); + error = error.toLowerCase(); + + if (error.equals("true")) { + setFlags(Debug.ERROR, Debug.SET); + } + + String w = props.getProperty("debug.output", "System.out"); + setOutput(w); + + } finally { + if (is !=null) + is.close(); + } + } catch (Throwable ex) { + ex.printStackTrace(System.err); + } + } + + /** + * Private constructor so as not to allow any instances of this class. + * + * <p>This serves as a singleton class.</p> + */ + private Debug() { + } + + /** + * Set the output to the specified argument. + * + * <p>This method is only used internally to prevent invalid string + * parameters.</p> + * + * @param str Output specifier. + */ + private static void setOutput(String str) { + if (writer == null) { + if (str.equals("System.out")) { + setOutput(System.out); + } else if (str.equals("System.err")) { + setOutput(System.err); + } else { + try { + setOutput(new FileWriter(str)); + } catch (IOException e) { + e.printStackTrace(System.err); + } + } + } + } + + /** + * Set the output to an {@code OutputStream} object. + * + * @param stream {@code OutputStream} object. + */ + private static void setOutput(OutputStream stream) { + setOutput(new OutputStreamWriter(stream)); + } + + /** + * Set the {@code Writer} object to manage the output. + * + * @param w {@code Writer} object to write out. + */ + private static void setOutput(Writer w) { + if (writer != null) { + writer.close(); + } + writer = new PrintWriter(new BufferedWriter(w), true); + } + + /** + * This method sets the levels for debugging logs. + * + * <p>Example calls:</p> + * + * <blockquote><pre>{@code Debug.setFlags( Debug.INFO, Debug.SET ) + * Debug.setFlags( Debug.TRACE, Debug.SET ) + * Debug.setFlags( Debug.INFO | Debug.TRACE, Debug.SET ) + * Debug.setFlags( Debug.ERROR, Debug.UNSET )}</pre></blockquote> + * + * @param f Debug flag + * @param set Use {@code Debug.SET} to set, and {@code Debug.UNSET} to + * unset the given flag. + */ + private static void setFlags(int f, boolean set) { + if (set) { + flags |= f; + } else { + flags &= ~f; + } + } + + /** + * Checks if flag is set. + * + * @return {@code true} if info logging is on, otherwise {@code false}. + */ + public static boolean isFlagSet(int f) { + return ((flags & f) != 0); + } + + /** + * Log message based on the flag type. + * + * <p>Example 1:</p> + * + * <blockquote><pre>{@code Debug.log(Debug.INFO, "info string here");}</pre> + * </blockquote> + * + * <p>This logs the message during runtime if {@code debug.info} in the + * properties file is set to true.</p> + * + * <p>Example 2:</p> + * + * <blockquote> + * <pre>{@code Debug.log(Debug.INFO | Debug.TRACE, "info string here");}</pre> + * </blockquote> + * + * <p>This logs the message during runtime if debug.info or debug.trace in + * the properties file is set to true.</p> + * + * @param flag Log type, one of the Debug constants {@link #INFO}, + * {@link #TRACE}, {@link #ERROR} or a combination of which + * or'ed together. + * @param msg The message. + */ + public static void log(int flag, String msg) { + if (isFlagSet(flag) && writer != null) { + writer.println(msg); + } + } + + /** + * Log message based on flag type plus print out stack trace of the + * exception passed in. + * + * <p>Refer to the other log method for description.</p> + * + * @param flag Log type, one of the Debug constants {@link #INFO}, + * {@link #TRACE}, {@link #ERROR} or a combination of which + * or'ed together. + * @param msg The message. + * @param e Throwable object. + */ + public static void log(int flag, String msg, Throwable e) { + if (isFlagSet(flag) && writer != null) { + writer.println(msg); + if (e != null) + e.printStackTrace(writer); + } + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties new file mode 100644 index 000000000..5802cb86c --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Debug.properties @@ -0,0 +1,29 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# 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 . +# +# x-no-translate + +# +# debug logging information and settings. +# + +debug.info=false +debug.trace=false +debug.error=false +debug.output=System.err + + diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java new file mode 100644 index 000000000..a796806f9 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/EndianConverter.java @@ -0,0 +1,128 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * Helper class providing static methods to convert data to/from Network Byte + * Order (Big Endian). + * + * <p>With the introduction of {@code java.nio.ByteOrder} and + * {@code java.nio.ByteBuffer} in Java 1.4, it may no longer be necessary to use + * this class in the future.</p> + * + * @version 1.1 + */ +public class EndianConverter { + + /** + * Convert a {@code short} to a Little Endian representation. + * + * @param value The {@code short} to be converted. + * + * @return Two element {@code byte} array containing the converted value. + */ + public static byte[] writeShort (short value) { + return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN) + .putShort(value).array(); + } + + /** + * Convert an integer to a Little Endian representation. + * + * @param value The {@code int} to be converted. + * + * @return Four element {@code byte} array containing the converted value. + */ + public static byte[] writeInt (int value) { + return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN) + .putInt(value).array(); + } + + /** + * Converts a {@code double} to a Little Endian representation of a float in + * IEEE-754 format. + * + * <p>An array with more than eight elements can be used, but only the first + * eight elements will be read.</p> + * + * @param value {@code double} containing the value to be converted. + * + * @return {@code byte} array containing the LE representation of a + * IEEE-754 float. + */ + public static byte[] writeDouble(double value) { + return ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong( + Double.doubleToLongBits(value)).array(); + } + + /** + * Convert a Little Endian representation of a short to a Java {@code short} + * (Network Byte Order). + * + * <p>An array with more than two elements can be used, but only the first + * two elements will be read.</p> + * + * @param value {@code byte} array containing the LE representation of + * the value. + * + * @return {@code short} containing the converted value. + */ + public static short readShort (byte[] value) { + return ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN) + .put(value).getShort(0); + } + + /** + * Convert a Little Endian representation of an integer to a Java {@code int} + * (Network Byte Order). + * + * <p>An array with more than four elements can be used, but only the first + * four elements will be read.</p> + * + * @param value {@code byte} array containing the LE representation of + * the value. + * + * @return {@code int} containing the converted value. + */ + public static int readInt(byte[] value) { + return ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN) + .put(value).getInt(0); + } + + /** + * Convert a Little Endian representation of a float in IEEE-754 Little + * Endian to a Java {@code double} (Network Byte Order). + * + * <p>An array with more than eight elements can be used, but only the first + * eight elements will be read.</p> + * + * @param value {@code byte} array containing the LE representation of an + * IEEE-754 float. + * + * @return {@code double} containing the converted value. + */ + public static double readDouble(byte[] value) { + return Double.longBitsToDouble( + ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).put(value) + .getLong(0)); + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java new file mode 100644 index 000000000..56b8212b6 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/IntArrayList.java @@ -0,0 +1,125 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import java.util.ArrayList; + +/** + * This is a convenience class used to create an {@code ArrayList} of integers. + */ +public class IntArrayList { + + /** The list to hold our integers. */ + private final ArrayList<Integer> list; + + /** + * Constructor. + * + * <p>Creates the list with 0 length.</p> + */ + public IntArrayList() { + list = new ArrayList<Integer>(); + } + + /** + * Constructor. + * + * @param initialCapacity Initial capacity of the list. + */ + public IntArrayList(int initialCapacity) { + list = new ArrayList<Integer>(initialCapacity); + } + + /** + * This method ensures that the list is large enough for {@code minCapacity} + * elements. + * + * @param minCapacity The minimum capacity of the list. + */ + public void ensureCapacity(int minCapacity) { + list.ensureCapacity(minCapacity); + } + + /** + * This method ensures that the list is large enough for {@code minCapacity} + * elements. + * + * <p>It also fills in the new slots in the list with the integer value + * input as {@code fillValue}.</p> + * + * @param minCapacity The minimum capacity of the list. + * @param fillValue This method adds in an integer for each slot that was + * added to ensure that the list meets the minimum + * capacity. {@code fillValue} is the value used as the + * initial value of these added elements. + */ + public void ensureCapacityAndFill(int minCapacity, int fillValue) { + + list.ensureCapacity(minCapacity); + + int needToAdd = minCapacity - list.size(); + if (needToAdd > 0) { + for (int i = 0; i < needToAdd; i++) { + list.add(Integer.valueOf(fillValue)); + } + } + } + + /** + * This method sets an element of the list to the input integer value. + * + * @param index The index in the list of the element we wish to set. + * @param value The integer value that we assign to the selected element + * of the list. + */ + public void set(int index, int value) { + list.set(index, Integer.valueOf(value)); + } + + /** + * This method appends an element to the list. + * + * @param value The integer value that we assign to the element that we + * are appending to the list. + */ + public void add(int value) { + list.add(Integer.valueOf(value)); + } + + /** + * This method gets the integer value stored in element index. + * + * @param index The index in the list of the element we wish to get the + * value from. + * + * @return The value of the data stored in element index. + */ + public int get(int index) { + return list.get(index).intValue(); + } + + /** + * This method gets the size of the list. + * + * @return The size of the list. + */ + public int size() { + return list.size(); + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java new file mode 100644 index 000000000..305100772 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/OfficeUtil.java @@ -0,0 +1,123 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +import org.openoffice.xmerge.converter.xml.OfficeConstants; + +import java.util.ArrayList; + +/** + * Class providing utility methods for OpenOffice plug-ins. + * + * @version 1.1 + */ +public class OfficeUtil implements OfficeConstants { + + /** + * Method to replace whitespace character within text with appropriate + * OpenOffice tags. + * + * @param text The text to parse for whitespace. + * + * @return {@code Node} array containing OpenOffice XML nodes representing + * the text. + */ + public static Node[] parseText(String text, Document parentDoc) { + ArrayList<Node> nodeVec = new ArrayList<Node>(); + + /* + * Break up the text from the text run into Open + * Office text runs. There may be more runs in OO because + * runs of 2 or more spaces map to nodes. + */ + while ((text.indexOf(" ") != -1) || (text.indexOf('\t') != 1)) { + + /* + * Find the indices of tabs and multiple spaces, and + * figure out which of them occurs first in the string. + */ + int spaceIndex = text.indexOf(" "); + int tabIndex = text.indexOf('\t'); + if ((spaceIndex == -1) && (tabIndex == -1)) + break; // DJP This should not be necessary. What is wrong + // with the while() stmt up above? + int closerIndex; // Index of the first of these + if (spaceIndex == -1) + closerIndex = tabIndex; + else if (tabIndex == -1) + closerIndex = spaceIndex; + else + closerIndex = (spaceIndex > tabIndex) ? tabIndex : spaceIndex; + + /* + * If there is any text prior to the first occurrence of a + * tab or spaces, create a text node from it, then chop it + * off the string we're working with. + */ + if (closerIndex > 0) { + String beginningText = text.substring(0, closerIndex); + Text textNode = parentDoc.createTextNode(beginningText); + nodeVec.add(textNode); + } + text = text.substring(closerIndex); + + /* + * Handle either tab character or space sequence by creating + * an element for it, and then chopping out the text that + * represented it in "text". + */ + if (closerIndex == tabIndex) { + Element tabNode = parentDoc.createElement(TAG_TAB_STOP); + nodeVec.add(tabNode); + text = text.substring(1); // tab is always a single character + } else { + // Compute length of space sequence. + int nrSpaces = 2; + while ((nrSpaces < text.length()) + && text.substring(nrSpaces, nrSpaces + 1).equals(" ")) { + nrSpaces++; + } + + Element spaceNode = parentDoc.createElement(TAG_SPACE); + spaceNode.setAttribute(ATTRIBUTE_SPACE_COUNT, + Integer.toString(nrSpaces)); + nodeVec.add(spaceNode); + text = text.substring(nrSpaces); + } + } + + /* + * No more tabs or space sequences. If there's any remaining + * text create a text node for it. + */ + if (text.length() > 0) { + Text textNode = parentDoc.createTextNode(text); + nodeVec.add(textNode); + } + + // Now create and populate an array to return the nodes in. + Node nodes[] = nodeVec.toArray(new Node[nodeVec.size()]); + return nodes; + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java new file mode 100644 index 000000000..aa7dd7c10 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/Resources.java @@ -0,0 +1,74 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import java.util.ResourceBundle; + +/** + * Provides a singleton resource class for converter messages. + * + * <p>By default, this class will search for a {@code ResourceBundle} class file + * or properties file based on the default locale.</p> + * + * <p>A properties file resources.properties will be provided.</p> + * + * <p>Note that if the resource bundle object is not loaded, the construction of + * the singleton object will throw a {@code MissingResourceException}, which is + * a {@code RuntimeException}, thus I opted to not explicitly declare it. If it + * does throw {@code MissingResourceException}, it may be due to a packaging + * problem.</p> + */ +public final class Resources +{ + private final ResourceBundle rb; + private static Resources instance = null; + + /** + * This method returns the singleton instance of this class. + * + * @return The singleton {@code Resources} instance. + */ + public synchronized static Resources getInstance() { + if (instance == null) { + instance = new Resources(); + } + + return instance; + } + + /** + * Default constructor is only accessible within this class. + * + * <p>Load the resource bundle that contains the resource {@code String} + * values.</p> + */ + private Resources() { + rb = ResourceBundle.getBundle("org.openoffice.xmerge.util.resources"); + } + + /** + * This method returns the corresponding {@code String} given the key. + * + * @param key Key string for getting the message {@code String}. + * @return Message {@code String} corresponding to the key. + */ + public String getString(String key) { + return rb.getString(key); + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java new file mode 100644 index 000000000..a8501f8b9 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/TwipsConverter.java @@ -0,0 +1,84 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +/** + * Helper class providing static methods to convert data to/from twips. + */ +public class TwipsConverter { + + /** + * Convert from twips to cm's. + * + * @param value The {@code short} to be converted. + * + * @return {@code float} containing the converted. + */ + public static float twips2cm(int value) { + float inches = (float) value/1440; + float cm = inches*(float)2.54; + return cm; + } + + /** + * Convert from cm's to twips. + * + * @param value {@code float} containing the representation of the value. + * + * @return {@code int} containing the converted value. + */ + private static int cm2twips(float value) { + int twips = (int) ((value/2.54)*1440); + return twips; + } + + /** + * Convert from cm's to twips. + * + * @param value {@code float} containing the representation of the value. + * + * @return {@code int} containing the converted value. + */ + private static int inches2twips(float value) { + return (int) (value*1440); + } + + /** + * Convert {@code String} to twips. + * + * @param value {@code String} in the form {@literal "1.234cm"} or + * {@literal "1.234inch"}. + * @param defaultValue the default value. + * @return the converted value if {@code value} is a well-formatted {@code + * String}, {@code defaultValue} otherwise. + */ + public static int convert2twips(String value, int defaultValue) { + int posi; + + if ((posi = value.indexOf("cm")) != -1) { + float cm = Float.parseFloat(value.substring(0,posi)); + return cm2twips(cm); + } else if ((posi = value.indexOf("inch")) != -1) { + float inches = Float.parseFloat(value.substring(0,posi)); + return inches2twips(inches); + } + + return defaultValue; + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java new file mode 100644 index 000000000..fd39536b3 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/XmlUtil.java @@ -0,0 +1,171 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util; + +import org.w3c.dom.Node; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; + +/** + * Class containing static utility methods for handling XML trees. + */ +public final class XmlUtil { + + /** + * Perform a deep clone of certain {@code Node} which will base on the + * document {@code Node} of the old {@code Node}. + * + * @param oldNode The {@code Document} of this {@code Node} is used to + * clone the {@code Node}. + * @param newNode The <code>Node</code> to clone. + * + * @return The cloned {@code Node}. + */ + public static Node deepClone(Node oldNode, Node newNode) { + Document docNode = oldNode.getOwnerDocument(); + + // clone the starting node + Node clonedNode = cloneNode(docNode, newNode); + + if (clonedNode != null) { + // then clone the sub-tree recursively + cloneTree(docNode, clonedNode, newNode); + } + + return clonedNode; + } + + /** + * Clone the sub-tree under certain given {@code Node}. + * + * @param docNode The {@code Document} used to clone the {@code Node}. + * @param oldNode The {@code Node} to clone. + * @param newNode The destination {@code Node}. + */ + private static void cloneTree(Document docNode, Node oldNode, Node newNode) { + + NodeList nodeList = newNode.getChildNodes(); + int nodeListLen = nodeList.getLength(); + + for (int i = 0; i < nodeListLen; i++) { + Node newClonedChild = cloneNode(docNode, nodeList.item(i)); + if (newClonedChild != null) { + oldNode.appendChild(newClonedChild); + cloneTree(docNode, newClonedChild, nodeList.item(i)); + } + } + } + + /** + * Clone a {@code Node} (either text or element). + * + * @param docNode The {@code Document} used to clone the {@code Node}. + * @param newNode The {@code Node}to clone. + * + * @return The cloned {@code Node}. + */ + private static Node cloneNode(Document docNode, Node newNode) { + + Node clonedNode = null; + + // only support text node and element node (will copy the attributes) + switch (newNode.getNodeType()) { + case Node.TEXT_NODE: + String textStr = newNode.getNodeValue(); + clonedNode = docNode.createTextNode(textStr); + break; + case Node.ELEMENT_NODE: + Element oldElem = (Element)newNode; + String tagName = newNode.getNodeName(); + Element newElem = docNode.createElement(tagName); + + // copy the attributes + NamedNodeMap attrs = oldElem.getAttributes(); + + for (int i = 0; i < attrs.getLength(); i++) { + newElem.setAttribute(attrs.item(i).getNodeName(), + attrs.item(i).getNodeValue()); + } + clonedNode = newElem; + break; + } + return clonedNode; + } + + /** + * Returns the name and type of an XML DOM {@code Node}. + * + * @param node {@code Node} to query. + * + * @return Name and type of XML DOM {@code Node}. + */ + public static String getNodeInfo(Node node) { + + String str = null; + switch (node.getNodeType()) { + + case Node.ELEMENT_NODE: + str = "ELEMENT"; + break; + case Node.ATTRIBUTE_NODE: + str = "ATTRIBUTE"; + break; + case Node.TEXT_NODE: + str = "TEXT"; + break; + case Node.CDATA_SECTION_NODE: + str = "CDATA_SECTION"; + break; + case Node.ENTITY_REFERENCE_NODE: + str = "ENTITY_REFERENCE"; + break; + case Node.ENTITY_NODE: + str = "ENTITY"; + break; + case Node.PROCESSING_INSTRUCTION_NODE: + str = "PROCESSING_INSTRUCTION"; + break; + case Node.COMMENT_NODE: + str = "COMMENT"; + break; + case Node.DOCUMENT_NODE: + str = "DOCUMENT"; + break; + case Node.DOCUMENT_TYPE_NODE: + str = "DOCUMENT_TYPE"; + break; + case Node.DOCUMENT_FRAGMENT_NODE: + str = "DOCUMENT_FRAGMENT"; + break; + case Node.NOTATION_NODE: + str = "NOTATION"; + break; + } + + StringBuffer buffer = new StringBuffer("name=\""); + buffer.append(node.getNodeName()); + buffer.append("\" type=\""); + buffer.append(str); + buffer.append("\""); + + return buffer.toString(); + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/package-info.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/package-info.java new file mode 100644 index 000000000..db76b1cc9 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/package-info.java @@ -0,0 +1,22 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +/** + * Provides general purpose utilities. + */ +package org.openoffice.xmerge.util; diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java new file mode 100644 index 000000000..2190ab27c --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfo.java @@ -0,0 +1,406 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util.registry; + +import java.lang.reflect.Constructor; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Iterator; + +import org.openoffice.xmerge.DocumentDeserializerFactory; +import org.openoffice.xmerge.DocumentMergerFactory; +import org.openoffice.xmerge.DocumentSerializerFactory; +import org.openoffice.xmerge.PluginFactory; + +/** + * Class for storing the information about a converter plug-in. + */ +public class ConverterInfo { + + /** Keep track of the valid Office mime types. */ + private static final String[] validOfficeTypes = new String[] { + // This needs to be updated to reflect all valid office types. + "staroffice/sxw", + "staroffice/sxc" + }; + + private final String piJarName; + private final String piOfficeMime; + private final ArrayList<String> piDeviceMime; + private final String piDisplayName; + private final String piDescription; + private final String piVersion; + private final String piVendor; + private final String piClassImpl; + private String piXsltSerial; + private String piXsltDeserial; + private boolean piCanSerialize = false; + private boolean piCanDeserialize = false; + private boolean piCanMerge = false; + private final ClassLoader piClassLoader; + private PluginFactory piPluginFactory; + + + /** + * The constructor builds a ConverterInfo structure. + * + * @param jarName The URL of the jarfile. + * @param officeMime The office mime-type. + * @param deviceMime The device mime-type. + * @param displayName The display name. + * @param description The description. + * @param version The version. + * @param vendor The vendor name. + * @param impl The implementation class name of + * {@code PluginFactory}. + * @param xsltSerial The URL of the serializer XSL stylesheet + * @param xsltDeserial The URL of the deserializer XSL stylesheet + * + * @throws RegistryException If {@code ci} cannot be loaded. + */ + public ConverterInfo(String jarName, String officeMime, + ArrayList<String> deviceMime, String displayName, + String description, String version, String vendor, + String impl,String xsltSerial, String xsltDeserial) + throws RegistryException { + + if (!isValidOfficeType(officeMime.trim())) { + RegistryException re = new RegistryException( "Invalid office type"); + throw re; + } + + piJarName = jarName.trim(); + piOfficeMime = officeMime.trim(); + piDeviceMime = deviceMime; + piDisplayName = displayName.trim(); + piDescription = description.trim(); + piVersion = version.trim(); + piVendor = vendor.trim(); + piXsltSerial = xsltSerial.trim(); + piXsltDeserial= xsltDeserial.trim(); + piClassImpl = impl.trim(); + piClassLoader = this.getClass().getClassLoader(); + + // Get instance of the PluginFactory. + + try { + final URL jarURL = new URL(jarName); + final URL[] urls = new URL[] { jarURL }; + URLClassLoader loader = AccessController.doPrivileged( + new PrivilegedAction<URLClassLoader>() { + public URLClassLoader run() { + return new URLClassLoader(urls, piClassLoader); + } + }); + Class<?> clas = loader.loadClass(piClassImpl); + Class<?>[] argumentTypes = { org.openoffice.xmerge.util.registry.ConverterInfo.class }; + Constructor<?> construct = clas.getConstructor(argumentTypes); + + Object[] arguments = { this }; + piPluginFactory = ( PluginFactory ) construct.newInstance(arguments); + + // See which interfaces the plug-in PluginFactory supports. + + Class<?>[] cl = piPluginFactory.getClass().getInterfaces(); + for (int i=0; i < cl.length; i++) { + + if (cl[i].getName().equals("org.openoffice.xmerge.DocumentSerializerFactory")) { + piCanSerialize = true; + } + if (cl[i].getName().equals("org.openoffice.xmerge.DocumentDeserializerFactory")) { + piCanDeserialize = true; + } + if (cl[i].getName().equals("org.openoffice.xmerge.DocumentMergerFactory")) { + piCanMerge = true; + } + } + + } catch (Exception e) { + throw new RegistryException( + "Class implementation of the plug-in cannot be loaded.", e); + } + } + + /** + * The constructor builds a ConverterInfo structure. + * + * @param jarName The URL of the jarfile. + * @param officeMime The office mime-type. + * @param deviceMime The device mime-type. + * @param displayName The display name. + * @param description The description. + * @param version The version. + * @param vendor The vendor name. + * @param impl The implementation class name of + * {@code PluginFactory}. + * + * @throws RegistryException If {@code ci} cannot be loaded. + */ + public ConverterInfo(String jarName, String officeMime, + ArrayList<String> deviceMime, String displayName, String description, + String version, String vendor, String impl) + throws RegistryException { + + if (officeMime == null || displayName == null || description == null || + version == null || vendor == null || impl == null) + throw new IllegalArgumentException("arguments unexpected null"); + + if (!isValidOfficeType(officeMime.trim())) { + RegistryException re = new RegistryException( + "Invalid office type"); + throw re; + } + + piJarName = jarName.trim(); + piOfficeMime = officeMime.trim(); + piDeviceMime = deviceMime; + piDisplayName = displayName.trim(); + piDescription = description.trim(); + piVersion = version.trim(); + piVendor = vendor.trim(); + piClassImpl = impl.trim(); + piClassLoader = this.getClass().getClassLoader(); + + // Get instance of the PluginFactory. + + try { + final URL jarURL = new URL(jarName); + final URL[] urls = new URL[] { jarURL }; + URLClassLoader loader = AccessController.doPrivileged( + new PrivilegedAction<URLClassLoader>() { + public URLClassLoader run() { + return new URLClassLoader(urls, piClassLoader); + } + }); + Class<?> clas = loader.loadClass(piClassImpl); + Class<?>[] argumentTypes = { org.openoffice.xmerge.util.registry.ConverterInfo.class }; + Constructor<?> construct = clas.getConstructor(argumentTypes); + + Object[] arguments = { this }; + piPluginFactory = ( PluginFactory ) construct.newInstance(arguments); + + // See which interfaces the plug-in PluginFactory supports. + + Class<?>[] cl = piPluginFactory.getClass().getInterfaces(); + for (int i=0; i < cl.length; i++) { + + if (cl[i].getName().equals("org.openoffice.xmerge.DocumentSerializerFactory")) { + piCanSerialize = true; + } + if (cl[i].getName().equals("org.openoffice.xmerge.DocumentDeserializerFactory")) { + piCanDeserialize = true; + } + if (cl[i].getName().equals("org.openoffice.xmerge.DocumentMergerFactory")) { + piCanMerge = true; + } + } + + } catch (Exception e) { + throw new RegistryException( + "Class implementation of the plug-in cannot be loaded.", e); + } + } + + /** + * Returns an instance of the {@code DocumentDeserializerFactory} interface. + * + * @return instance of the {@code DocumentDeserializer} for this + * {@code ConverterInfo}. + */ + public DocumentSerializerFactory getDocSerializerFactory() { + return (DocumentSerializerFactory)piPluginFactory; + } + + /** + * Returns an instance of the {@code DocumentSerializerFactory} interface. + * + * @return instance of the {@code DocumentSerializer} for this + * {@code ConverterInfo}. + */ + public DocumentDeserializerFactory getDocDeserializerFactory() { + return (DocumentDeserializerFactory)piPluginFactory; + } + + /** + * Returns an instance of the DocumentMergerFactory interface. + * + * @return instance of the {@code DocumentMergerFactory} for this + * {@code ConverterInfo}. + */ + public DocumentMergerFactory getDocMergerFactory() { + return (DocumentMergerFactory)piPluginFactory; + } + + /** + * Returns the jar file name. + * + * @return The jar file name, {@code null} if none exists. + */ + public String getJarName() { + return piJarName; + } + + /** + * Returns the office mime-type. + * + * @return The office mime-type, {@code null} if none exists. + */ + public String getOfficeMime() { + return piOfficeMime; + } + + /** + * Returns an {@code Enumeration} of {@code String} objects indicating the + * device mime-type. + * + * @return An {@code Enumeration} of {@code String} objects indicating the + * device mime-type. + */ + public Iterator<String> getDeviceMime() { + return piDeviceMime.iterator(); + } + + /** + * Returns the display name. + * + * @return The display name, {@code null} if none exists. + */ + public String getDisplayName() { + return piDisplayName; + } + + /** + * Returns the description. + * + * @return The description, {@code null} if none exists. + */ + public String getDescription() { + return piDescription; + } + + /** + * Returns the version. + * + * @return The version, {@code null} if none exists. + */ + public String getVersion() { + return piVersion; + } + + /** + * Returns the vendor name. + * + * @return The vendor name, {@code null} if none exists. + */ + public String getVendor() { + return piVendor; + } + + /** + * Returns the implementation class name of PluginFactory. + * + * @return The implementation class name of {@code PluginFactory}, + * {@code null} if none exists. + */ + public String getClassImpl() { + return piClassImpl; + } + + /** + * Returns the {@code PluginFactory} instance for this plug-in. + * + * @return The {@code PluginFactory} instance for this plug-in. + */ + public PluginFactory getPluginFactory() { + return piPluginFactory; + } + + /** + * Returns {@code true} if this plug-in has a serializer, {@code false} + * otherwise. + * + * @return {@code true} if this plug-in has a serializer, {@code false} + * otherwise. + */ + public boolean canSerialize() { + return piCanSerialize; + } + + /** + * Returns {@code true} if this plug-in has a deserializer, {@code false} + * otherwise. + * + * @return {@code true} if this plug-in has a deserializer, {@code false} + * otherwise. + */ + public boolean canDeserialize() { + return piCanDeserialize; + } + + /** + * Returns {@code true} if this plug-in has a merger, {@code false} + * otherwise. + * + * @return {@code true} if this plug-in has a merger, {@code false} + * otherwise. + */ + public boolean canMerge() { + return piCanMerge; + } + + /** + * Returns {@code true} if the officeMime is a valid Office mime type. + * + * @return {@code true} if the officeMime is a valid Office mime type. + */ + public static boolean isValidOfficeType(String officeMime) { + + boolean rc = false; + for (String validOfficeType : validOfficeTypes) { + if (officeMime.equals(validOfficeType)) { + rc = true; + } + } + + return rc; + } + + /** + * Returns a {@code String} containing the Xslt stylesheet URL that is to be + * used by the Xslt Plug-in Serializer. + * + * @return {@code String}. + */ + public String getXsltSerial() { + return piXsltSerial; + } + + /** + * Returns a {@code String} containing the xslt stylesheet URL that is to be + * used by the Xslt Plug-in Deserializer. + * + * @return {@code String}. + */ + public String getXsltDeserial() { + return piXsltDeserial; + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java new file mode 100644 index 000000000..9cea2df38 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoMgr.java @@ -0,0 +1,477 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util.registry; + +import java.util.*; +import java.io.*; + +/** + * Manages the converter plug-ins that are currently active. + * + * <p>This class allows plug-ins to be added or removed dynamically.</p> + * + * <p>This class is a singleton (static) class, so that only one manager can + * exist at a time. It is final, so it may not be sub-classed.</p> + */ +public final class ConverterInfoMgr { + + private static final ArrayList<ConverterInfo> converterInfoList = new ArrayList<ConverterInfo>(); + + /** + * Adds a converter plug-in to the registry. + * + * <p>The {@code ConverterInfo} must have a unique DisplayName and must have + * non-null values for DisplayName, ClassImpl, OfficeMime, and DeviceMime.</p> + * + * @param ci A {@code ConverterInfo} object describing a plug-in. + * + * @throws RegistryException If the {@code ConverterInfo} is not valid. + */ + private static void addPlugIn(ConverterInfo ci) throws RegistryException { + + // Validate + if (ci.getDisplayName() == null) { + RegistryException re = new RegistryException( + "Converter must have valid name."); + throw re; + } + if (ci.getClassImpl() == null) { + RegistryException re = new RegistryException( + "Converter must have valid class implementation specified."); + throw re; + } + if (ci.getOfficeMime() == null) { + RegistryException re = new RegistryException( + "Converter must have valid office mime specified."); + throw re; + } + if (! ci.getDeviceMime().hasNext()) { + RegistryException re = new RegistryException( + "Converter must have valid device mime specified."); + throw re; + } + + // Verify there is no converter with the same Display Name in the + // registry. + for (ConverterInfo converterInfo : converterInfoList) { + if (ci.getDisplayName().equals(converterInfo.getDisplayName())) { + RegistryException re = new RegistryException( + "Converter with specified display name already exists."); + throw re; + } + } + + // Since this is adding to a static Vector, make sure this add method + // call is synchronized. + synchronized (converterInfoList) { + converterInfoList.add(ci); + } + } + + /** + * Adds a list of converter plug-ins to the registry. + * + * <p>Each {@code ConverterInfo} in the list must have a unique DisplayName + * and must have non-null values for DisplayName, ClassImpl, OfficeMime, and + * DeviceMime.</p> + * + * @param jarEnum An {@code Enumeration} of {@code ConverterInfo} objects + * describing one or more plug-in(s). + * + * @throws RegistryException If a {@code ConverterInfo} in the + * {@code Vector} is not valid. + */ + public static void addPlugIn(Iterator<ConverterInfo> jarEnum) + throws RegistryException { + + while (jarEnum.hasNext()) { + ConverterInfo converterInfo = jarEnum.next(); + addPlugIn(converterInfo); + } + } + + /** + * Returns an {@code Enumeration} of registered {@code ConverterInfo} objects. + * + * @return An {@code Enumeration} containing the currently registered + * {@code ConverterInfo} objects, an empty {@code Vector} if none + * exist. + */ + private static Iterator<ConverterInfo> getConverterInfoEnumeration() { + return converterInfoList.iterator(); + } + + /** + * Removes any {@code ConverterInfo} object from the registry that have the + * specified jar name value. + * + * @param jar The name of the jarfile. + * + * @return {@code true} if a {@code ConverterInfo} object was removed, + * {@code false} otherwise. + */ + public static boolean removeByJar(String jar) { + + boolean rc = false; + + for (Iterator<ConverterInfo> it = converterInfoList.iterator(); it.hasNext();) { + ConverterInfo converterInfo = it.next(); + if (jar.equals(converterInfo.getJarName())) { + it.remove(); + rc = true; + } + } + return rc; + } + + /** + * Removes any {@code ConverterInfo} object from the registry that have the + * specified display name value. + * + * @param name The display name. + * + * @return {@code true} if a {@code ConverterInfo} object was removed, + * {@code false} otherwise. + */ + private static boolean removeByName(String name) { + + boolean rc = false; + + for (Iterator<ConverterInfo> it = converterInfoList.iterator(); it.hasNext();) { + ConverterInfo converterInfo = it.next(); + if (name.equals(converterInfo.getDisplayName())) { + it.remove(); + rc = true; + } + } + return rc; + } + + /** + * Returns the {@code ConverterInfo} object that supports the specified + * device/office mime type conversion. + * + * <p>If there are multiple {@code ConverterInfo} objects registered that + * support this conversion, only the first is returned.</p> + * + * @param deviceMime The device mime. + * @param officeMime The office mime. + * + * @return The first plug-in that supports the specified conversion. + */ + public static ConverterInfo findConverterInfo(String deviceMime, String officeMime) { + + if (deviceMime == null || + !ConverterInfo.isValidOfficeType(officeMime)) { + return null; + } + + // Loop over elements comparing with deviceFromMime + for (ConverterInfo converterInfo : converterInfoList) { + String toDeviceInfo = converterInfo.getOfficeMime(); + Iterator<String> fromEnum = converterInfo.getDeviceMime(); + + // Loop over the deviceMime types. + while (fromEnum.hasNext()) { + String fromDeviceInfo = fromEnum.next(); + if (deviceMime.trim().equals(fromDeviceInfo) && + officeMime.trim().equals(toDeviceInfo)) { + return converterInfo; + } + } + } + return null; + } + + /** + * Returns an array of two {@code ConverterInfo} objects that can be chained + * to perform the specified mime type conversion. + * + * <p>If there are multiple {@code ConverterInfo} objects that support this + * conversion, only the first is returned.</p> + * + * @param deviceFromMime The device from mime. + * @param deviceToMime The device to mime. + * + * @return An array of two {@code ConverterInfo} objects that can be chained + * to perform the specified conversion. + */ + private static ConverterInfo[] findConverterInfoChain(String deviceFromMime, String deviceToMime) { + + if (deviceFromMime == null || deviceToMime == null) { + return null; + } + + ConverterInfo[] converterInfo = new ConverterInfo[2]; + + // Loop over elements comparing with deviceFromMime + Iterator<ConverterInfo> cifEnum = converterInfoList.iterator(); + while (cifEnum.hasNext()) { + + converterInfo[0] = cifEnum.next(); + String fromOfficeInfo = converterInfo[0].getOfficeMime(); + Iterator<String> fromEnum = converterInfo[0].getDeviceMime(); + + // Loop over the deviceMime types looking for a deviceFromMime + // match. + while (fromEnum.hasNext()) { + String fromDeviceInfo = fromEnum.next(); + + if (deviceFromMime.trim().equals(fromDeviceInfo)) { + + // Found a match for deviceFrom. Now loop over the + // elements comparing with deviceToMime + Iterator<ConverterInfo> citEnum = converterInfoList.iterator(); + while (citEnum.hasNext()) { + + converterInfo[1] = citEnum.next(); + String toOfficeInfo = converterInfo[1].getOfficeMime(); + Iterator<String> toEnum = converterInfo[1].getDeviceMime(); + + // Loop over deviceMime types looking for a + // deviceToMime match. + while (toEnum.hasNext()) { + String toDeviceInfo = toEnum.next(); + if (deviceToMime.trim().equals(toDeviceInfo) && + fromOfficeInfo.equals(toOfficeInfo)) { + + // Found a match + return converterInfo; + } + } + } + } + } + } + return null; + } + + static String readLine(BufferedReader br) throws IOException{ + String ret = br.readLine(); + if (ret == null) { + throw new IOException("short read"); + } + return ret; + } + + /** + * Main to let the user specify what plug-ins to register from jarfiles and + * to display the currently registered plug-ins. + * + * @param args Not used. + */ + public static void main(String args[]) { + + ConverterInfoReader cir = null; + boolean validate = false; + InputStreamReader isr = new InputStreamReader(System.in); + BufferedReader br = new BufferedReader(isr); + char c = ' '; + + boolean exitFlag = false; + while (!exitFlag) { + + System.out.println("\nMenu:"); + System.out.println("(L)oad plug-ins from a jar file"); + System.out.println("(D)isplay name unload"); + System.out.println("(J)ar name unload"); + System.out.println("(F)ind ConverterInfo"); + System.out.println("(C)ind ConverterInfo chain"); + System.out.println("(V)iew plug-ins"); + System.out.println("(T)oggle Validation"); + System.out.println("(Q)uit\n"); + + try { + c = readLine(br).toUpperCase().trim().charAt(0); + } catch(Exception e) { + System.out.println("Invalid entry"); + System.out.println("Error msg: " + e.getMessage()); + continue; + } + + System.out.println(""); + + // Quit + if (c == 'Q') { + exitFlag = true; + + // Load by Jarfile + } else if (c == 'L') { + + System.out.println("Enter path to jarfile: "); + try { + String jarname = readLine(br).trim(); + cir = new ConverterInfoReader(jarname,validate); + } catch (RegistryException e) { + System.out.println("Cannot load plug-in ConverterFactory implementation."); + System.out.println("Error msg: " + e.getMessage()); + } catch (Exception e) { + System.out.println("Error adding data to registry"); + System.out.println("Error msg: " + e.getMessage()); + } + + if (cir != null) { + Iterator<ConverterInfo> jarInfoEnum = cir.getConverterInfoEnumeration(); + try { + ConverterInfoMgr.addPlugIn(jarInfoEnum); + } catch (Exception e) { + System.out.println("Error adding data to registry"); + System.out.println("Error msg: " + e.getMessage()); + } + } + + // Unload by Display Name or Jarfile + } else if (c == 'T') { + if (validate){ + System.out.println("Validation switched off"); + validate=false; + } else { + System.out.println("Validation switched on"); + validate=true; + } + } else if (c == 'D' || c == 'J') { + + if (c == 'D') { + System.out.println("Enter display name: "); + } else { + System.out.println("Enter path to jarfile: "); + } + + try { + String name = readLine(br).trim(); + boolean rc = false; + + if (c == 'D') { + rc = ConverterInfoMgr.removeByName(name); + } else { + rc = ConverterInfoMgr.removeByJar(name); + } + + if (rc) { + System.out.println("Remove successful."); + } else { + System.out.println("Remove failed."); + } + + } catch (Exception e) { + System.out.println("Error removing value from registry"); + System.out.println("Error msg: " + e.getMessage()); + } + + // Find Office Mime + + } else if (c == 'F' || c == 'C') { + + String findMimeOne = null; + String findMimeTwo = null; + + if (c == 'F') { + System.out.println("Enter device mime: "); + } else { + System.out.println("Enter device from mime: "); + } + + try { + findMimeOne = readLine(br).trim(); + } catch (Exception e) { + System.out.println("Error adding data to registry"); + System.out.println("Error msg: " + e.getMessage()); + } + + if (c == 'F') { + System.out.println("Enter office mime: "); + } else { + System.out.println("Enter device to mime: "); + } + + try { + findMimeTwo = readLine(br).trim(); + } catch (Exception e) { + System.out.println("Error adding data to registry"); + System.out.println("Error msg: " + e.getMessage()); + } + + if (c == 'F') { + ConverterInfo foundInfo = ConverterInfoMgr.findConverterInfo(findMimeOne, findMimeTwo); + if (foundInfo != null) { + System.out.println(" Found ConverterInfo"); + System.out.println(" DisplayName : " + foundInfo.getDisplayName()); + } else { + System.out.println(" Did not find ConverterInfo"); + } + } else { + ConverterInfo[] foundInfo = ConverterInfoMgr.findConverterInfoChain(findMimeOne, + findMimeTwo); + if (foundInfo != null && foundInfo[0] != null && foundInfo[1] != null ) { + System.out.println(" Found ConverterInfo Chain"); + System.out.println(" DisplayName : " + foundInfo[0].getDisplayName()); + System.out.println(" DisplayName : " + foundInfo[1].getDisplayName()); + } else { + System.out.println(" Did not find ConverterInfo"); + } + } + + // View + + } else if (c == 'V') { + + Iterator<ConverterInfo> ciEnum = ConverterInfoMgr.getConverterInfoEnumeration(); + + int ciCnt = 0; + while (ciEnum.hasNext()) + { + System.out.println(""); + System.out.println(" Displaying converter number " + ciCnt); + ConverterInfo converterInfo = ciEnum.next(); + System.out.println(" DisplayName : " + converterInfo.getDisplayName()); + System.out.println(" JarFile : " + converterInfo.getJarName()); + System.out.println(" Description : " + converterInfo.getDescription()); + System.out.println(" Version : " + converterInfo.getVersion()); + System.out.println(" OfficeMime : " + converterInfo.getOfficeMime()); + Iterator<String> fromEnum = converterInfo.getDeviceMime(); + int feCnt = 1; + while (fromEnum.hasNext()) + { + System.out.println(" DeviceMime : (#" + feCnt + ") : " + + fromEnum.next()); + feCnt++; + } + if (feCnt == 1) { + System.out.println(" DeviceMime : None specified"); + } + + System.out.println(" Vendor : " + converterInfo.getVendor()); + System.out.println(" ClassImpl : " + converterInfo.getClassImpl()); + System.out.println(" XsltSerial : " + converterInfo.getXsltSerial()); + System.out.println(" XsltDeserial : " + converterInfo.getXsltDeserial()); + System.out.println(" Serialize : " + converterInfo.canSerialize()); + System.out.println(" Deserialize : " + converterInfo.canDeserialize()); + System.out.println(" Merge : " + converterInfo.canMerge()); + ciCnt++; + } + + if (ciCnt == 0) { + System.out.println("No converters registered"); + } + } else { + System.out.println("Invalid input"); + } + } + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java new file mode 100644 index 000000000..21831a691 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/ConverterInfoReader.java @@ -0,0 +1,245 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util.registry; + +import java.io.*; +import java.util.*; +import java.util.jar.*; +import org.xml.sax.*; +import org.w3c.dom.*; +import javax.xml.parsers.*; +import java.net.URL; +import java.net.JarURLConnection; + +/** + * The {@code ConverterInfoReader} pulls a {@code META-INF/converter.xml} file + * out of a jar file and parses it, providing access to this information in a + * {@code Vector} of {@code ConverterInfo} objects. + */ +public class ConverterInfoReader { + + private static final String TAG_CONVERTER = "converter"; + private static final String ATTRIB_OFFICE_TYPE = "type"; + private static final String ATTRIB_VERSION = "version"; + private static final String TAG_NAME = "converter-display-name"; + private static final String TAG_DESC = "converter-description"; + private static final String TAG_VENDOR = "converter-vendor"; + private static final String TAG_CLASS_IMPL = "converter-class-impl"; + private static final String TAG_TARGET = "converter-target"; + private static final String ATTRIB_DEVICE_TYPE = "type"; + private static final String TAG_XSLT_DESERIAL = "converter-xslt-deserialize"; + private static final String TAG_XSLT_SERIAL = "converter-xslt-serialize"; + private final String jarfilename; + private final Document document; + private final ArrayList<ConverterInfo> converterInfoList; + + /** + * Constructor. + * + * <p>A jar file is passed in. The jar file is parsed and the {@code Vector} + * of {@code ConverterInfo} objects is built.</p> + * + * @param jar The URL of the jar file to process. + * @param shouldvalidate Boolean to enable or disable xml validation. + * + * @throws IOException If the jar file cannot be read or + * if the META-INF/converter.xml can + * not be read in the jar file. + * @throws ParserConfigurationException If the {@code DocumentBuilder} + * can not be built. + * @throws org.xml.sax.SAXException If the converter.xml file can not + * be parsed. + * @throws RegistryException If the {@code ConverterFactory} + * implementation of a plug-in cannot + * be loaded. + */ + public ConverterInfoReader(String jar,boolean shouldvalidate) throws IOException, + ParserConfigurationException, org.xml.sax.SAXException, + RegistryException { + + converterInfoList = new ArrayList<ConverterInfo>(); + jarfilename = jar; + + // Get Jar via URL + URL url = new URL("jar:" + jar + "!/META-INF/converter.xml"); + JarURLConnection jarConnection = (JarURLConnection)url.openConnection(); + JarEntry jarentry = jarConnection.getJarEntry(); + JarFile jarfile = jarConnection.getJarFile(); + + if (jarfile == null || jarentry == null) { + throw new IOException("Missing jar entry"); + } + + // Build the InputSource + InputStream istream = jarfile.getInputStream(jarentry); + InputSource isource = new InputSource(istream); + + // Get the DOM builder and build the document. + + DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); + + //DTD validation + + if (shouldvalidate) { + System.out.println("Validating xml..."); + builderFactory.setValidating(true); + } + + DocumentBuilder builder = builderFactory.newDocumentBuilder(); + document = builder.parse(isource); + + // Parse the document. + + parseDocument(); + } + + /** + * Loops over the <i>converter</i> {@code Node} in the converter.xml file + * and processes them. + * + * @throws RegistryException If the plug-in associated with a specific + * <i>converter</i> {@code Node} cannot be + * loaded. + */ + private void parseDocument() throws RegistryException { + + Node converterNode; + NodeList converterNodes = document.getElementsByTagName(TAG_CONVERTER); + + for (int i=0; i < converterNodes.getLength(); i++) { + converterNode = converterNodes.item(i); + if (converterNode.getNodeType() == Node.ELEMENT_NODE) { + parseConverterNode((Element)converterNode); + } + } + } + + /** + * Parses a <i>converter</i> node, pulling the information out of the + * {@code Node} and placing it in a {@code ConverterInfo} object, and adds + * that object to a {@code Vector} of {@code ConverterInfo} objects. + * + * @param e The {@code Element} corresponding to the <i>converter</i> + * XML tag. + * + * @throws RegistryException If the plug-in cannot be loaded. + */ + private void parseConverterNode(Element e) throws RegistryException { + + Element detailElement; + Node detailNode; + String elementTagName; + String officeMime = null; + ArrayList<String> deviceMime = new ArrayList<String>(); + String name = null; + String desc = null; + String version = null; + String vendor = null; + String classImpl = null; + String xsltSerial = null; + String xsltDeserial = null; + String temp; + + temp = e.getAttribute(ATTRIB_OFFICE_TYPE); + if (temp.length() != 0) { + officeMime = temp; + } + + temp = e.getAttribute(ATTRIB_VERSION); + if (temp.length() != 0) { + version = temp; + } + + NodeList detailNodes = e.getChildNodes(); + for (int i=0; i < detailNodes.getLength(); i++) { + + detailNode = detailNodes.item(i); + if (detailNode.getNodeType() == Node.ELEMENT_NODE) { + + detailElement = (Element)detailNode; + elementTagName = detailElement.getTagName(); + + if (TAG_NAME.equalsIgnoreCase(elementTagName)) { + name = getTextValue(detailElement); + } else if (TAG_DESC.equalsIgnoreCase(elementTagName)) { + desc = getTextValue(detailElement); + } else if (TAG_VENDOR.equalsIgnoreCase(elementTagName)) { + vendor = getTextValue(detailElement); + } else if (TAG_XSLT_SERIAL.equalsIgnoreCase(elementTagName)) { + xsltSerial = getTextValue(detailElement); + } else if (TAG_XSLT_DESERIAL.equalsIgnoreCase(elementTagName)) { + xsltDeserial = getTextValue(detailElement); + } else if (TAG_CLASS_IMPL.equalsIgnoreCase(elementTagName)) { + classImpl = getTextValue(detailElement); + } else if (TAG_TARGET.equalsIgnoreCase(elementTagName)) { + temp = detailElement.getAttribute(ATTRIB_DEVICE_TYPE); + if (temp.length() != 0) { + deviceMime.add(temp); + } + } + } + } + + ConverterInfo converterInfo; + if ((xsltSerial == null) || (xsltDeserial == null)) { + converterInfo = new ConverterInfo(jarfilename, + officeMime, deviceMime, name, + desc, version, vendor, classImpl); + } else { + converterInfo = new ConverterInfo(jarfilename, + officeMime, deviceMime, name, + desc, version, vendor, classImpl, + xsltSerial, xsltDeserial); + } + converterInfoList.add(converterInfo); + } + + /** + * Helper function to get the text value of an {@code Element}. + * + * @param e The {@code Element} to process. + * + * @return The text value of the {@code Element}. + */ + private String getTextValue(Element e) { + + NodeList tempNodes = e.getChildNodes(); + String text = null; + Node tempNode; + + for (int j=0; j < tempNodes.getLength(); j++) { + tempNode = tempNodes.item(j); + if (tempNode.getNodeType() == Node.TEXT_NODE) { + text = tempNode.getNodeValue().trim(); + break; + } + } + + return text; + } + + /** + * Returns an {@code Enumeration} of {@code ConverterInfo} objects. + * + * @return An {@code Enumeration} of {@code ConverterInfo} objects. + */ + public Iterator<ConverterInfo> getConverterInfoEnumeration() { + return converterInfoList.iterator(); + } +} diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java new file mode 100644 index 000000000..6452256d2 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/RegistryException.java @@ -0,0 +1,38 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +package org.openoffice.xmerge.util.registry; + +/** + * This {@code Exception} is thrown by converter registry algorithms. + */ +public class RegistryException extends Exception { + + /** + * Exception thrown by merge algorithms. + * + * @param message Message to be included in the {@code Exception}. + */ + public RegistryException(String message) { + super(message); + } + + public RegistryException(String message, Throwable cause) { + super(message, cause); + } +}
\ No newline at end of file diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package-info.java b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package-info.java new file mode 100644 index 000000000..8634ab0a9 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/registry/package-info.java @@ -0,0 +1,59 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * 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 . + */ + +/** + * Provides an interface for plug-in registration. + * + * <p>Each plug-in must have a corresponding Plug-in Configuration XML File + * which is named converter.xml. If the plug-in is stored in a jarfile, this + * converter.xml file is typically stored in the following location in the + * jarfile:</p> + * + * <blockquote>META-INF/converter.xml</blockquote> + * + * <p>The Plug-in Configuration XML File must validate against the converter.dtd + * file provided with this package. Since a jarfile can contain multiple + * plug-ins, this DTD supports specifying multiple plug-ins per jarfile. Please + * refer to the SDK document for more information about how to implement a + * Plug-in Configuration XML File for a specific plug-in.</p> + * + * <p>All information in the Plug-in Configuration XML File is bundled into one + * or more {@code ConverterInfo} object. The {@code ConverterInfoReader} object + * is used to build a {@code Vector} of {@code ConverterInfo} objects from a + * jarfile.</p> + * + * <p>The {@code ConverterInfoMgr} manages the registry of {@code ConverterInfo}. + * It is a singleton class, so that only one registry manager will ever exist. + * It is the client program's responsibility to register {@code ConverterInfo} + * objects that correspond to the plug-ins that are to be used.</p> + * + * <h2>TODO/IDEAS list</h2> + * <ol> + * <li>The {@code ConverterInfo} object could contain + * {@code org.w3c.dom.Document} fragments that are accessed in a generic + * fashion rather than get/set methods for each item in the DTD. This would + * provide a more flexible approach, especially for adding custom tags to a + * specific Plug-in Configuration XML file (tags that are only used by its + * associated plug-in).</li> + * <li>{@code ConverterInfo} should allow the merge/serialize/deserialize logic + * to be included in separate plug-ins, if desired.</li> + * <li>{@code ConverterInfoMgr} could use the Java Activation Framework (JAF) + * to manage registration.</li> + * </ol> + */ +package org.openoffice.xmerge.util.registry; diff --git a/xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties new file mode 100644 index 000000000..95e10b9e6 --- /dev/null +++ b/xmerge/source/xmerge/java/org/openoffice/xmerge/util/resources.properties @@ -0,0 +1,59 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# 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 . +# +# x-no-translate + +# +# resources.properties +# +# resources for org.openoffice.xmerge.converter package. +# +NULL_MIME_EXCEPTION=Cannot specify null MIME types +EMPTY_MIME_EXCEPTION=Cannot specify empty MIME types +CANNOT_LOAD_CLASS=Unable to load class +CANNOT_INST_CLASS=Unable to instantiate class +NOT_AN_INSTANCE= is not an instance of +CANNOT_FIND_REGISTERED=Cannot find registered class +PARSE_ERROR=Parse Error +LINE=Line +COLUMN=Column +PUBLIC_ID=PublicId +SYSTEM_ID=SystemId +INVALID_LOG_LEVEL=Invalid log level specified +OPERATION_NOT_SUPPORTED=Operation not supported +TEMPLATE_FILE_LOAD_ERROR=Error in loading template file - + +# +# diff/merge algorithm error messages +# +EMPTY_NODE_EXCEPTION=Current Node is empty +NOT_LEAFNODE_EXCEPTION=Current Node is not a leaf node +ROOTNODE_EXCEPTION=Cannot perform insert/append/remove on root node +NOT_TEXTNODE_EXCEPTION=The target Node is not a TEXT_NODE, it is - +NULL_NODE_EXCEPTION=The initial Xmldocument node is null +CELL_NODE_EXCEPTION1=Cell node do not have only 1 child <text:p> nodes, will skip the merge of this node.Num of PARA child nodes: +CELL_NODE_EXCEPTION2=Cell node have a non Element child nodes - +CELL_NODE_EXCEPTION2=There is a child node under an expected empty cell node. +NOT_ELEM_NODE_ERROR=The compared nodes are not an Element Node +NOT_PARA_NODE_ERROR=The compared nodes are not a Paragraph or Heading node - +NOT_NODE_ERROR=The compared nodes are not a Node +# +# SXW to/from DOC conversion error messages. +# +UNKNOWN_DOC_VERSION=Unknown DOC version. +DOC_TEXT_LENGTH_EXCEEDED=DOC text length exceeds maximum value. +DOC_TEXT_RECORD_SIZE_EXCEEDED=DOC text record exceeds size limit. |