X-Git-Url: http://git.chise.org/gitweb/?p=m17n%2Fm17n-lib-cs.git;a=blobdiff_plain;f=MDatabase.cs;h=afefa61b97032b9f4913c47e2e943eddc912e95b;hp=a532b96286fc305434936ae6971841930d08d876;hb=1d437136777ceed08a6a1835feb6864219ebef86;hpb=87c251c72e14e0719942d3308079d84e72ea245f diff --git a/MDatabase.cs b/MDatabase.cs index a532b96..afefa61 100644 --- a/MDatabase.cs +++ b/MDatabase.cs @@ -2,6 +2,8 @@ using System; using System.Collections; using System.Collections.Generic; using System.IO; +using System.Xml; + using M17N; using M17N.Core; @@ -48,11 +50,13 @@ namespace M17N.Core int len = pattern.Length; int i; + M17n.DebugPrint ("Listing {0} in {1} ...", pattern, dirinfo); for (i = 0; i < len && pattern[i] != sep; i++); try { if (i == len) { FileInfo[] listing = dirinfo.GetFiles (pattern); + i = listing.Length; foreach (FileInfo elt in listing) files.Add (elt); } @@ -61,11 +65,14 @@ namespace M17N.Core string tail = pattern.Substring (i + 1); pattern = pattern.Substring (0, i); DirectoryInfo[] listing = dirinfo.GetDirectories (pattern); + + i = listing.Length; foreach (DirectoryInfo elt in listing) list (ref files, elt, tail); } } catch { } + M17n.DebugPrint (" found {0} files\n", i); } } @@ -137,7 +144,7 @@ namespace M17N.Core } } - public class MDatabase : IComparable + public partial class MDatabase : IComparable { /// Identifier of a MDatabase. public struct Tag : IEquatable @@ -270,9 +277,10 @@ namespace M17N.Core public MDatabaseInfo (MPlist plist) { - Format = MSymbol.plist; + Format = MSymbol.nil; if (plist.IsMText) { + Format = MSymbol.plist; Filename = plist.Text.ToString (); plist = plist.Next; } @@ -281,22 +289,22 @@ namespace M17N.Core MPlist p = plist.Plist; if (p.IsMText) - Filename = p.Text.ToString (); - p = p.Next; - if (! p.IsEmpty) { - if (p.IsSymbol) - Format = p.Symbol; + Filename = p.Text.ToString (); + p = p.Next; + } + if (p.IsSymbol) + { + Format = p.Symbol; p = p.Next; - if (! p.IsEmpty) - { - if (p.IsSymbol) - Schema = p.Symbol; - p = p.Next; - if (p.IsMText) - SchemaFile = p.Text.ToString (); - } } + if (p.IsSymbol) + { + Schema = p.Symbol; + p = p.Next; + } + if (p.IsMText) + SchemaFile = p.Text.ToString (); plist = plist.Next; } @@ -361,10 +369,13 @@ namespace M17N.Core private static DateTime LastUpdateTime = new DateTime (0); - private static readonly MSymbol Mversion = MSymbol.Of ("version"); - private static readonly MSymbol Mwildcard = MSymbol.Of ("*"); - private static readonly MSymbol Mchar_table = MSymbol.Of ("char-table"); - private static readonly MSymbol Mcharset = MSymbol.Of ("charset"); + private static readonly MSymbol Mversion = "version"; + private static readonly MSymbol Mwildcard = "*"; + private static readonly MSymbol Mchar_table = "char-table"; + private static readonly MSymbol Mcharset = "charset"; + private static readonly MSymbol Mxml = "xml"; + + private static TimeSpan CheckInterval = new TimeSpan (50000000); /// Type of database private enum MDBType @@ -401,11 +412,12 @@ namespace M17N.Core // current system, or the validation was failed. DISABLED, // The database is deleted by the modificaiton of mdb.dir, or - // is overwritten by a new explicit definition.. + // is overwritten by a new explicit definition. INVALID, }; public Tag tag; + public NameTable name_table = new NameTable (); private Loader loader; private object ExtraInfo; // Directory of the database file. @@ -417,10 +429,22 @@ namespace M17N.Core private MDBType DBType; private MDBStatus DBStatus; internal MDatabaseInfo Info; - // File in which the database contents is stored. + // File in which the database contents is stored. This is null + // when DBStatus is NOT_READY. internal FileInfo FileInfo; - // When the database file is checked (or validated). - internal DateTime CheckedTime; + // When the database file is loaded last. + internal DateTime LastLoaded = DateTime.Now; + + public enum LoadStatus + { + None, + InvalidLoadMethod, + NotAvailable, + NotReadable, + InvalidContents, + }; + + public LoadStatus LastLoadStatus = LoadStatus.None; static MDatabase () { @@ -441,19 +465,23 @@ namespace M17N.Core } DBDirs[2] = new MDatabaseDir (null); DBDirs[3] = new MDatabaseDir (Path.Combine (share_dir, "m17n")); - update_all (); + update_all (true); } public static string ApplicationDir { get { return (DBDirs[1].Dirname); } - set { DBDirs[2] = new MDatabaseDir (value); update_all (); } + set { DBDirs[2] = new MDatabaseDir (value); update_all (true); } } - private static bool update_all () + // Update all listing and directories. Return true iff some are + // really updated. + private static bool update_all (bool force) { - bool updated = false; + if (! force && DateTime.Now - LastUpdateTime < CheckInterval) + return false; + bool updated = false; for (int i = 1; i < 4; i++) if (DBDirs[i].Dirname != null) { @@ -469,13 +497,14 @@ namespace M17N.Core updated = true; } } - LastUpdateTime = DateTime.Now; + if (updated) + LastUpdateTime = DateTime.Now; return updated; } public static void Dump () { - update_all (); + update_all (false); Console.WriteLine ("[DBDirs]"); for (int i = 1; i < 4; i++) if (DBDirs[i].Dirname != null) @@ -497,7 +526,7 @@ namespace M17N.Core foreach (MDatabase mdb in kv.Value) Console.WriteLine (mdb); - Console.WriteLine ("[NDITCT]"); + Console.WriteLine ("[NDICT]"); foreach (KeyValuePair> kv in ndict) foreach (MDatabase mdb in kv.Value) Console.WriteLine (mdb); @@ -514,7 +543,6 @@ namespace M17N.Core for (int i = 0; i < mdbs.Count; i++) if (mdbs[i].ListIndex == mdb.ListIndex) { - mdbs[i].DBStatus = MDBStatus.INVALID; mdbs[i] = mdb; return; @@ -532,30 +560,45 @@ namespace M17N.Core private static void register (int list_idx, int dir_idx, Tag tag, MDatabaseInfo info) { + Dictionary> dict + = tag.HasWildcard ? wdict : ndict; List mdbs; MDatabase mdb; - if (ndict.TryGetValue (tag, out mdbs)) + if (dict.TryGetValue (tag, out mdbs)) for (int i = 0; i < mdbs.Count; i++) { mdb = mdbs[i]; - if (mdb.ListIndex == list_idx) + if (mdb.ListIndex == list_idx && mdb.DirIndex >= dir_idx) { + mdb.DirIndex = dir_idx; + if (dict == wdict) + { + mdb.DBType = MDBType.WILDCARD; + mdb.DBStatus = MDBStatus.NOT_READY; + } + else if (dir_idx == -1) + { + mdb.DBType = MDBType.AUTO; + mdb.DBStatus = MDBStatus.NOT_READY; + } + else + { + mdb.DBType = MDBType.MULTIPLE; + mdb.DBStatus = MDBStatus.READY; + } + mdb.Info = info; if (mdb.DBStatus == MDBStatus.INVALID) M17n.DebugPrint ("registering: {0}\n", mdb); else M17n.DebugPrint ("updating: {0}\n", mdb); - mdb.DBType = dir_idx == -1 ? MDBType.AUTO : MDBType.MULTIPLE; - mdb.DBStatus = MDBStatus.NOT_READY; - mdb.DirIndex = dir_idx; - mdb.Info = info; return; } } else { mdbs = new List (1); - ndict.Add (tag, mdbs); + dict.Add (tag, mdbs); } mdb = new MDatabase (list_idx, dir_idx, tag, info); M17n.DebugPrint ("registering: {0}\n", mdb); @@ -581,7 +624,10 @@ namespace M17N.Core if (Path.IsPathRooted (filename)) { DirIndex = 0; - DBStatus = MDBStatus.READY; + if (File.Exists (filename)) + DBStatus = MDBStatus.READY; + else + DBStatus = MDBStatus.INVALID; } else { @@ -599,14 +645,16 @@ namespace M17N.Core this.tag = tag; this.Info = info; DBType = this.tag.HasWildcard ? MDBType.WILDCARD : MDBType.AUTO; - if (this.tag[0] == Mchar_table || this.tag[0] == Mcharset) - Info.Format = this.tag[0]; + if (tag[0] == Mchar_table || tag[0] == Mcharset) + Info.Format = tag[0]; ListIndex = list_idx; DirIndex = dir_idx; if (Path.IsPathRooted (Info.Filename)) DBStatus = MDBStatus.READY; else DBStatus = MDBStatus.NOT_READY; + if (Info.Format == Mchar_table) + MCharProp.Define (tag[2], this); } public override String ToString () { @@ -622,6 +670,7 @@ namespace M17N.Core // DBDirs[list_idx]. private static void update_list (int list_idx) { + M17n.DebugPrint ("Updating list: {0}\n", list_idx); // At first disable all target databases. foreach (KeyValuePair> kv in wdict) foreach (MDatabase mdb in kv.Value) @@ -647,8 +696,7 @@ namespace M17N.Core MPlist plist = null; using (FileStream stream = File.OpenRead (dblist.FullName)) { - MStreamReader reader = new MStreamReader (stream); - plist = new MPlist (reader); + plist = new MPlist (stream); } if (plist == null) return; @@ -673,6 +721,7 @@ namespace M17N.Core // Update (or disable) databases in DBDirs[dir_idx]. private static void update_dir (int dir_idx) { + M17n.DebugPrint ("Updating dir: {0}\n", dir_idx); // Reset all databases in DBDirs[dir_idx]. foreach (KeyValuePair> kv in ndict) foreach (MDatabase mdb in kv.Value) @@ -689,39 +738,91 @@ namespace M17N.Core if (mdb.DBStatus == MDBStatus.READY) { M17n.DebugPrint ("re-expanding: {0}\n", mdb); - register_files (DBDirs[dir_idx].Dirname, mdb.ListIndex, - dir_idx, mdb.Info); + register_files (DBDirs[dir_idx].Dirname, dir_idx, mdb); + } + } + + private static bool parse_plist_header (FileInfo fileinfo, MDatabase mdb, + out Tag tag, out MDatabaseInfo info) + { + MPlist plist = null; + + tag = new Tag (MSymbol.nil); + info = null; + using (FileStream stream = fileinfo.OpenRead ()) + { + try { plist = new MPlist (stream, 1); } catch { } + } + if (plist == null || ! plist.IsPlist) + return false; + plist = plist.Plist; + tag = new Tag (ref plist); + if (tag.HasWildcard || ! tag.Match (mdb.tag)) + return false; + info = new MDatabaseInfo (plist); + return true; + } + + private static bool parse_xml_header (FileInfo fileinfo, MDatabase mdb, + out Tag tag, out MDatabaseInfo info) + { + tag = new Tag (MSymbol.nil); + info = null; + using (FileStream stream = fileinfo.OpenRead ()) + { + try { + MPlist plist = new MPlist (); + XmlTextReader reader = new XmlTextReader (stream); + + reader.WhitespaceHandling = WhitespaceHandling.None; + do { + reader.Read (); + } while (reader.NodeType != XmlNodeType.Element); + plist.Add (MSymbol.symbol, (MSymbol) reader.Name); + reader.Read (); + if (reader.NodeType == XmlNodeType.Element && reader.Name == "tags") + { + reader.Read (); + while (reader.NodeType == XmlNodeType.Element) + { + reader.Read (); + plist.Add (MSymbol.symbol, (MSymbol) reader.Value); + reader.Read (); + reader.Read (); + } + tag = new Tag (ref plist); + if (tag.HasWildcard || ! tag.Match (mdb.tag)) + return false; + info = new MDatabaseInfo (plist); + return true; } + } catch (Exception e) { + Console.WriteLine ("error {0}", e); + } + } + return false; } - private static void register_files (string dir, int list_idx, int dir_idx, - MDatabaseInfo base_info) + private static void register_files (string dir, int dir_idx, MDatabase mdb) { + int list_idx = mdb.ListIndex; List files = new List (); - MGlob.FileList (ref files, dir, base_info.Filename); + MGlob.FileList (ref files, dir, mdb.Info.Filename); foreach (FileInfo fileinfo in files) { - MPlist plist = null; - using (FileStream stream = fileinfo.OpenRead ()) - { - MStreamReader reader = new MStreamReader (stream); - plist = new MPlist (reader, 1); - } - if (plist != null && plist.IsPlist) - { - plist = plist.Plist; - Tag tag = new Tag (ref plist); + Tag tag; + MDatabaseInfo info; - if (! tag.HasWildcard && tag.Match (tag)) - { - MDatabaseInfo info = new MDatabaseInfo (plist); - info.Merge (base_info); - if (Path.IsPathRooted (base_info.Filename)) - info.Filename = fileinfo.FullName; - else - info.Filename = fileinfo.Name; - register (list_idx, dir_idx, tag, info); - } + if (mdb.Info.Format == MSymbol.plist + ? parse_plist_header (fileinfo, mdb, out tag, out info) + : parse_xml_header (fileinfo, mdb, out tag, out info)) + { + info.Merge (mdb.Info); + if (Path.IsPathRooted (mdb.Info.Filename)) + info.Filename = fileinfo.FullName; + else + info.Filename = fileinfo.Name; + register (list_idx, dir_idx, tag, info); } } } @@ -731,60 +832,66 @@ namespace M17N.Core M17n.DebugPrint ("expanding: {0}\n", this); if (DirIndex == 0) - register_files (null, ListIndex, DirIndex, Info); + register_files (null, DirIndex, this); else for (int i = 1; i < 4; i++) if (DBDirs[i].DirInfo != null) - register_files (DBDirs[i].DirInfo.FullName, ListIndex, i, Info); + register_files (DBDirs[i].DirInfo.FullName, i, this); DBStatus = MDBStatus.READY; } private static void maybe_expand_wildcard (Tag tag) { foreach (KeyValuePair> kv in wdict) - if (kv.Key.Match (tag)) - foreach (MDatabase mdb in kv.Value) - if (mdb.DBStatus == MDBStatus.NOT_READY) - mdb.expand_wildcard (); - } - - private bool update_status () - { - if (DBType == MDBType.UNKNOWN) - return true; - if (DBStatus == MDBStatus.READY - && FileInfo != null) { - FileInfo.Refresh (); - if (CheckedTime >= FileInfo.LastWriteTime) - return true; - - + M17n.DebugPrint ("expand check: {0}\n", kv.Key); + if (kv.Key.Match (tag)) { - FileInfo[] files - = DBDirs[DirIndex].DirInfo.GetFiles (Info.Filename); - if (files.Count > 0) - FileInfo = files[0]; + foreach (MDatabase mdb in kv.Value) + { + if (mdb.DBStatus == MDBStatus.NOT_READY) + mdb.expand_wildcard (); + } } - } - - if (DBDirs[DirIndex].DirInfo == null) - return false; - FileInfo[] files = DBDirs[DirIndex].DirInfo.GetFiles (Info.Filename); - if (files.Length == 0) - return false; - FileInfo = files[0]; - return true; } - private bool find_file () + // Update the status. Return true iff the database file is + // readable but changed. + + private bool update_status () { - if (DirIndex == 0) + if (DBType == MDBType.UNKNOWN) + return true; + update_all (false); + if (DBStatus == MDBStatus.INVALID) + return false; + if (DBStatus != MDBStatus.NOT_READY) { - - } - return true; + try { + FileInfo.Refresh (); + } catch { + DBStatus = MDBStatus.INVALID; + return false; + } + if (LastLoaded >= FileInfo.LastWriteTime) + return false; + DBStatus = MDBStatus.READY; + return true; + } + for (int i = 1; i < 4; i++) + if (DBDirs[i] != null && DBDirs[i].Dirname != null) + { + string filename = Path.Combine (DBDirs[i].Dirname, Info.Filename); + if (File.Exists (filename)) + { + FileInfo = new FileInfo (filename); + DirIndex = i; + DBStatus = MDBStatus.READY; + return true; + } + } + return false; } public static MDatabase Find (Tag tag) @@ -807,14 +914,18 @@ namespace M17N.Core break; } } - if (! update_all () && mdb != null) + if (! update_all (false) && mdb != null) return mdb; maybe_expand_wildcard (tag); if (! ndict.TryGetValue (tag, out mdbs)) return null; for (int i = 0; i < mdbs.Count; i++) - if ((mdb = mdbs[i]).check_file ()) - return mdb; + { + mdb = mdbs[i]; + mdb.update_status (); + if (mdb.DBStatus == MDBStatus.READY) + return mdb; + } return null; } @@ -822,7 +933,7 @@ namespace M17N.Core { List list = new List (); - update_all (); + update_all (false); maybe_expand_wildcard (tag); if (tag.HasWildcard) @@ -830,44 +941,266 @@ namespace M17N.Core foreach (KeyValuePair> kv in ndict) if (kv.Key.Match (tag)) foreach (MDatabase mdb in kv.Value) - if (mdb.check_file ()) - { - list.Add (mdb); - break; - } + { + mdb.update_status (); + if (mdb.DBStatus == MDBStatus.READY) + { + list.Add (mdb); + break; + } + } } else { List mdbs; if (ndict.TryGetValue (tag, out mdbs)) foreach (MDatabase mdb in mdbs) - if (mdb.check_file ()) - { - list.Add (mdb); - break; - } + { + mdb.update_status (); + if (mdb.DBStatus == MDBStatus.READY) + { + list.Add (mdb); + break; + } + } } return list; } + private FileStream get_stream () + { + if (loader != null + || (Info.Format != MSymbol.plist && Info.Format != Mxml)) + { + LastLoadStatus = LoadStatus.InvalidLoadMethod; + return null; + } + if (DBStatus != MDBStatus.READY) + { + LastLoadStatus = LoadStatus.NotAvailable; + return null; + } + + FileStream stream = null; + try { + stream = FileInfo.OpenRead (); + } catch { + LastLoadStatus = LoadStatus.NotReadable; + } + return stream; + } + public object Load () { - return (loader != null ? loader (tag, ExtraInfo) - : load (MSymbol.nil, MSymbol.nil)); + if (loader != null) + return loader (tag, ExtraInfo); + if (Info.Format == Mxml) + { + XmlDocument doc = new XmlDocument (name_table); + try { + XmlTextReader reader + = new XmlTextReader (FileInfo.FullName, name_table); + doc.Load (reader); + LastLoaded = DateTime.Now; + } catch (Exception e) { + Console.WriteLine (e); + LastLoadStatus = LoadStatus.InvalidContents; + } + return doc; + } + + FileStream stream = get_stream (); + if (stream == null) + return null; + MPlist plist = null; + try { + plist = new MPlist (stream); + LastLoaded = DateTime.Now; + } catch { + LastLoadStatus = LoadStatus.InvalidContents; + } finally { + stream.Dispose (); + } + return plist; } public object Load (MSymbol key, MSymbol stop) { - if (loader != null) + FileStream stream = get_stream (); + + if (stream == null) + return null; + if (Info.Format == Mxml) + { + XmlDocument doc = new XmlDocument (name_table); + XmlTextReader reader = new XmlTextReader (stream, name_table); + + reader.WhitespaceHandling = WhitespaceHandling.None; + try { + reader.Read (); + while (reader.NodeType != XmlNodeType.Element) + reader.Read (); + doc.LoadXml ("<" + reader.Name + ">"); + reader.Read (); + XmlNode node = doc.DocumentElement; + while (reader.NodeType == XmlNodeType.Element + ? reader.Name != stop.Name + : reader.NodeType != XmlNodeType.EndElement) + if (reader.NodeType == XmlNodeType.Element + && reader.Name == key.Name) + node = doc.DocumentElement.InsertAfter (doc.ReadNode (reader), + node); + } finally { + reader.Close (); + stream.Dispose (); + } + return doc; + } + + MPlist plist = null; + try { + plist = new MPlist (stream, key, stop); + LastLoaded = DateTime.Now; + } catch { + LastLoadStatus = LoadStatus.InvalidContents; + } finally { + stream.Dispose (); + } + return plist; + } + + public object Load (MSymbol stop) + { + FileStream stream = get_stream (); + + if (stream == null) return null; - return load (key, stop); + if (Info.Format == Mxml) + { + XmlDocument doc = new XmlDocument (name_table); + XmlTextReader reader = new XmlTextReader (stream, name_table); + + reader.WhitespaceHandling = WhitespaceHandling.None; + try { + reader.Read (); + while (reader.NodeType != XmlNodeType.Element) + reader.Read (); + doc.LoadXml ("<" + reader.Name + ">"); + reader.Read (); + XmlNode node = null; + while (reader.NodeType == XmlNodeType.Element + ? reader.Name != stop.Name + : reader.NodeType != XmlNodeType.EndElement) + if (reader.NodeType == XmlNodeType.Element) + node = doc.DocumentElement.InsertAfter (doc.ReadNode (reader), + node); + } catch (Exception e) { + Console.WriteLine (e); + } finally { + reader.Close (); + stream.Dispose (); + } + return doc; + } + + MPlist plist = null; + try { + plist = new MPlist (stream, stop); + LastLoaded = DateTime.Now; + } catch (Exception e) { + Console.WriteLine (e); + LastLoadStatus = LoadStatus.InvalidContents; + } finally { + stream.Dispose (); + } + return plist; } - private object load (MSymbol key, MSymbol stop) + public XmlNode Load (string id, params string[] nodes) { - return null; + FileStream stream = get_stream (); + if (stream == null) + return null; + if (Info.Format != Mxml) + throw new Exception ("Not an XML format"); + + XmlDocument doc = new XmlDocument (name_table); + XmlTextReader reader = new XmlTextReader (stream, name_table); + int len = nodes.Length; + + reader.WhitespaceHandling = WhitespaceHandling.None; + do { + reader.Read (); + } while (reader.NodeType != XmlNodeType.Element); + + if (reader.Name != nodes[0]) + return null; + + string ns = reader.GetAttribute ("xmlns"); + XmlNode top = doc.CreateNode (XmlNodeType.Element, nodes[0], ns); + XmlNode node = top; + + try { + int i; + + for (i = 1; i + 1 < len; i++) + { + if (! reader.ReadToDescendant (nodes[i])) + return null; + node = node.InsertAfter (doc.CreateNode (XmlNodeType.Element, + nodes[i], ns), null); + } + if (! reader.ReadToDescendant (nodes[i])) + return null; + XmlNode ref_node = null; + while (reader.NodeType != XmlNodeType.EndElement) + { + if (reader.NodeType == XmlNodeType.Element) + { + if (reader.Name == nodes[i] + && (id == null || id == reader.GetAttribute ("id"))) + ref_node = node.InsertAfter (doc.ReadNode (reader), ref_node); + else + reader.Skip (); + } + else + reader.Read (); + } + + } catch (Exception e) { + Console.WriteLine (e); + } finally { + reader.Close (); + stream.Dispose (); + } + return top; } + /// Return a list of currently available database + /// directory names. + public static string[] DirectoryList () + { + List dirs = new List (); + + for (int i = 1; i < 4; i++) + if (DBDirs[i].Dirname != null) + dirs.Add (DBDirs[i].Dirname); + return dirs.ToArray (); + } + + public MSymbol Format { get { return Info.Format; } } + + public static bool Changed (DateTime time) + { + update_all (false); + return (time < LastUpdateTime); + } + + public bool NeedReload () + { + return update_status (); + } + // For IComparable public int CompareTo (MDatabase other) { @@ -876,4 +1209,4 @@ namespace M17N.Core : ListIndex - other.ListIndex); } } -} \ No newline at end of file +}