home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / VCAFE.3.0A / Main.bin / Properties.java < prev    next >
Text File  |  1998-10-23  |  35KB  |  1,429 lines

  1. package com.symantec.itools.util;
  2.  
  3.  
  4. import java.io.BufferedReader;
  5. import java.io.FileOutputStream;
  6. import java.io.File;
  7. import java.io.InputStream;
  8. import java.io.InputStreamReader;
  9. import java.io.IOException;
  10. import java.io.LineNumberReader;
  11. import java.io.OutputStream;
  12. import java.io.PushbackReader;
  13. import java.lang.reflect.Constructor;
  14. import java.lang.reflect.InvocationTargetException;
  15. import java.net.URL;
  16. import java.util.Enumeration;
  17. import java.util.Vector;
  18. import com.symantec.itools.io.FileSystem;
  19. import com.symantec.itools.lang.Debug;
  20. import com.symantec.itools.lang.DynamicClassException;
  21. import com.symantec.itools.lang.NotImplementedError;
  22.  
  23.  
  24. /**
  25.  * @author Symantec Internet Tools Division
  26.  * @version 1.0
  27.  * @since VCafe 3.0
  28.  */
  29.  
  30. public class Properties
  31.     extends java.util.Properties
  32. {
  33.  
  34.     /**
  35.      * @since VCafe 3.0
  36.      */
  37.     protected final static String INDENT = "    ";
  38.  
  39.     /**
  40.      * @since VCafe 3.0
  41.      */
  42.     protected String  fileName;
  43.  
  44.     /**
  45.      * @since VCafe 3.0
  46.      */
  47.     protected boolean saveChanges;
  48.  
  49.     /**
  50.      * @since VCafe 3.0
  51.      */
  52.     protected boolean saved;
  53.  
  54.     /**
  55.      * @since VCafe 3.0
  56.      */
  57.     protected boolean extendedPropertiesFileFormat;
  58.  
  59.     {
  60.         extendedPropertiesFileFormat = true;
  61.     }
  62.  
  63.     public Properties()
  64.     {
  65.     }
  66.  
  67.     public Properties(String name)
  68.         throws IOException
  69.     {
  70.         InputStream is;
  71.  
  72.         if(name.charAt(0) != '/')
  73.         {
  74.             name = '/' + name;
  75.         }
  76.  
  77.         is = null;
  78.  
  79.         try
  80.         {
  81.             is = Properties.class.getResourceAsStream(name);
  82.             load(is);
  83.         }
  84.         finally
  85.         {
  86.             if(is != null)
  87.             {
  88.                 is.close();
  89.             }
  90.         }
  91.     }
  92.  
  93.     public Properties(URL url)
  94.         throws IOException
  95.     {
  96.         InputStream is;
  97.         
  98.         is       = null;
  99.         fileName = url.getFile();
  100.         
  101.         try
  102.         {
  103.             is = url.openStream();
  104.             load(is);
  105.         }
  106.         finally
  107.         {
  108.             if(is != null)
  109.             {
  110.                 is.close();
  111.             }
  112.         }
  113.     }
  114.  
  115.     public Properties(InputStream stream)
  116.         throws IOException
  117.     {
  118.         load(stream);
  119.     }
  120.  
  121.     public Properties(Properties properties)
  122.     {
  123.  
  124.         load(properties);
  125.         fileName = properties.fileName;
  126.     }
  127.  
  128.     public Properties(String[][] data)
  129.     {
  130.         load(data);
  131.     }
  132.  
  133.     /**
  134.      * @param properties TODO
  135.      * @since VCafe 3.0
  136.      */
  137.     public void load(java.util.Properties properties)
  138.     {
  139.         for(Enumeration e = properties.keys(); e.hasMoreElements();)
  140.         {
  141.             Object key;
  142.  
  143.             key = e.nextElement();
  144.             super.put(key, properties.get(key));
  145.         }
  146.  
  147.         saved = false;
  148.     }
  149.  
  150.     /**
  151.      * @param data TODO
  152.      * @since VCafe 3.0
  153.      */
  154.     public void load(String[][] data)
  155.     {
  156.         for(int i = 0; i < data.length; i++)
  157.         {
  158.             super.put(data[i][0], data[i][1]);
  159.         }
  160.  
  161.         saved = false;
  162.     }
  163.  
  164.     /**
  165.      * @param in TODO
  166.      * @exception java.io.IOException
  167.      * @since VCafe 3.0
  168.      */
  169.     public synchronized void load(InputStream in)
  170.         throws IOException
  171.     {
  172.         BufferedReader   bufferedReader;
  173.         LineNumberReader lineReader;
  174.         PushbackReader   reader;
  175.         int              ch;
  176.         String           key;
  177.         Object           value;
  178.  
  179.         if(in == null)
  180.         {
  181.             throw new IOException("Input Stream is null");
  182.         }
  183.         
  184.         bufferedReader = new BufferedReader(new InputStreamReader(in));
  185.         lineReader     = new LineNumberReader(bufferedReader);
  186.         reader         = new PushbackReader(lineReader);
  187.         ch             = reader.read();
  188.  
  189.         if(ch == '{')
  190.         {
  191.             ch = reader.read();
  192.  
  193.             while(ch >= 0 && ch != '}')
  194.             {
  195.                 reader.unread(ch);
  196.                 key = readKey(reader, lineReader);
  197.                 
  198.                 if(key.indexOf('$') == -1)
  199.                 {
  200.                     value = readValue(reader, lineReader, ';');
  201.                     skipWhitespace(reader, lineReader);
  202.                 }
  203.                 else
  204.                 {
  205.                     value = skipWhitespace(reader, lineReader);
  206.                 }
  207.                 
  208.                   super.put(key, value);
  209.                 
  210.                 ch = reader.read();
  211.             }
  212.  
  213.             if(ch < 0)
  214.             {
  215.                 throw new IOException("Unexpected termination of input reader - no closing '}' character found on line" +
  216.                                       lineReader.getLineNumber());
  217.             }
  218.             
  219.             extendedPropertiesFileFormat = true;
  220.             // ignore everything after the closing curly
  221.         }
  222.         else
  223.         {
  224.             super.load(in);
  225.             extendedPropertiesFileFormat = false;
  226.         }
  227.     }
  228.  
  229.     /**
  230.      * @param key TODO
  231.      * @param value TODO
  232.      * @since VCafe 3.0
  233.      */
  234.     public Object put(Object key, Object value)
  235.     {
  236.         if(extendedPropertiesFileFormat)
  237.         {
  238.             if(!((value instanceof String)     || (value instanceof String[]) ||
  239.                  (value instanceof Properties) || (value instanceof Properties[])))
  240.             {
  241.                 throw new NotImplementedError("put(Object, Object) is not allowed for Extended Properties");
  242.             }
  243.         }
  244.  
  245.         saved = false;
  246.  
  247.         return (super.put(key, value));
  248.     }
  249.  
  250.     /**
  251.      * @param f TODO
  252.      * @since VCafe 3.0
  253.      */
  254.     public void setSaveChanges(boolean f)
  255.     {
  256.         saveChanges = f;
  257.     }
  258.  
  259.     /**
  260.      * @since VCafe 3.0
  261.      */
  262.     public boolean isSaveChanges()
  263.     {
  264.         return (saveChanges);
  265.     }
  266.  
  267.     /**
  268.      * @param name TODO
  269.      * @since VCafe 3.0
  270.      */
  271.     public void setFileName(String name)
  272.     {
  273.         fileName = FileSystem.getCanonicalPath(name, true);
  274.     }
  275.  
  276.     /**
  277.      * @since VCafe 3.0
  278.      */
  279.     public String getFileName()
  280.     {
  281.         return (fileName);
  282.     }
  283.  
  284.     /**
  285.      * @param f TODO
  286.      * @since VCafe 3.0
  287.      */
  288.     public void setExtendedPropertiesFileFormat(boolean f)
  289.     {
  290.         extendedPropertiesFileFormat = f;
  291.     }
  292.  
  293.     /**
  294.      * @since VCafe 3.0
  295.      */
  296.     public boolean getExtendedPropertiesFileFormat()
  297.     {
  298.         return (extendedPropertiesFileFormat);
  299.     }
  300.  
  301.     /**
  302.      * @exception java.lang.Throwable
  303.      * @since VCafe 3.0
  304.      */
  305.     public void finalize()
  306.         throws Throwable
  307.     {
  308.         super.finalize();
  309.  
  310.         if(saveChanges && fileName != null && !saved)
  311.         {
  312.             save(fileName);
  313.         }
  314.     }
  315.  
  316.     /**
  317.      * @param key TODO
  318.      * @param value TODO
  319.      * @since VCafe 3.0
  320.      */
  321.     public void set(String key, String value)
  322.     {
  323.         super.put(key, value);
  324.     }
  325.  
  326.     /**
  327.      * @param key TODO
  328.      * @param f TODO
  329.      * @since VCafe 3.0
  330.      */
  331.     public void set(String key, boolean f)
  332.     {
  333.         super.put(key, new Boolean(f).toString());
  334.     }
  335.  
  336.     /**
  337.      * @param key TODO
  338.      * @param i TODO
  339.      * @since VCafe 3.0
  340.      */
  341.     public void set(String key, int i)
  342.     {
  343.         super.put(key, Integer.toString(i));
  344.     }
  345.  
  346.     /**
  347.      * @param key TODO
  348.      * @param f TODO
  349.      * @since VCafe 3.0
  350.      */
  351.     public void set(String key, float f)
  352.     {
  353.         super.put(key, Float.toString(f));
  354.     }
  355.  
  356.     /**
  357.      * @param key TODO
  358.      * @param l TODO
  359.      * @since VCafe 3.0
  360.      */
  361.     public void set(String key, long l)
  362.     {
  363.         super.put(key, Long.toString(l));
  364.     }
  365.  
  366.     /**
  367.      * @param key TODO
  368.      * @param d TODO
  369.      * @since VCafe 3.0
  370.      */
  371.     public void set(String key, double d)
  372.     {
  373.         super.put(key, Double.toString(d));
  374.     }
  375.  
  376.     /**
  377.      * @param key TODO
  378.      * @param clazz TODO
  379.      * @since VCafe 3.0
  380.      */
  381.     public void set(String key, Class clazz)
  382.     {
  383.         super.put(key, clazz.getName());
  384.     }
  385.  
  386.     /**
  387.      * @param key TODO
  388.      * @param value TODO
  389.      * @since VCafe 3.0
  390.      */
  391.     public void set(String key, Properties value)
  392.     {
  393.         super.put(key, value);
  394.     }
  395.  
  396.     /**
  397.      * @param key TODO
  398.      * @param value TODO
  399.      * @since VCafe 3.0
  400.      */
  401.     public void set(String key, String[] value)
  402.     {
  403.         if(value == null)
  404.         {
  405.             value = new String[0];
  406.         }
  407.  
  408.         super.put(key, value);
  409.     }
  410.  
  411.     /**
  412.      * @param key TODO
  413.      * @param value TODO
  414.      * @since VCafe 3.0
  415.      */
  416.     public void set(String key, Properties[] value)
  417.     {
  418.         if(value == null)
  419.         {
  420.             value = new Properties[0];
  421.         }
  422.  
  423.         super.put(key, value);
  424.     }
  425.  
  426.     /**
  427.      * @param key TODO
  428.      * @since VCafe 3.0
  429.      */
  430.     public String getString(String key)
  431.     {
  432.         return getProperty(key, null);
  433.     }
  434.  
  435.     /**
  436.      * @param key TODO
  437.      * @param defaultValue TODO
  438.      * @since VCafe 3.0
  439.      */
  440.     public String getString(String key, String defaultValue)
  441.     {
  442.         return getProperty(key, defaultValue);
  443.     }
  444.  
  445.     /**
  446.      * @param key TODO
  447.      * @since VCafe 3.0
  448.      */
  449.     public boolean getBoolean(String key)
  450.     {
  451.         return (getBoolean(key, false));
  452.     }
  453.  
  454.     /**
  455.      * @param key TODO
  456.      * @param defaultValue TODO
  457.      * @since VCafe 3.0
  458.      */
  459.     public boolean getBoolean(String key, boolean defaultValue)
  460.     {
  461.         String value;
  462.  
  463.         value = getProperty(key);
  464.  
  465.         if(value != null)
  466.         {
  467.             return (new Boolean(value).booleanValue());
  468.         }
  469.  
  470.         return (defaultValue);
  471.     }
  472.  
  473.     /**
  474.      * @param key TODO
  475.      * @since VCafe 3.0
  476.      */
  477.     public int getInteger(String key)
  478.     {
  479.         return (getInteger(key, 0));
  480.     }
  481.  
  482.     /**
  483.      * @param key TODO
  484.      * @param defaultValue TODO
  485.      * @since VCafe 3.0
  486.      */
  487.     public int getInteger(String key, int defaultValue)
  488.     {
  489.         String value;
  490.  
  491.         value = getProperty(key);
  492.  
  493.         try
  494.         {
  495.             if(value != null)
  496.             {
  497.                 return (Integer.parseInt(value));
  498.             }
  499.         }
  500.         catch(NumberFormatException ex)
  501.         {
  502.         }
  503.  
  504.         return (defaultValue);
  505.     }
  506.  
  507.     /**
  508.      * @param key TODO
  509.      * @since VCafe 3.0
  510.      */
  511.     public long getLong(String key)
  512.     {
  513.         return (getLong(key, 0));
  514.     }
  515.  
  516.     /**
  517.      * @param key TODO
  518.      * @param defaultValue TODO
  519.      * @since VCafe 3.0
  520.      */
  521.     public long getLong(String key, long defaultValue)
  522.     {
  523.         String value;
  524.  
  525.         value = getProperty(key);
  526.  
  527.         try
  528.         {
  529.             if(value != null)
  530.             {
  531.                 return (Long.parseLong(value));
  532.             }
  533.         }
  534.         catch(NumberFormatException ex)
  535.         {
  536.         }
  537.  
  538.         return (defaultValue);
  539.     }
  540.  
  541.     /**
  542.      * @param key TODO
  543.      * @since VCafe 3.0
  544.      */
  545.     public float getFloat(String key)
  546.     {
  547.         return (getFloat(key, 0.0f));
  548.     }
  549.  
  550.     /**
  551.      * @param key TODO
  552.      * @param defaultValue TODO
  553.      * @since VCafe 3.0
  554.      */
  555.     public float getFloat(String key, float defaultValue)
  556.     {
  557.         String value;
  558.  
  559.         value = getProperty(key);
  560.  
  561.         try
  562.         {
  563.             if(value != null)
  564.             {
  565.                 return (Float.valueOf(value).floatValue());
  566.             }
  567.         }
  568.         catch(NumberFormatException ex)
  569.         {
  570.         }
  571.  
  572.         return (defaultValue);
  573.     }
  574.  
  575.     /**
  576.      * @param key TODO
  577.      * @since VCafe 3.0
  578.      */
  579.     public double getDouble(String key)
  580.     {
  581.         return (getDouble(key, 0.0));
  582.     }
  583.  
  584.     /**
  585.      * @param key TODO
  586.      * @param defaultValue TODO
  587.      * @since VCafe 3.0
  588.      */
  589.     public double getDouble(String key, double defaultValue)
  590.     {
  591.         String value;
  592.  
  593.         value = getProperty(key);
  594.  
  595.         try
  596.         {
  597.             if(value != null)
  598.             {
  599.                 return (Double.valueOf(value).doubleValue());
  600.             }
  601.         }
  602.         catch(NumberFormatException ex)
  603.         {
  604.         }
  605.  
  606.         return (defaultValue);
  607.     }
  608.  
  609.     /**
  610.      * @param key TODO
  611.      * @exception java.lang.ClassNotFoundException
  612.      * @since VCafe 3.0
  613.      */
  614.     public Class getClass(String key)
  615.         throws ClassNotFoundException,
  616.                KeyNotFoundException
  617.     {
  618.         String className;
  619.  
  620.         className = getProperty(key);
  621.  
  622.         if(className == null)
  623.         {
  624.             throw new KeyNotFoundException(key);
  625.         }
  626.  
  627.         return (Class.forName(getProperty(key)));
  628.     }
  629.  
  630.     /**
  631.      * @param key TODO
  632.      * @exception com.symantec.itools.lang.DynamicClassException
  633.      * @since VCafe 3.0
  634.      */
  635.     public Object getNewInstanceOfClass(String key)
  636.         throws DynamicClassException
  637.     {
  638.         String className;
  639.  
  640.         className = getString(key);
  641.  
  642.         if(className == null)
  643.         {
  644.             return (null);
  645.         }
  646.  
  647.         try
  648.         {
  649.             return (Class.forName(className).newInstance());
  650.         }
  651.         catch(ClassNotFoundException ex)
  652.         {
  653.             throw new DynamicClassException(className, "class cannot be found");
  654.         }
  655.         catch(InstantiationException ex)
  656.         {
  657.             throw new DynamicClassException(className, "class is either abstract or an interface)");
  658.         }
  659.         catch(IllegalAccessException ex)
  660.         {
  661.             throw new DynamicClassException(className, "class is not public");
  662.         }
  663.     }
  664.  
  665.     /**
  666.      * @param key TODO
  667.      * @param argTypes TODO
  668.      * @param args TODO
  669.      * @exception com.symantec.itools.lang.DynamicClassException
  670.      * @since VCafe 3.0
  671.      */
  672.     public Object getNewInstanceOfClass(String key, Class[] argTypes, Object[] args)
  673.         throws DynamicClassException
  674.     {
  675.         String className;
  676.  
  677.         className = getString(key);
  678.  
  679.         if(className == null)
  680.         {
  681.             return (null);
  682.         }
  683.  
  684.         try
  685.         {
  686.             return (Class.forName(className).getConstructor(argTypes).newInstance(args));
  687.         }
  688.         catch(NoSuchMethodException ex)
  689.         {
  690.             throw new DynamicClassException(className, "specified constructor does not exist");
  691.         }
  692.         catch(InvocationTargetException ex)
  693.         {
  694.             throw new DynamicClassException(className, ex.getTargetException().getMessage());
  695.         }
  696.         catch(ClassNotFoundException ex)
  697.         {
  698.             throw new DynamicClassException(className, "class cannot be found");
  699.         }
  700.         catch(InstantiationException ex)
  701.         {
  702.             throw new DynamicClassException(className, "class is either abstract or an interface)");
  703.         }
  704.         catch(IllegalAccessException ex)
  705.         {
  706.             throw new DynamicClassException(className, "class is not public");
  707.         }
  708.     }
  709.  
  710.     /**
  711.      * @param key TODO
  712.      * @since VCafe 3.0
  713.      */
  714.     public Properties getProperties(String key)
  715.     {
  716.         try
  717.         {
  718.             return ((Properties)get(key));
  719.         }
  720.         catch(ClassCastException ex)
  721.         {
  722.         }
  723.  
  724.         return (null);
  725.     }
  726.  
  727.     /**
  728.      * @param key TODO
  729.      * @since VCafe 3.0
  730.      */
  731.     public String[] getStringList(String key)
  732.     {
  733.         String[] value;
  734.  
  735.         try
  736.         {
  737.             value = (String[])get(key);
  738.         }
  739.         catch(ClassCastException ex)
  740.         {
  741.             return (new String[0]);
  742.         }
  743.  
  744.         if(value == null)
  745.         {
  746.             return (new String[0]);
  747.         }
  748.  
  749.         return (value);
  750.     }
  751.  
  752.     /**
  753.      * @param key TODO
  754.      * @param defaultValue TODO
  755.      * @since VCafe 3.0
  756.      */
  757.     public String[] getStringList(String key, String[] defaultValue)
  758.     {
  759.         String[] value;
  760.  
  761.         try
  762.         {
  763.             value = (String[])get(key);
  764.         }
  765.         catch(ClassCastException ex)
  766.         {
  767.             return (defaultValue);
  768.         }
  769.  
  770.         if(value == null)
  771.         {
  772.             return (defaultValue);
  773.         }
  774.  
  775.         return (value);
  776.     }
  777.  
  778.     /**
  779.      * @param key TODO
  780.      * @since VCafe 3.0
  781.      */
  782.     public Properties[] getPropertiesList(String key)
  783.     {
  784.         Properties[] value;
  785.  
  786.         try
  787.         {
  788.             value = (Properties[])get(key);
  789.         }
  790.         catch(ClassCastException ex)
  791.         {
  792.             return (new Properties[0]);
  793.         }
  794.  
  795.         if(value == null)
  796.         {
  797.             return (new Properties[0]);
  798.         }
  799.  
  800.         return (value);
  801.     }
  802.  
  803.    /**
  804.     * @param reader TODO
  805.     * @param lineReader TODO
  806.     * @exception java.io.IOException
  807.     * @since VCafe 3.0
  808.     */
  809.    protected String skipWhitespace(PushbackReader reader, LineNumberReader lineReader)
  810.         throws IOException
  811.     {
  812.         StringBuffer buf;
  813.         int          ch;
  814.  
  815.         buf = new StringBuffer();
  816.         ch  = reader.read();
  817.  
  818.            while((ch >= 0) && ((Character.isSpaceChar((char)ch)) || (ch == '\t') || (ch == '\n') || (ch == '\r') || 
  819.                                (ch == '/') || (ch == '#')))
  820.            {
  821.                buf.append((char)ch);
  822.                
  823.                if(ch == '/')
  824.                {
  825.                    ch = reader.read();
  826.                    buf.append((char)ch);
  827.  
  828.                    if(ch == '*')
  829.                    {
  830.                        // read until closing star-slash combo
  831.                        boolean justSawClosingStar;
  832.                        
  833.                        justSawClosingStar = false;
  834.  
  835.                        while((ch >= 0) && !((ch == '/') && justSawClosingStar))
  836.                        {
  837.                            justSawClosingStar = (ch == '*');
  838.                            ch = reader.read();
  839.                            buf.append((char)ch);
  840.                        }
  841.                    }
  842.                    else if(ch == '/')
  843.                    {
  844.                        // read until end of line
  845.                        while((ch >= 0) && (ch != '\r') && (ch != '\n'))
  846.                        {
  847.                            ch = reader.read();
  848.                            buf.append((char)ch);
  849.                        }
  850.                    }
  851.                }
  852.                else if(ch == '#')
  853.                {
  854.                    while((ch >= 0) && (ch != '\r') && (ch != '\n'))
  855.                    {
  856.                        ch = reader.read();
  857.                        buf.append((char)ch);
  858.                    }
  859.                }
  860.  
  861.                ch = reader.read();
  862.                buf.append((char)ch);
  863.            }
  864.  
  865.         reader.unread(ch);
  866.         
  867.         if(buf.length() > 0)
  868.         {
  869.             buf.setLength(buf.length() - 1);
  870.         }
  871.         
  872.         return (buf.toString());
  873.     }
  874.  
  875.     /**
  876.      * @param reader TODO
  877.      * @param lineReader TODO
  878.      * @exception java.io.IOException
  879.      * @since VCafe 3.0
  880.      */
  881.     protected String readKey(PushbackReader reader, LineNumberReader lineReader)
  882.         throws IOException
  883.     {
  884.         int          ch;
  885.         StringBuffer key;
  886.  
  887.         skipWhitespace(reader, lineReader);
  888.         ch  = reader.read();
  889.         key = new StringBuffer();
  890.  
  891.         while((ch >= 0) && (ch != '=') && (ch != ':') && (ch != '\t') && (ch != '\n') && (ch != '\r'))
  892.         {
  893.             key.append((char)ch);
  894.             ch = reader.read();
  895.         }
  896.  
  897.         while((ch >= 0) && (ch != '=') && (ch != ':'))
  898.         {
  899.             ch = reader.read();
  900.         }
  901.  
  902.         return (key.toString().trim());
  903.     }
  904.  
  905.     /**
  906.      * @param reader TODO
  907.      * @param lineReader TODO
  908.      * @param expectedTermination TODO
  909.      * @exception java.io.IOException
  910.      * @since VCafe 3.0
  911.      */
  912.     protected Object readValue(PushbackReader reader, LineNumberReader lineReader, int expectedTermination)
  913.         throws IOException
  914.     {
  915.         int    ch;
  916.         Object value;
  917.  
  918.         skipWhitespace(reader, lineReader);
  919.         ch = reader.read();
  920.  
  921.         switch(ch)
  922.         {
  923.             case '(' :
  924.             {
  925.                 value = readListValue(reader, lineReader, expectedTermination);
  926.                 break;
  927.             }
  928.             case '{' :
  929.             {
  930.                 value = readPropertiesValue(reader, lineReader, expectedTermination, -2);
  931.                 break;
  932.             }
  933.             default :
  934.             {
  935.                 reader.unread(ch);
  936.                 value = readStringValue(reader, lineReader, expectedTermination, -2);
  937.                 break;
  938.             }
  939.         }
  940.  
  941.         return (value);
  942.     }
  943.  
  944.     /**
  945.      * @param reader TODO
  946.      * @param lineReader TODO
  947.      * @param expectedTermination TODO
  948.      * @exception java.io.IOException
  949.      * @since VCafe 3.0
  950.      */
  951.     protected Object[] readListValue(PushbackReader reader, LineNumberReader lineReader, int expectedTermination)
  952.         throws IOException
  953.     {
  954.         int          ch;
  955.         Vector       list;
  956.         Object[]     objects;
  957.  
  958.         skipWhitespace(reader, lineReader);
  959.         ch   = reader.read();
  960.         list = new Vector(10);
  961.  
  962.         while((ch >= 0) && (ch != ')'))
  963.         {
  964.             switch(ch)
  965.             {
  966.                 case '{' :
  967.                 {
  968.                     list.addElement(readPropertiesValue(reader, lineReader, ',', ')'));
  969.                     break;
  970.                 }
  971.                 default:
  972.                 {
  973.                     reader.unread(ch);
  974.                     list.addElement(readStringValue(reader, lineReader, ',', ')'));
  975.                     break;
  976.                 }
  977.             }
  978.  
  979.             skipWhitespace(reader, lineReader);
  980.             ch = reader.read();
  981.         }
  982.  
  983.         skipWhitespace(reader, lineReader);
  984.         ch = reader.read();
  985.         
  986.         if (ch != expectedTermination)
  987.         {
  988.             throw new IOException("List value must be terminated with ')' and '" + (char)expectedTermination +
  989.                                   "' characters on line " + lineReader.getLineNumber());
  990.         }
  991.         
  992.         if(list.size() > 0)
  993.         {
  994.             if(list.elementAt(0) instanceof java.lang.String)
  995.             {
  996.                 objects = new String[list.size()];
  997.             }
  998.             else if(list.elementAt(0) instanceof Properties)
  999.             {
  1000.                 objects = new Properties[list.size()];
  1001.             }
  1002.             else
  1003.             {
  1004.                 throw new IOException("Internal error - unknown list element type");
  1005.             }
  1006.         }
  1007.         else
  1008.         {
  1009.             objects = new Object[0];
  1010.         }
  1011.  
  1012.         try
  1013.         {
  1014.             list.copyInto(objects);
  1015.         }
  1016.         catch(ArrayStoreException ex)
  1017.         {
  1018.             throw new IOException("Inconsistent list element types on line " + lineReader.getLineNumber());
  1019.         }
  1020.  
  1021.         return (objects);
  1022.     }
  1023.  
  1024.     /**
  1025.      * @param reader TODO
  1026.      * @param lineReader TODO
  1027.      * @param expectedTermination1 TODO
  1028.      * @param expectedTermination2 TODO
  1029.      * @exception java.io.IOException
  1030.      * @since VCafe 3.0
  1031.      */
  1032.     protected Properties readPropertiesValue(PushbackReader reader,
  1033.                                              LineNumberReader lineReader,
  1034.                                              int expectedTermination1,
  1035.                                              int expectedTermination2)
  1036.         throws IOException
  1037.     {
  1038.         Properties properties;
  1039.         int        ch;
  1040.  
  1041.         skipWhitespace(reader, lineReader);
  1042.         ch = reader.read();
  1043.         properties = new Properties();
  1044.  
  1045.         while((ch >= 0) && (ch != '}'))
  1046.         {
  1047.             String key;
  1048.             Object value;
  1049.  
  1050.             reader.unread(ch);
  1051.             key   = readKey(reader, lineReader);
  1052.             value = readValue(reader, lineReader, ';');
  1053.             skipWhitespace(reader, lineReader);
  1054.             properties.put(key, value);
  1055.             ch = reader.read();
  1056.         }
  1057.  
  1058.         skipWhitespace(reader, lineReader);
  1059.         ch = reader.read();
  1060.  
  1061.         if(ch == expectedTermination2)
  1062.         {
  1063.            reader.unread(ch);
  1064.         }
  1065.  
  1066.         if ((ch != expectedTermination1) && (ch != expectedTermination2))
  1067.         {
  1068.             throw new IOException("Properties value must be terminated with '}' and '" + (char)expectedTermination1
  1069.                                   + " or " + (char)expectedTermination2
  1070.                                   + "' characters on line " + lineReader.getLineNumber() + " got a " + (char)ch);
  1071.         }
  1072.  
  1073.         return (properties);
  1074.     }
  1075.  
  1076.     /**
  1077.      * @param reader TODO
  1078.      * @param lineReader TODO
  1079.      * @param expectedTermination1 TODO
  1080.      * @param expectedTermination2 TODO
  1081.      * @exception java.io.IOException
  1082.      * @since VCafe 3.0
  1083.      */
  1084.     protected String readStringValue(PushbackReader reader,
  1085.                                      LineNumberReader lineReader,
  1086.                                      int expectedTermination1,
  1087.                                      int expectedTermination2)
  1088.         throws IOException
  1089.     {
  1090.         int          ch;
  1091.         StringBuffer buf;
  1092.         boolean trailingQuoteExpected = false;
  1093.  
  1094.         buf = new StringBuffer();
  1095.         skipWhitespace(reader, lineReader);
  1096.         ch  = reader.read();
  1097.  
  1098.         if(ch == DBLQUOTE_CHAR)
  1099.         {
  1100.             trailingQuoteExpected = true;
  1101.             ch = reader.read();
  1102.         }
  1103.  
  1104.         if(trailingQuoteExpected)
  1105.         {
  1106.             while(ch >= 0)
  1107.             {
  1108.                 if (ch == BACKSLASH_CHAR)
  1109.                 {
  1110.                     // dblquotes and backslashes must be escaped in storage;
  1111.                     // strip off those escapes here
  1112.                     int nextch = reader.read();
  1113.  
  1114.                     if (nextch != DBLQUOTE_CHAR && nextch != BACKSLASH_CHAR)
  1115.                     {
  1116.                         buf.append((char)ch);
  1117.                     }
  1118.                     ch = nextch;
  1119.                 }
  1120.                 else if (ch == DBLQUOTE_CHAR)
  1121.                 {
  1122.                     skipWhitespace(reader, lineReader);
  1123.                     ch = reader.read();
  1124.  
  1125.                     if ((ch < 0) || (ch == expectedTermination1) || (ch == expectedTermination2))
  1126.                     {
  1127.                         break;
  1128.                     }
  1129.                     else
  1130.                     {
  1131.                         throw new IOException("Bad string value.  Expected " + (char)expectedTermination1
  1132.                                   + " or " + (char)expectedTermination2
  1133.                                   + ", but got a " + (char)ch + " on line " + lineReader.getLineNumber());
  1134.                     }
  1135.                 }
  1136.  
  1137.                 buf.append((char)ch);
  1138.                 ch = reader.read();
  1139.             }
  1140.         }
  1141.         else
  1142.         {
  1143.             while(((ch >= 0) && (ch != '\r') || (ch != '\n')) && (ch != expectedTermination1) && (ch != expectedTermination2))
  1144.             {
  1145.                 buf.append((char)ch);
  1146.                 ch = reader.read();
  1147.             }
  1148.         }
  1149.  
  1150.         if (ch == expectedTermination2)
  1151.         {
  1152.            reader.unread(ch);
  1153.         }
  1154.  
  1155.         return (buf.toString());
  1156.     }
  1157.  
  1158.     /**
  1159.      * @param name TODO
  1160.      * @exception java.io.IOException
  1161.      * @since VCafe 3.0
  1162.      */
  1163.     public synchronized void save(String name)
  1164.         throws IOException
  1165.     {
  1166.         if(name != null)
  1167.         {
  1168.             String  saveName;
  1169.             File    file;
  1170.             File    saveFile;
  1171.             boolean fileRenamed;
  1172.             
  1173.             saveName    = name + "~~save";
  1174.             file        = new File(name);
  1175.             saveFile    = new File(saveName);
  1176.             fileRenamed = false;
  1177.             
  1178.             if(file.exists()) 
  1179.             {
  1180.                 fileRenamed = file.renameTo(saveFile);
  1181.                 
  1182.                 if(!fileRenamed)
  1183.                 {
  1184.                     throw new IOException("Couldn't rename " + name + " to backup file " + saveName);
  1185.                 }
  1186.             }
  1187.  
  1188.             try 
  1189.             {
  1190.                 OutputStream os;
  1191.                 
  1192.                 os = null;
  1193.                 
  1194.                 try 
  1195.                 {
  1196.                     os = new FileOutputStream(name);
  1197.                     save(os);
  1198.                 } 
  1199.                 finally 
  1200.                 {
  1201.                     if(os != null)
  1202.                     {
  1203.                         os.close();
  1204.                     }
  1205.                 }
  1206.             }
  1207.             catch(IOException ex) 
  1208.             {
  1209.                 try 
  1210.                 {
  1211.                     if(fileRenamed)
  1212.                     {
  1213.                         saveFile.renameTo(file);  // put things back
  1214.                     }
  1215.                 } 
  1216.                 catch(SecurityException sex) 
  1217.                 {
  1218.                 }
  1219.                 
  1220.                 throw(ex);
  1221.             }
  1222.             
  1223.             if(fileRenamed && !saveFile.delete())
  1224.             {
  1225.                 throw new IOException("Couldn't delete backup file: " + saveName);
  1226.             }
  1227.         }
  1228.     }
  1229.  
  1230.     /**
  1231.      * @param stream TODO
  1232.      * @since VCafe 3.0
  1233.      */
  1234.     public synchronized void save(OutputStream stream)
  1235.     {
  1236.         if(extendedPropertiesFileFormat)
  1237.         {
  1238.             try 
  1239.             {
  1240.                 stream.write(toString().getBytes());
  1241.                 saved = true;
  1242.             } 
  1243.             catch(IOException ex) 
  1244.             {
  1245.                 // superclass doesn't declare this exception - bogus!
  1246.             }
  1247.         }
  1248.         else
  1249.         {
  1250.             super.save(stream, "");
  1251.             saved = true;
  1252.         }
  1253.     }
  1254.  
  1255.     /**
  1256.      * @param stream TODO
  1257.      * @param header TODO
  1258.      * @since VCafe 3.0
  1259.      */
  1260.     public void save(OutputStream stream, String header)
  1261.     {
  1262.         if(extendedPropertiesFileFormat)
  1263.         {
  1264.             save(stream);
  1265.         }
  1266.         else
  1267.         {
  1268.             super.save(stream, header);
  1269.         }
  1270.  
  1271.         saved = true;
  1272.     }
  1273.  
  1274.     /**
  1275.      * @since VCafe 3.0
  1276.      */
  1277.     public String toString()
  1278.     {
  1279.         return (toString("").append((char)'\n').toString());
  1280.     }
  1281.  
  1282.     /**
  1283.      * @param indentation TODO
  1284.      * @since VCafe 3.0
  1285.      */
  1286.     protected StringBuffer toString(String indentation)
  1287.     {
  1288.         StringBuffer buf;
  1289.  
  1290.         buf = new StringBuffer(indentation + "{" + EOL);
  1291.  
  1292.         for(Enumeration e = keys(); e.hasMoreElements();)
  1293.         {
  1294.             String key;                        
  1295.             
  1296.             key = (String)e.nextElement();
  1297.             
  1298.             if(key.indexOf('$') == -1)
  1299.             {
  1300.                 buf.append(toString(key, indentation));
  1301.             }
  1302.         }
  1303.  
  1304.         return (buf.append(indentation).append("}"));
  1305.     }
  1306.     
  1307.     protected StringBuffer toString(String key, String indentation)
  1308.     {
  1309.         String       innerIndentation;
  1310.         StringBuffer buf;
  1311.         Object       value;
  1312.         
  1313.         buf = new StringBuffer();
  1314.         
  1315.         if(get(key + "$Comment") != null)
  1316.         {
  1317.             buf.append(toString(key + "$Comment", indentation));
  1318.         }
  1319.         
  1320.         innerIndentation = indentation + INDENT;
  1321.         value            = get(key);
  1322.  
  1323.         buf.append(innerIndentation).append(key).append(" = ");
  1324.  
  1325.         if(value instanceof String)
  1326.         {
  1327.             if(key.indexOf('$') == -1)
  1328.             {
  1329.                 buf.append(DBLQUOTE_CHAR).append(fixup((String)value)).append(DBLQUOTE_CHAR).append(';').append(EOL);
  1330.             }
  1331.             else
  1332.             {
  1333.                 buf.append((String)value).append(EOL);
  1334.             }
  1335.         }
  1336.         else if(value instanceof String[])
  1337.         {
  1338.             String[] array;
  1339.  
  1340.             array = (String[])value;
  1341.  
  1342.             buf.append(EOL).append(innerIndentation).append("(").append(EOL);
  1343.  
  1344.             for(int i = 0; i < array.length; i++)
  1345.             {
  1346.                 buf.append(innerIndentation).append("\t\"").append(fixup(array[i])).append(DBLQUOTE_CHAR).append(',').append(EOL);
  1347.             }
  1348.  
  1349.             buf.append(innerIndentation).append(");").append(EOL);
  1350.         }
  1351.         else if(value instanceof Properties)
  1352.         {
  1353.             Properties subProp;
  1354.  
  1355.             subProp = (Properties)value;
  1356.             buf.append(EOL).append(subProp.toString(innerIndentation)).append(";").append(EOL);
  1357.         }
  1358.         else if(value instanceof Properties[])
  1359.         {
  1360.             Properties[] array;
  1361.  
  1362.             array = (Properties[])value;
  1363.  
  1364.             buf.append(EOL).append(innerIndentation).append("(").append(EOL);
  1365.  
  1366.             for(int i = 0; i < array.length; i++)
  1367.             {
  1368.                 buf.append(indentation).append(array[i].toString(innerIndentation + INDENT)).append(",").append(EOL);
  1369.             }
  1370.  
  1371.             buf.append(innerIndentation).append(");").append(EOL);
  1372.         }
  1373.         else  // shouldn't happen since we block "put(Object, Object)"
  1374.         {
  1375.             throw new IllegalArgumentException("Can't store a " + value.getClass() + " in a Properties");
  1376.         }
  1377.         
  1378.         return (buf);
  1379.     }
  1380.  
  1381.     /**
  1382.      * @param s TODO
  1383.      * @since VCafe 3.0
  1384.      */
  1385.     protected static String fixup(String s)
  1386.     {
  1387.         // If the list of characters to escape grows further,
  1388.         // it might be faster to make a single pass through the
  1389.         // string, character by character.  Depends on the data somewhat, too.
  1390.  
  1391.         // Escape any backslashes
  1392.         s = replace(s, BACKSLASH, BACKSLASH+BACKSLASH);
  1393.  
  1394.         // Escape any double-quote chars
  1395.         s = replace(s, DBLQUOTE,  BACKSLASH+DBLQUOTE );
  1396.  
  1397.         return s;
  1398.     }
  1399.  
  1400.     /**
  1401.      * @param s TODO
  1402.      * @param sOld TODO
  1403.      * @param sNew TODO
  1404.      * @since VCafe 3.0
  1405.      */
  1406.     protected static String replace(String s, String sOld, String sNew )
  1407.     {
  1408.         StringBuffer sb = new StringBuffer();
  1409.         int oldLen = sOld.length();
  1410.         int index = -1;
  1411.         int startIndex = 0;
  1412.         while ( (index = s.indexOf(sOld,startIndex)) != -1 ) {
  1413.             sb.append(s.substring(startIndex,index));
  1414.             sb.append(sNew);
  1415.             startIndex = index + oldLen;
  1416.         }
  1417.         sb.append(s.substring(startIndex));
  1418.         return sb.toString();
  1419.     }
  1420.  
  1421.     private static final char
  1422.         DBLQUOTE_CHAR  = '\"',
  1423.         BACKSLASH_CHAR = '\\';
  1424.  
  1425.     private static final String
  1426.         BACKSLASH = "\\",
  1427.         DBLQUOTE  = "\"",
  1428.         EOL       = "\r\n";
  1429. }