예제 #1
0
 /// <summary>
 ///   Compiles the specified files and generates the output resource file.
 /// </summary>
 /// <param name="fileList">The enumeration of <see cref="FileInfo" /> objects.</param>
 /// <param name="output">The destination <see cref="DirectoryInfo" /> object.</param>
 /// <returns></returns>
 internal int Compile(IEnumerable<FileInfo> fileList, ResourceOutput output)
 {
     var database = new TzdbDatabase();
     ParseAllFiles(fileList, database);
     GenerateDateTimeZones(database, output);
     LogCounts(database);
     return 0;
 }
 public void Parse_twoZonesTwoRule()
 {
     const string text =
         "# A comment\n" + "Rule US 1987 2006 - Apr Sun>=1 2:00 1:00 D\n" + "Rule US 2007 max  - Mar Sun>=8 2:00 1:00 D\n" +
         "Zone PST 2:00 US P%sT # An end of line comment\n" + "         3:00 -  P%sT\n" + "         4:00 -  P%sT\n" +
         "Zone EST 2:00 US E%sT # An end of line comment\n" + "         3:00 -  E%sT\n";
     var reader = new StringReader(text);
     var database = new TzdbDatabase();
     Parser.Parse(reader, database);
     ValidateCounts(database, 1, 2, 0);
     Assert.AreEqual(2, database.Zones[0].Count, "Zones in set " + database.Zones[0].Name);
     Assert.AreEqual(3, database.Zones[1].Count, "Zones in set " + database.Zones[1].Name);
 }
 public void Parse_twoZones()
 {
     const string text =
         "# A comment\n" + "Zone PST 2:00 US P%sT # An end of line comment\n" + "         3:00 -  P%sT\n" + "         4:00 -  P%sT\n" +
         "Zone EST 2:00 US E%sT # An end of line comment\n" + "         3:00 -  E%sT\n";
     var reader = new StringReader(text);
     var database = new TzdbDatabase();
     Parser.Parse(reader, database);
     ValidateCounts(database, 0, 2, 0);
     Assert.AreEqual(2, database.Zones[0].Count, "Zones in set " + database.Zones[0].Name);
     Assert.AreEqual(3, database.Zones[1].Count, "Zones in set " + database.Zones[1].Name);
 }
 public void Parse_twoLinks()
 {
     const string text = "# First line must be a comment\n" + "Link from to\n" + "Link target source\n";
     var reader = new StringReader(text);
     var database = new TzdbDatabase();
     Parser.Parse(reader, database);
     ValidateCounts(database, 0, 0, 2);
 }
 public void Parse_twoLines()
 {
     const string text = "# A comment\n" + "Zone PST 2:00 US P%sT\n";
     var reader = new StringReader(text);
     var database = new TzdbDatabase();
     Parser.Parse(reader, database);
     ValidateCounts(database, 0, 1, 0);
     Assert.AreEqual(1, database.Zones[0].Count, "Zones in set");
 }
 public void Parse_emptyStream()
 {
     var reader = new StringReader(string.Empty);
     var database = new TzdbDatabase();
     Parser.Parse(reader, database);
     ValidateCounts(database, 0, 0, 0);
 }
예제 #7
0
 /// <summary>
 ///   Writes various informational counts to the log.
 /// </summary>
 /// <param name="database">The database to query for the counts.</param>
 private void LogCounts(TzdbDatabase database)
 {
     log.Info("=======================================");
     log.Info("Rule sets: {0:D}", database.Rules.Count);
     log.Info("Zones:     {0:D}", database.Zones.Count);
     log.Info("Aliases:   {0:D}", database.Aliases.Count);
     log.Info("=======================================");
 }
예제 #8
0
 /// <summary>
 ///   Parses the TZDB time zone info file from the given reader and merges its information
 ///   with the given database. The reader is not closed or disposed.
 /// </summary>
 /// <param name="reader">The reader to read.</param>
 /// <param name="database">The database to fill.</param>
 public void Parse(TextReader reader, TzdbDatabase database)
 {
     Log.LineNumber = 1;
     try
     {
         for (var line = reader.ReadLine(); line != null; line = reader.ReadLine())
         {
             try
             {
                 if (Log.LineNumber == 1)
                 {
                     if (!line.StartsWith("# ", StringComparison.Ordinal))
                     {
                         return;
                     }
                 }
                 else
                 {
                     ParseLine(line, database);
                 }
             }
             catch (ParseException)
             {
                 // Nothing to do
             }
             catch (Exception e)
             {
                 Log.Error("Exception {0} occurred: {1}", e.GetType().Name, e.Message);
                 throw;
             }
             Log.LineNumber++;
         }
     }
     finally
     {
         Log.LineNumber = -1;
     }
 }
 public void ParseLine_link()
 {
     const string line = "Link from to";
     var database = new TzdbDatabase();
     Parser.ParseLine(line, database);
     ValidateCounts(database, 0, 0, 1);
 }
예제 #10
0
 public void ParseLine_emptyString()
 {
     var database = new TzdbDatabase();
     Parser.ParseLine(string.Empty, database);
     ValidateCounts(database, 0, 0, 0);
 }
예제 #11
0
 public void ParseLine_commentWithLeadingWhitespace()
 {
     const string line = "   # Comment";
     var database = new TzdbDatabase();
     Parser.ParseLine(line, database);
     ValidateCounts(database, 0, 0, 0);
 }
예제 #12
0
 /// <summary>
 ///   Parses the file defined by the given <see cref="FileInfo" />.
 /// </summary>
 /// <remarks>
 ///   Currently this compiler only handles files in the Olson (TZDB) zone info format.
 /// </remarks>
 /// <param name="file">The file to parse.</param>
 /// <param name="database">The <see cref="TzdbDatabase" /> where the parsed data is placed.</param>
 internal void ParseFile(FileInfo file, TzdbDatabase database)
 {
     log.FileName = file.Name;
     try
     {
         using (FileStream stream = file.OpenRead())
         {
             tzdbParser.Parse(stream, database);
         }
     }
     finally
     {
         log.FileName = null;
     }
 }
예제 #13
0
 /// <summary>
 ///   Parses all of the given files.
 /// </summary>
 /// <param name="files">The <see cref="IEnumerable{T}" /> of <see cref="FileInfo" /> objects.</param>
 /// <param name="database">The <see cref="TzdbDatabase" /> where the parsed data is placed.</param>
 private void ParseAllFiles(IEnumerable<FileInfo> files, TzdbDatabase database)
 {
     foreach (var file in files)
     {
         log.Info("Parsing file {0} . . .", file.Name);
         ParseFile(file, database);
     }
 }
예제 #14
0
 private static void ValidateCounts(TzdbDatabase database, int ruleSets, int zoneLists, int links)
 {
     Assert.AreEqual(ruleSets, database.Rules.Count, "Rules");
     Assert.AreEqual(zoneLists, database.Zones.Count, "Zones");
     Assert.AreEqual(links, database.Aliases.Count, "Links");
 }
예제 #15
0
 public void ParseLine_whiteSpace()
 {
     const string line = "    \t\t\n";
     var database = new TzdbDatabase();
     Parser.ParseLine(line, database);
     ValidateCounts(database, 0, 0, 0);
 }
예제 #16
0
 /// <summary>
 ///   Parses the TZDB time zone info file from the given stream and merges its information
 ///   with the given database. The stream is not closed or disposed.
 /// </summary>
 /// <param name="input">The stream input to parse.</param>
 /// <param name="database">The database to fill.</param>
 public void Parse(Stream input, TzdbDatabase database)
 {
     Parse(new StreamReader(input, true), database);
 }
예제 #17
0
        public void ParseLine_zonePlus()
        {
            const string line = "Zone PST 2:00 US P%sT";
            var database = new TzdbDatabase();
            Parser.ParseLine(line, database);

            const string line2 = "  3:00 US P%sT";
            Parser.ParseLine(line2, database);
            ValidateCounts(database, 0, 1, 0);
            Assert.AreEqual(2, database.Zones[0].Count, "Zones in set");
        }
예제 #18
0
 /// <summary>
 ///   Parses a single line of an TZDB zone info file.
 /// </summary>
 /// <remarks>
 ///   <para>
 ///     TZDB files have a simple line based structure. Each line defines one item. Comments
 ///     start with a hash or pound sign (#) and continue to the end of the line. Blank lines are
 ///     ignored. Of the remaining there are four line types which are determined by the first
 ///     keyword on the line.
 ///   </para>
 ///   <para>
 ///     A line beginning with the keyword <c>Link</c> defines an alias between one time zone and
 ///     another. Both time zones use the same definition but have different names.
 ///   </para>
 ///   <para>
 ///     A line beginning with the keyword <c>Rule</c> defines a daylight savings time
 ///     calculation rule.
 ///   </para>
 ///   <para>
 ///     A line beginning with the keyword <c>Zone</c> defines a time zone.
 ///   </para>
 ///   <para>
 ///     A line beginning with leading whitespace (an empty keyword) defines another part of the
 ///     preceeding time zone. As many lines as necessary to define the time zone can be listed,
 ///     but they must all be together and only the first line can have a name.
 ///   </para>
 /// </remarks>
 /// <param name="line">The line to parse.</param>
 /// <param name="database">The database to fill.</param>
 internal void ParseLine(string line, TzdbDatabase database)
 {
     int index = line.IndexOf("#", StringComparison.Ordinal);
     if (index == 0)
     {
         return;
     }
     if (index > 0)
     {
         line = line.Substring(0, index - 1);
     }
     line = line.TrimEnd();
     if (line.Length == 0)
     {
         return;
     }
     var tokens = Tokens.Tokenize(line);
     var keyword = NextString(tokens, "Keyword");
     switch (keyword)
     {
         case KeywordRule:
             database.AddRule(ParseRule(tokens));
             break;
         case KeywordLink:
             database.AddAlias(ParseLink(tokens));
             break;
         case KeywordZone:
             var name = NextString(tokens, "GetName");
             var namedZone = ParseZone(name, tokens);
             database.AddZone(namedZone);
             break;
         default:
             if (string.IsNullOrEmpty(keyword))
             {
                 var zone = ParseZone(string.Empty, tokens);
                 database.AddZone(zone);
             }
             else
             {
                 Error("Unexpected zone database keyword: {0}", keyword);
             }
             break;
     }
 }
예제 #19
0
        /// <summary>
        ///   Generates the date time zones from the given parsed time zone information object.
        /// </summary>
        /// <remarks>
        ///   <para>
        ///     First we go through the list of time zones and generate an <see cref="DateTimeZone" />
        ///     object for each one. We create a mapping between the time zone name and itself (for
        ///     writing out later). Then we write out the time zone as a resource to the current writer.
        ///   </para>
        ///   <para>
        ///     Second we go through all of the alias mappings and find the actual time zone that they
        ///     map to. we do this by redirecting through aliases until there are no more aliases. This
        ///     allows for on alias to refer to another. We add the alias mapping to the time zone
        ///     mapping created in the first step. When done, we write out the entire mapping as a
        ///     resource. The keys of the mapping can be used as the list of valid time zone ids
        ///     supported by this resource file.
        ///   </para>
        /// </remarks>
        /// <param name="database">The database of parsed zone info records.</param>
        /// <param name="output">The output file <see cref="ResourceOutput" />.</param>
        private static void GenerateDateTimeZones(TzdbDatabase database, ResourceOutput output)
        {
            var timeZoneMap = new Dictionary<string, string>();
            foreach (var zoneList in database.Zones)
            {
                var timeZone = CreateTimeZone(zoneList, database.Rules);
                timeZoneMap.Add(timeZone.Id, timeZone.Id);
                output.WriteTimeZone(timeZone.Id, timeZone);
            }

            foreach (var key in database.Aliases.Keys)
            {
                var value = database.Aliases[key];
                while (database.Aliases.ContainsKey(value))
                {
                    value = database.Aliases[value];
                }
                timeZoneMap.Add(key, value);
            }

            output.WriteDictionary(DateTimeZoneResourceProvider.IdMapKey, timeZoneMap);
        }