lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nightowl...@apache.org
Subject [05/12] lucenenet git commit: Lucene.Net.Support.DictionaryExtensions: Added Load and Store methods from Apache Harmony, so an IDictionary<string, string> can be used the same way the Properties class is used in Java (saving and loading the same format).
Date Wed, 02 Aug 2017 04:12:22 GMT
Lucene.Net.Support.DictionaryExtensions: Added Load and Store methods from Apache Harmony,
so an IDictionary<string, string> can be used the same way the Properties class is used
in Java (saving and loading the same format).


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/cd2d3514
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/cd2d3514
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/cd2d3514

Branch: refs/heads/master
Commit: cd2d3514e3fcda42ec1168667e91657f64aac5f6
Parents: dc67a55
Author: Shad Storhaug <shad@shadstorhaug.com>
Authored: Mon Jul 31 06:55:19 2017 +0700
Committer: Shad Storhaug <shad@shadstorhaug.com>
Committed: Wed Aug 2 09:53:09 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Tests/Lucene.Net.Tests.csproj    |   2 +
 .../Support/TestDictionaryExtensions.cs         | 411 +++++++++++++++++++
 .../Support/hyts_PropertiesTest.properties      |  29 ++
 src/Lucene.Net/Support/DictionaryExtensions.cs  | 409 +++++++++++++++++-
 4 files changed, 850 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
index 7631329..13282e1 100644
--- a/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
+++ b/src/Lucene.Net.Tests/Lucene.Net.Tests.csproj
@@ -118,6 +118,7 @@
     <None Include="Lucene.Net.snk" />
     <None Include="Lucene.Net.Tests.project.json" />
     <EmbeddedResource Include="Store\LUCENENET521.zip" />
+    <EmbeddedResource Include="Support\hyts_PropertiesTest.properties" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Lucene.Net.Analysis.Common\Lucene.Net.Analysis.Common.csproj">
@@ -522,6 +523,7 @@
     <Compile Include="Support\IO\TestReadOnlyHeapByteBuffer.cs" />
     <Compile Include="Support\IO\TestStreamTokenizer.cs" />
     <Compile Include="Support\SmallObject.cs" />
+    <Compile Include="Support\TestDictionaryExtensions.cs" />
     <Compile Include="Support\TestPriorityQueue.cs" />
     <Compile Include="Support\Threading\TestCloseableThreadLocal.cs" />
     <Compile Include="Support\TestCollections.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs b/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs
new file mode 100644
index 0000000..540d964
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/TestDictionaryExtensions.cs
@@ -0,0 +1,411 @@
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.Tests.Support
+{
+    public class TestDictionaryExtensions : LuceneTestCase
+    {
+        [Test]
+        public void Test_loadLSystem_IO_Stream_ArgumentNullException()
+        {
+            Dictionary<string, string> p = new Dictionary<string, string>();
+            try
+            {
+                p.Load((Stream)null);
+                fail("should throw NullPointerException");
+            }
+#pragma warning disable 168
+            catch (ArgumentNullException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+        }
+
+        /**
+     * @tests java.util.Properties#load(java.io.InputStream)
+     */
+        [Test]
+        public void Test_loadLSystem_IO_Stream()
+        {
+            Dictionary<string, string> prop = new Dictionary<string, string>();
+            using (Stream @is = new MemoryStream(writeProperties()))
+            {
+                prop.Load(@is);
+            }
+            assertEquals("Failed to load correct properties", "harmony.tests", prop.get("test.pkg"));
+            assertNull("Load failed to parse incorrectly", prop
+                    .get("commented.entry"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=".getBytes()));
+            assertEquals("Failed to add empty key", "", prop.get(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(" = ".getBytes()));
+            assertEquals("Failed to add empty key2", "", prop.get(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(" a= b".getBytes()));
+            assertEquals("Failed to ignore whitespace", "b", prop.get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(" a b".getBytes()));
+            assertEquals("Failed to interpret whitespace as =", "b", prop.get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("#comment\na=value"
+                    .getBytes("UTF-8")));
+            assertEquals("value", prop.get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("#\u008d\u00d2\na=\u008d\u00d3"
+                    .getBytes("ISO-8859-1")));
+            assertEquals("Failed to parse chars >= 0x80", "\u008d\u00d3", prop
+                    .get("a"));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream(
+                    "#properties file\r\nfred=1\r\n#last comment"
+                            .getBytes("ISO-8859-1")));
+            assertEquals("Failed to load when last line contains a comment", "1",
+                    prop.get("fred"));
+
+            // Regression tests for HARMONY-5414
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("a=\\u1234z".getBytes()));
+
+            prop = new Dictionary<string, string>();
+            try
+            {
+                prop.Load(new MemoryStream("a=\\u123".getBytes()));
+                fail("should throw IllegalArgumentException");
+            }
+#pragma warning disable 168
+            catch (ArgumentException e)
+#pragma warning restore 168
+            {
+                // Expected
+            }
+
+            prop = new Dictionary<string, string>();
+            try
+            {
+                prop.Load(new MemoryStream("a=\\u123z".getBytes()));
+                fail("should throw IllegalArgumentException");
+            }
+            catch (ArgumentException /*expected*/)
+            {
+                // Expected
+            }
+
+            prop = new Dictionary<string, string>();
+            Dictionary<string, string> expected = new Dictionary<string, string>();
+            expected.Put("a", "\u0000");
+            prop.Load(new MemoryStream("a=\\".getBytes()));
+            assertEquals("Failed to read trailing slash value", expected, prop);
+
+            prop = new Dictionary<string, string>();
+            expected = new Dictionary<string, string>();
+            expected.Put("a", "\u1234\u0000");
+            prop.Load(new MemoryStream("a=\\u1234\\".getBytes()));
+            assertEquals("Failed to read trailing slash value #2", expected, prop);
+
+            prop = new Dictionary<string, string>();
+            expected = new Dictionary<string, string>();
+            expected.Put("a", "q");
+            prop.Load(new MemoryStream("a=\\q".getBytes()));
+            assertEquals("Failed to read slash value #3", expected, prop);
+        }
+
+        /**
+         * @tests java.util.Properties#load(java.io.InputStream)
+         */
+        [Test]
+        public void Test_loadLSystem_IO_Stream_Special()
+        {
+            // Test for method void java.util.Properties.load(java.io.InputStream)
+            Dictionary<string, string> prop = null;
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=".getBytes()));
+            assertTrue("Failed to add empty key", prop.get("").equals(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=\r\n".getBytes()));
+            assertTrue("Failed to add empty key", prop.get("").equals(""));
+
+            prop = new Dictionary<string, string>();
+            prop.Load(new MemoryStream("=\n\r".getBytes()));
+            assertTrue("Failed to add empty key", prop.get("").equals(""));
+        }
+
+        /**
+         * @tests java.util.Properties#load(java.io.InputStream)
+         */
+        [Test]
+        public void Test_loadLSystem_IO_Stream_subtest0()
+        {
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            using (Stream input = GetType().getResourceAsStream("hyts_PropertiesTest.properties"))
+                props.Load(input);
+
+            assertEquals("1", "\n \t \f", props.getProperty(" \r"));
+            assertEquals("2", "a", props.getProperty("a"));
+            assertEquals("3", "bb as,dn   ", props.getProperty("b"));
+            assertEquals("4", ":: cu", props.getProperty("c\r \t\nu"));
+            assertEquals("5", "bu", props.getProperty("bu"));
+            assertEquals("6", "d\r\ne=e", props.getProperty("d"));
+            assertEquals("7", "fff", props.getProperty("f"));
+            assertEquals("8", "g", props.getProperty("g"));
+            assertEquals("9", "", props.getProperty("h h"));
+            assertEquals("10", "i=i", props.getProperty(" "));
+            assertEquals("11", "   j", props.getProperty("j"));
+            assertEquals("12", "   c", props.getProperty("space"));
+            assertEquals("13", "\\", props.getProperty("dblbackslash"));
+        }
+
+        /**
+     * @tests java.util.Properties#store(java.io.OutputStream, java.lang.String)
+     */
+        [Test]
+        public void Test_storeLSystem_IO_StreamLSystem_String()
+        {
+            Dictionary<string, string> myProps = new Dictionary<string, string>();
+            myProps.Put("Property A", " aye\\\f\t\n\r\b");
+            myProps.Put("Property B", "b ee#!=:");
+            myProps.Put("Property C", "see");
+
+            MemoryStream @out = new MemoryStream();
+            myProps.Store(@out, "A Header");
+            @out.Dispose();
+
+            MemoryStream @in = new MemoryStream(@out.ToArray());
+            Dictionary<string, string> myProps2 = new Dictionary<string, string>();
+            myProps2.Load(@in);
+            @in.Dispose();
+
+            using (var e = myProps.Keys.GetEnumerator())
+            {
+                String nextKey;
+                while (e.MoveNext())
+                {
+                    nextKey = e.Current;
+                    assertTrue("Stored property list not equal to original", myProps2
+                        .getProperty(nextKey).equals(myProps.getProperty(nextKey)));
+                }
+            }
+        }
+
+        /**
+        * if loading from single line like "hello" without "\n\r" neither "=", it
+        * should be same as loading from "hello="
+        */
+        [Test]
+        public void TestLoadSingleLine()
+        {
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            Stream sr = new MemoryStream("hello".getBytes());
+            props.Load(sr);
+            assertEquals(1, props.size());
+        }
+
+        private String comment1 = "comment1";
+
+        private String comment2 = "comment2";
+
+        private void validateOutput(String[] expectStrings, byte[] output)
+        {
+            MemoryStream bais = new MemoryStream(output);
+            TextReader br = new StreamReader(bais,
+                    Encoding.GetEncoding("ISO-8859-1"));
+            foreach (String expectString in expectStrings)
+            {
+                assertEquals(expectString, br.ReadLine());
+            }
+            br.ReadLine();
+            assertNull(br.ReadLine());
+            br.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario0()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario1()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario2()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '\n' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario3()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '\r' + comment2);
+            validateOutput(new String[] { "#comment1", "#", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario4()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario5()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario6()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario7()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario8()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '\n' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario9()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '\r' + '#' + comment2);
+            validateOutput(new String[] { "#comment1", "#", "#comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario10()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\r' + '\n' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+        [Test]
+        public void TestStore_scenario11()
+        {
+            MemoryStream baos = new MemoryStream();
+            Dictionary<string, string> props = new Dictionary<string, string>();
+            props.Store(baos, comment1 + '\n' + '\r' + '!' + comment2);
+            validateOutput(new String[] { "#comment1", "#", "!comment2" },
+                    baos.ToArray());
+            baos.Dispose();
+        }
+
+
+
+        protected byte[] writeProperties()
+        {
+            MemoryStream bout = new MemoryStream();
+            TextWriter ps = new StreamWriter(bout);
+            ps.WriteLine("#commented.entry=Bogus");
+            ps.WriteLine("test.pkg=harmony.tests");
+            ps.WriteLine("test.proj=Automated Tests");
+            ps.Dispose();
+            return bout.ToArray();
+        }
+
+    }
+
+    public static class Extensions
+    {
+        public static byte[] getBytes(this string input)
+        {
+            return Encoding.UTF8.GetBytes(input);
+        }
+
+        public static byte[] getBytes(this string input, string encoding)
+        {
+            return Encoding.GetEncoding(encoding).GetBytes(input);
+        }
+
+        public static string get(this IDictionary<string, string> dict, string key)
+        {
+            string result;
+            dict.TryGetValue(key, out result);
+            return result;
+        }
+
+        public static string getProperty(this IDictionary<string, string> dict, string
key)
+        {
+            string result;
+            dict.TryGetValue(key, out result);
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties b/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties
new file mode 100644
index 0000000..6c1b950
--- /dev/null
+++ b/src/Lucene.Net.Tests/Support/hyts_PropertiesTest.properties
@@ -0,0 +1,29 @@
+
+
+    
+    		
+   \ \r \n \t \f
+   
+            					
+! dshfjklahfjkldashgjl;as
+     #jdfagdfjagkdjfghksdajfd
+     
+!!properties
+
+a=a
+b bb as,dn   
+c\r\ \t\nu =:: cu
+bu= b\
+		u
+d=d\r\ne=e
+f   :f\
+f\
+			f
+g		g
+h\u0020h
+\   i=i
+j=\   j
+space=\   c
+
+dblbackslash=\\
+                        
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/cd2d3514/src/Lucene.Net/Support/DictionaryExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/DictionaryExtensions.cs b/src/Lucene.Net/Support/DictionaryExtensions.cs
index 18acd6a..0f616cb 100644
--- a/src/Lucene.Net/Support/DictionaryExtensions.cs
+++ b/src/Lucene.Net/Support/DictionaryExtensions.cs
@@ -1,4 +1,7 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
 
 namespace Lucene.Net.Support
 {
@@ -50,5 +53,409 @@ namespace Lucene.Net.Support
             dict[key] = value;
             return oldValue;
         }
+
+        private static readonly int NONE = 0, SLASH = 1, UNICODE = 2, CONTINUE = 3,
+            KEY_DONE = 4, IGNORE = 5;
+        private static string lineSeparator = Environment.NewLine;
+
+
+        // LUCENENET NOTE: Sourced from Apache Harmony:
+
+        /// <summary>
+        /// Loads properties from the specified <see cref="Stream"/>. The encoding
is
+        /// ISO8859-1. 
+        /// </summary>
+        /// <remarks>
+        /// The Properties file is interpreted according to the
+        /// following rules:
+        /// <list type="bullet">
+        ///     <item><description>
+        ///         Empty lines are ignored.
+        ///     </description></item>
+        ///     <item><description>
+        ///         Lines starting with either a "#" or a "!" are comment lines and are
+        ///         ignored.
+        ///     </description></item>
+        ///     <item><description>
+        ///         A backslash at the end of the line escapes the following newline
+        ///         character ("\r", "\n", "\r\n"). If there's a whitespace after the
+        ///         backslash it will just escape that whitespace instead of concatenating
+        ///         the lines. This does not apply to comment lines.
+        ///     </description></item>
+        ///     <item><description>
+        ///         A property line consists of the key, the space between the key and
+        ///         the value, and the value. The key goes up to the first whitespace, "="
or
+        ///         ":" that is not escaped. The space between the key and the value contains
+        ///         either one whitespace, one "=" or one ":" and any number of additional
+        ///         whitespaces before and after that character. The value starts with the
+        ///         first character after the space between the key and the value.
+        ///     </description></item>
+        ///     <item><description>
+        ///         Following escape sequences are recognized: "\ ", "\\", "\r", "\n",
+        ///         "\!", "\#", "\t", "\b", "\f", and "&#92;uXXXX" (unicode character).
+        ///     </description></item>
+        /// </list>
+        /// <para/>
+        /// This method is to mimic and interoperate with the Properties class in Java, which
+        /// is essentially a string dictionary that natively supports importing and exporting
to this format.
+        /// </remarks>
+        /// <param name="dict">This dictionary.</param>
+        /// <param name="input">The <see cref="Stream"/>.</param>
+        /// <exception cref="IOException">If error occurs during reading from the <see
cref="Stream"/>.</exception>
+        public static void Load(this IDictionary<string, string> dict, Stream input)
+        {
+            if (input == null)
+            {
+                throw new ArgumentNullException("input");
+            }
+            lock (dict)
+            {
+                int mode = NONE, unicode = 0, count = 0;
+                char nextChar;
+                char[] buf = new char[40];
+                int offset = 0, keyLength = -1, intVal;
+                bool firstChar = true;
+                Stream bis = input;
+
+                while (true)
+                {
+                    intVal = bis.ReadByte();
+                    if (intVal == -1)
+                    {
+                        // if mode is UNICODE but has less than 4 hex digits, should
+                        // throw an IllegalArgumentException
+                        // luni.08=Invalid Unicode sequence: expected format \\uxxxx
+                        if (mode == UNICODE && count < 4)
+                        {
+                            throw new ArgumentException("Invalid Unicode sequence: expected
format \\uxxxx"); //$NON-NLS-1$
+                        }
+                        // if mode is SLASH and no data is read, should append '\u0000'
+                        // to buf
+                        if (mode == SLASH)
+                        {
+                            buf[offset++] = '\u0000';
+                        }
+                        break;
+                    }
+                    nextChar = (char)(intVal & 0xff);
+
+                    if (offset == buf.Length)
+                    {
+                        char[] newBuf = new char[buf.Length * 2];
+                        System.Array.Copy(buf, 0, newBuf, 0, offset);
+                        buf = newBuf;
+                    }
+                    if (mode == UNICODE)
+                    {
+                        int digit = Character.Digit(nextChar, 16);
+                        if (digit >= 0)
+                        {
+                            unicode = (unicode << 4) + digit;
+                            if (++count < 4)
+                            {
+                                continue;
+                            }
+                        }
+                        else if (count <= 4)
+                        {
+                            // luni.09=Invalid Unicode sequence: illegal character
+                            throw new ArgumentException("Invalid Unicode sequence: illegal
character"); //$NON-NLS-1$
+                        }
+                        mode = NONE;
+                        buf[offset++] = (char)unicode;
+                        if (nextChar != '\n')
+                        {
+                            continue;
+                        }
+                    }
+                    if (mode == SLASH)
+                    {
+                        mode = NONE;
+                        switch (nextChar)
+                        {
+                            case '\r':
+                                mode = CONTINUE; // Look for a following \n
+                                continue;
+                            case '\n':
+                                mode = IGNORE; // Ignore whitespace on the next line
+                                continue;
+                            case 'b':
+                                nextChar = '\b';
+                                break;
+                            case 'f':
+                                nextChar = '\f';
+                                break;
+                            case 'n':
+                                nextChar = '\n';
+                                break;
+                            case 'r':
+                                nextChar = '\r';
+                                break;
+                            case 't':
+                                nextChar = '\t';
+                                break;
+                            case 'u':
+                                mode = UNICODE;
+                                unicode = count = 0;
+                                continue;
+                        }
+                    }
+                    else
+                    {
+                        switch (nextChar)
+                        {
+                            case '#':
+                            case '!':
+                                if (firstChar)
+                                {
+                                    while (true)
+                                    {
+                                        intVal = bis.ReadByte();
+                                        if (intVal == -1)
+                                        {
+                                            break;
+                                        }
+                                        // & 0xff not required
+                                        nextChar = (char)intVal;
+                                        if (nextChar == '\r' || nextChar == '\n')
+                                        {
+                                            break;
+                                        }
+                                    }
+                                    continue;
+                                }
+                                break;
+                            case '\n':
+                                if (mode == CONTINUE)
+                                { // Part of a \r\n sequence
+                                    mode = IGNORE; // Ignore whitespace on the next line
+                                    continue;
+                                }
+                                // fall into the next case
+                                mode = NONE;
+                                firstChar = true;
+                                if (offset > 0 || (offset == 0 && keyLength ==
0))
+                                {
+                                    if (keyLength == -1)
+                                    {
+                                        keyLength = offset;
+                                    }
+                                    string temp = new string(buf, 0, offset);
+                                    dict.Put(temp.Substring(0, keyLength), temp
+                                            .Substring(keyLength));
+                                }
+                                keyLength = -1;
+                                offset = 0;
+                                continue;
+                            case '\r':
+                                mode = NONE;
+                                firstChar = true;
+                                if (offset > 0 || (offset == 0 && keyLength ==
0))
+                                {
+                                    if (keyLength == -1)
+                                    {
+                                        keyLength = offset;
+                                    }
+                                    string temp = new string(buf, 0, offset);
+                                    dict.Put(temp.Substring(0, keyLength), temp
+                                            .Substring(keyLength));
+                                }
+                                keyLength = -1;
+                                offset = 0;
+                                continue;
+                            case '\\':
+                                if (mode == KEY_DONE)
+                                {
+                                    keyLength = offset;
+                                }
+                                mode = SLASH;
+                                continue;
+                            case ':':
+                            case '=':
+                                if (keyLength == -1)
+                                { // if parsing the key
+                                    mode = NONE;
+                                    keyLength = offset;
+                                    continue;
+                                }
+                                break;
+                        }
+                        if (nextChar < 256 && char.IsWhiteSpace(nextChar))
+                        {
+                            if (mode == CONTINUE)
+                            {
+                                mode = IGNORE;
+                            }
+                            // if key length == 0 or value length == 0
+                            if (offset == 0 || offset == keyLength || mode == IGNORE)
+                            {
+                                continue;
+                            }
+                            if (keyLength == -1)
+                            { // if parsing the key
+                                mode = KEY_DONE;
+                                continue;
+                            }
+                        }
+                        if (mode == IGNORE || mode == CONTINUE)
+                        {
+                            mode = NONE;
+                        }
+                    }
+                    firstChar = false;
+                    if (mode == KEY_DONE)
+                    {
+                        keyLength = offset;
+                        mode = NONE;
+                    }
+                    buf[offset++] = nextChar;
+                }
+                if (keyLength == -1 && offset > 0)
+                {
+                    keyLength = offset;
+                }
+                if (keyLength >= 0)
+                {
+                    string temp = new string(buf, 0, offset);
+                    dict.Put(temp.Substring(0, keyLength), temp.Substring(keyLength));
+                }
+            }
+        }
+
+        /// <summary>
+        /// Stores the mappings in this Properties to the specified
+        /// <see cref="Stream"/>, putting the specified comment at the beginning. The
+        /// output from this method is suitable for being read by the
+        /// <see cref="Load(IDictionary{string, string}, Stream)"/> method.
+        /// </summary>
+        /// <param name="dict">This dictionary.</param>
+        /// <param name="output">The output <see cref="Stream"/> to write to.</param>
+        /// <param name="comments">The comments to put at the beginning.</param>
+        /// <exception cref="IOException">If an error occurs during the write to the
<see cref="Stream"/>.</exception>
+        /// <exception cref="InvalidCastException">If the key or value of a mapping
is not a <see cref="string"/>.</exception>
+        public static void Store(this IDictionary<string, string> dict, Stream output,
string comments)
+        {
+            lock (dict)
+            {
+                StreamWriter writer = new StreamWriter(output, Encoding.GetEncoding("iso-8859-1"));
//$NON-NLS-1$
+                if (comments != null)
+                {
+                    WriteComments(writer, comments);
+                }
+                writer.Write('#');
+                writer.Write(new DateTime().ToString("yyyy-MM-dd"));
+                writer.Write(lineSeparator);
+
+                StringBuilder buffer = new StringBuilder(200);
+                foreach (var entry in dict)
+                {
+                    string key = entry.Key;
+                    DumpString(buffer, key, true);
+                    buffer.Append('=');
+                    DumpString(buffer, entry.Value, false);
+                    buffer.Append(lineSeparator);
+                    writer.Write(buffer.ToString());
+                    buffer.Length = 0;
+                }
+                writer.Flush();
+            }
+        }
+
+        private static void WriteComments(TextWriter writer, string comments)
+        {
+            writer.Write('#');
+            char[] chars = comments.ToCharArray();
+            for (int index = 0; index < chars.Length; index++)
+            {
+                if (chars[index] == '\r' || chars[index] == '\n')
+                {
+                    int indexPlusOne = index + 1;
+                    if (chars[index] == '\r' && indexPlusOne < chars.Length
+                            && chars[indexPlusOne] == '\n')
+                    {
+                        // "\r\n"
+                        continue;
+                    }
+                    writer.Write(lineSeparator);
+                    if (indexPlusOne < chars.Length
+                            && (chars[indexPlusOne] == '#' || chars[indexPlusOne]
== '!'))
+                    {
+                        // return char with either '#' or '!' afterward
+                        continue;
+                    }
+                    writer.Write('#');
+                }
+                else
+                {
+                    writer.Write(chars[index]);
+                }
+            }
+            writer.Write(lineSeparator);
+        }
+
+        private static void DumpString(StringBuilder buffer, string str, bool isKey)
+        {
+            int index = 0, length = str.Length;
+            if (!isKey && index < length && str[index] == ' ')
+            {
+                buffer.Append("\\ "); //$NON-NLS-1$
+                index++;
+            }
+
+            for (; index < length; index++)
+            {
+                char ch = str[index];
+                switch (ch)
+                {
+                    case '\t':
+                        buffer.Append("\\t"); //$NON-NLS-1$
+                        break;
+                    case '\n':
+                        buffer.Append("\\n"); //$NON-NLS-1$
+                        break;
+                    case '\f':
+                        buffer.Append("\\f"); //$NON-NLS-1$
+                        break;
+                    case '\r':
+                        buffer.Append("\\r"); //$NON-NLS-1$
+                        break;
+                    default:
+                        if ("\\#!=:".IndexOf(ch) >= 0 || (isKey && ch == ' '))
+                        {
+                            buffer.Append('\\');
+                        }
+                        if (ch >= ' ' && ch <= '~')
+                        {
+                            buffer.Append(ch);
+                        }
+                        else
+                        {
+                            buffer.Append(ToHexaDecimal(ch));
+                        }
+                        break;
+                }
+            }
+        }
+
+        private static char[] ToHexaDecimal(int ch)
+        {
+            char[] hexChars = { '\\', 'u', '0', '0', '0', '0' };
+            int hexChar, index = hexChars.Length, copyOfCh = ch;
+            do
+            {
+                hexChar = copyOfCh & 15;
+                if (hexChar > 9)
+                {
+                    hexChar = hexChar - 10 + 'A';
+                }
+                else
+                {
+                    hexChar += '0';
+                }
+                hexChars[--index] = (char)hexChar;
+                //} while ((copyOfCh >>>= 4) != 0);
+            } while ((copyOfCh = (int)((uint)copyOfCh >> 4)) != 0);
+            return hexChars;
+        }
     }
 }
\ No newline at end of file


Mime
View raw message