[Mono-docs-list] Monodoc HelpSource refactor patch

Peter Williams peter@newton.cx
Sat, 28 Aug 2004 15:30:27 -0400


--=-8EJ1AW5KRODhV30cSSOg
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

Hi all,

The attached patch refactors the HelpSource class a bit. It adds a new
parent class called HelpStore, which deals with the I/O tasks of the
class. Then the HelpSource implementation adds the tree loading and
saving. The patch doesn't change any functionality, but it adds
encapsulation of the IO routines and helps reduce the size of
provider.cs, which I think is too long at the moment.

Comments?

Peter

-- 
Peter Williams                          peter@newton.cx

"[Ninjas] are cool; and by cool, I mean totally sweet."
                              -- REAL Ultimate Power

--=-8EJ1AW5KRODhV30cSSOg
Content-Disposition: inline; filename=helpstore.diff
Content-Type: text/x-patch; name=helpstore.diff; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

Index: ChangeLog
===================================================================
RCS file: /cvs/public/monodoc/browser/ChangeLog,v
retrieving revision 1.137
diff -u -r1.137 ChangeLog
--- ChangeLog	25 Aug 2004 16:08:56 -0000	1.137
+++ ChangeLog	28 Aug 2004 18:21:32 -0000
@@ -1,3 +1,16 @@
+2004-08-28  Peter Williams  <peter@newton.cx>
+
+	* HelpStore.cs (HelpStore): Break out the IO routines of HelpSource into
+	a new class, to better separate the IO and Help dimensions of
+	the class. 
+	
+	* provider.cs (HelpSource): Refactor to be a subclass of
+	HelpStore.
+	(Tree): Change to work with a generic Stream, not
+	filename/FileStream, to accomodate the split.
+	
+	* Makefile.am: Add HelpStore.cs into the build.
+	
 2004-08-25  Peter Williams  <peter@newton.cx>
 
 	* provider.cs: Allow a .source file to add nodes to the tree
Index: provider.cs
===================================================================
RCS file: /cvs/public/monodoc/browser/provider.cs,v
retrieving revision 1.65
diff -u -r1.65 provider.cs
--- provider.cs	25 Aug 2004 16:08:56 -0000	1.65
+++ provider.cs	28 Aug 2004 18:21:32 -0000
@@ -19,7 +19,6 @@
 using System.Configuration;
 using System.Xml;
 using System.Xml.XPath;
-using ICSharpCode.SharpZipLib.Zip;
 
 /// <summary>
 ///    This tree is populated by the documentation providers, or populated
@@ -35,21 +34,17 @@
 	/// </summary>
 	public readonly HelpSource HelpSource;
 	
-	internal FileStream InputStream;
+	internal Stream InputStream;
 	internal BinaryReader InputReader;
 
 	/// <summary>
 	///   Load from file constructor
 	/// </summary>
-	public Tree (HelpSource hs, string filename) : base (null, null)
+	public Tree (HelpSource hs, Stream input) : base (null, null)
 	{
 		Encoding utf8 = new UTF8Encoding (false, true);
 
-		if (!File.Exists (filename)){
-			throw new FileNotFoundException ();
-		}
-		
-		InputStream = File.OpenRead (filename);
+		InputStream = input;
 		InputReader = new BinaryReader (InputStream, utf8);
 		byte [] sig = InputReader.ReadBytes (4);
 		
@@ -81,21 +76,20 @@
 	/// <summary>
 	///    Saves the tree into the specified file using the help file format.
 	/// </summary>
-	public void Save (string file)
+	public void Save (Stream output)
 	{
 		Encoding utf8 = new UTF8Encoding (false, true);
-		using (FileStream output = File.OpenWrite (file)){
-			// Skip over the pointer to the first node.
-			output.Position = 8;
+
+		// Skip over the pointer to the first node.
+		output.Position = 8;
 			
-			using (BinaryWriter writer = new BinaryWriter (output, utf8)){
-				// Recursively dump
-				Dump (output, writer);
-
-				output.Position = 0;
-				writer.Write (new byte [] { (byte) 'M', (byte) 'o', (byte) 'H', (byte) 'P' });
-				writer.Write (position);
-			}
+		using (BinaryWriter writer = new BinaryWriter (output, utf8)){
+			// Recursively dump
+			Dump (output, writer);
+			
+			output.Position = 0;
+			writer.Write (new byte [] { (byte) 'M', (byte) 'o', (byte) 'H', (byte) 'P' });
+			writer.Write (position);
 		}
 	}
 
@@ -287,7 +281,7 @@
                         return ret;
 	}
 
-	internal void Dump (FileStream output, BinaryWriter writer)
+	internal void Dump (Stream output, BinaryWriter writer)
 	{
 		if (nodes != null){
 			foreach (Node child in nodes){
@@ -360,42 +354,27 @@
 // The HelpSource class keeps track of the archived data, and its
 // tree
 //
-public class HelpSource {
+public class HelpSource : HelpStore {
 	static int id;
 
 	//
 	// The unique ID for this HelpSource.
 	//
 	int source_id;
-	DateTime zipFileWriteTime;
 	string name;
 
-	public HelpSource (string base_filename, bool create)
+	public HelpSource (string base_filename, bool create) : base (base_filename, create)
 	{
 		this.name = Path.GetFileName (base_filename);
-		tree_filename = base_filename + ".tree";
-		zip_filename = base_filename + ".zip";
 
 		if (create)
-			SetupForOutput ();
+			Tree = new Tree (this, "", "");
 		else 
-			Tree = new Tree (this, tree_filename);
+			Tree = new Tree (this, GetTreeStream ());
 
 		source_id = id++;
-		try {
-			FileInfo fi = new FileInfo (zip_filename);
-			zipFileWriteTime = fi.LastWriteTime;
-		} catch {
-			zipFileWriteTime = DateTime.Now;
-		}
 	}
 
-	public DateTime ZipFileWriteTime {
-		get {
-			return zipFileWriteTime;
-		}
-	}
-	
 	public int SourceID {
 		get {
 			return source_id;
@@ -408,66 +387,30 @@
 		}
 	}
 	
-	ZipFile zip_file;
-	
-	/// <summary>
-	///   Returns a stream from the packaged help source archive
-	/// </summary>
-	public Stream GetHelpStream (string id)
-	{
-		if (zip_file == null)
-			zip_file = new ZipFile (zip_filename);
-
-		ZipEntry entry = zip_file.GetEntry (id);
-		if (entry != null)
-			return zip_file.GetInputStream (entry);
-		return null;
-	}
-	
-	public string GetRealPath (string file)
-	{
-		if (zip_file == null)
-			zip_file = new ZipFile (zip_filename);
-
-		ZipEntry entry = zip_file.GetEntry (file);
-		if (entry != null && entry.ExtraData != null)
-			return ConvertToString (entry.ExtraData);
-		return null;
-	}
-	
 	public XmlReader GetHelpXml (string id)
 	{
-		if (zip_file == null)
-			zip_file = new ZipFile (zip_filename);
+		Stream s = GetHelpStream (id);
+		if (s == null)
+			return null;
 
-		ZipEntry entry = zip_file.GetEntry (id);
-		if (entry != null) {
-			Stream s = zip_file.GetInputStream (entry);
-			string url = "monodoc://" + SourceID + "@" + System.Web.HttpUtility.UrlEncode (id) + "@";
-			return new XmlTextReader (url, s);
-		}
-		return null;
+		string url = "monodoc://" + SourceID + "@" + System.Web.HttpUtility.UrlEncode (id) + "@";
+		return new XmlTextReader (url, s);
 	}
 	
 	public XmlDocument GetHelpXmlWithChanges (string id)
 	{
-		if (zip_file == null)
-			zip_file = new ZipFile (zip_filename);
+		XmlReader r = GetHelpXml (id);
+		if (r == null)
+			return null;
 
-		ZipEntry entry = zip_file.GetEntry (id);
-		if (entry != null) {
-			Stream s = zip_file.GetInputStream (entry);
-			string url = "monodoc://" + SourceID + "@" + System.Web.HttpUtility.UrlEncode (id) + "@";
-			XmlReader r = new XmlTextReader (url, s);
-			XmlDocument ret = new XmlDocument ();
-			ret.Load (r);
+		XmlDocument ret = new XmlDocument ();
+		ret.Load (r);
 			
-			if (entry.ExtraData != null)
-				EditingUtils.AccountForChanges (ret, Name, ConvertToString (entry.ExtraData));
+		string real = GetRealPath (id);
+		if (real != null)
+			EditingUtils.AccountForChanges (ret, Name, real);
 			
-			return ret;
-		}
-		return null;	
+		return ret;
 	}
 	
 	/// <summary>
@@ -486,109 +429,20 @@
 		return EditingUtils.FormatEditUri (n.BaseURI, GetNodeXPath (n));
 	}
 	
-	static string ConvertToString (byte[] data)
-	{
-		return Encoding.UTF8.GetString(data);
-	}
-	
-	static byte[] ConvertToArray (string str)
-	{
-		return Encoding.UTF8.GetBytes(str);
-	}
-
 	/// <summary>
 	///   The tree that is being populated
 	/// </summary>
 	public Tree Tree;
 
-	// Base filename used by this HelpSource.
-	string tree_filename, zip_filename;
-
-	// Used for ziping. 
-	const int buffer_size = 65536;
-	ZipOutputStream zip_output;
-	byte [] buffer;
-	
-	HelpSource (string base_filename)
-	{
-	}
-		
-	void SetupForOutput ()
-	{
-		Tree = new Tree (this, "", "");
-
-		FileStream stream = File.Create (zip_filename);
-		
-		zip_output = new ZipOutputStream (stream);
-		zip_output.SetLevel (9);
-
-		buffer = new byte [buffer_size];
-	}		
-
 	/// <summary>
 	///   Saves the tree and the archive
 	/// </summary>
-	public void Save ()
-	{
-		Tree.Save (tree_filename);
-		zip_output.Finish ();
-		zip_output.Close ();
-	}
-
-	int code;
-
-	string GetNewCode ()
-	{
-		return String.Format ("{0}", code++);
-	}
-
-	/// <summary>
-	///   Providers call this to store a file they will need, and the return value
-	///   is the name that was assigned to it
-	/// </summary>
-	public string PackFile (string file)
+	public override void Save ()
 	{
-		string entry_name = GetNewCode ();
-		return PackFile (file, entry_name);
+		Tree.Save (GetTreeStream ());
+		base.Save ();
 	}
 
-	public string PackFile (string file, string entry_name)
-	{
-		using (FileStream input = File.OpenRead (file)) {
-			PackStream (input, entry_name, file);
-		}
-
-		return entry_name;
-	}
-	
-	public void PackStream (Stream s, string entry_name)
-	{
-		PackStream (s, entry_name, null);
-	}
-	
-	void PackStream (Stream s, string entry_name, string realPath)
-	{
-		ZipEntry entry = new ZipEntry (entry_name);
-				
-		if (realPath != null)
-			entry.ExtraData = ConvertToArray (realPath);
-		
-		zip_output.PutNextEntry (entry);
-		int n;
-			
-		while ((n = s.Read (buffer, 0, buffer_size)) > 0){
-			zip_output.Write (buffer, 0, n);
-		}	
-	}
-	
-	public void PackXml (string fname, XmlDocument doc)
-	{
-		zip_output.PutNextEntry (new ZipEntry (fname));
-		XmlTextWriter xmlWriter = new XmlTextWriter (zip_output, Encoding.UTF8);
-		doc.WriteContentTo (xmlWriter);
-		xmlWriter.Flush ();
-	}
-	
 	public virtual void RenderPreviewDocs (XmlNode newNode, XmlWriter writer)
 	{
 		throw new NotImplementedException ();
Index: Makefile.am
===================================================================
RCS file: /cvs/public/monodoc/browser/Makefile.am,v
retrieving revision 1.63
diff -u -r1.63 Makefile.am
--- Makefile.am	3 Aug 2004 04:24:00 -0000	1.63
+++ Makefile.am	28 Aug 2004 18:21:32 -0000
@@ -15,6 +15,7 @@
 	$(srcdir)/simple-provider.cs 	\
 	$(srcdir)/html-helper.cs	\
 	$(srcdir)/provider.cs 		\
+	$(srcdir)/HelpStore.cs 		\
 	$(srcdir)/index.cs 		\
 	$(srcdir)/error-provider.cs 	\
 	$(srcdir)/ecmaspec-provider.cs 	\

--=-8EJ1AW5KRODhV30cSSOg
Content-Disposition: inline; filename=HelpStore.cs
Content-Type: text/x-csharp; name=HelpStore.cs; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

//
// HelpStore: backend for saving/loading help data
//
// Authors:
//   Peter Williams (peter@newton.cx)
//   Miguel de Icaza (miguel@ximian.com)
//
// (C) 2004, Ximian, Inc.
//

namespace Monodoc {

using System;
using System.IO;
using System.Xml;
using System.Text;

using ICSharpCode.SharpZipLib.Zip;

public class HelpStore {
	bool write_mode;

	string tree_filename, zip_filename;
	DateTime zipFileWriteTime;
	ZipFile zip_file;
		
	public HelpStore (string base_filename, bool write_mode)
	{
		this.write_mode = write_mode;
		tree_filename = base_filename + ".tree";
		zip_filename = base_filename + ".zip";
		
		if (write_mode)
			SetupForOutput ();

		try {
			FileInfo fi = new FileInfo (zip_filename);
			zipFileWriteTime = fi.LastWriteTime;
		} catch {
			zipFileWriteTime = DateTime.Now;
		}
	}

	public DateTime ZipFileWriteTime {
		get {
			return zipFileWriteTime;
		}
	}
	
	// Reading from the store

	public Stream GetTreeStream ()
	{
		if (write_mode)
			return File.OpenWrite (tree_filename);

		return File.OpenRead (tree_filename);
	}

	public Stream GetHelpStream (string id)
	{
		if (zip_file == null)
			zip_file = new ZipFile (zip_filename);

		ZipEntry entry = zip_file.GetEntry (id);
		if (entry != null)
			return zip_file.GetInputStream (entry);
		return null;
	}
	
	public string GetRealPath (string file)
	{
		if (zip_file == null)
			zip_file = new ZipFile (zip_filename);

		ZipEntry entry = zip_file.GetEntry (file);
		if (entry != null && entry.ExtraData != null)
			return ConvertToString (entry.ExtraData);
		return null;
	}
	
	// Writing

	const int buffer_size = 65536;
	ZipOutputStream zip_output;
	byte [] buffer;
	
	void SetupForOutput ()
	{
		FileStream stream = File.Create (zip_filename);
		
		zip_output = new ZipOutputStream (stream);
		zip_output.SetLevel (9);

		buffer = new byte [buffer_size];
	}		

	void CheckWriteMode ()
	{
		if (write_mode)
			return;

		throw new InvalidOperationException ("Can't do this on a read-only HelpStore.");
	}

	public virtual void Save ()
	{
		CheckWriteMode ();

		zip_output.Finish ();
		zip_output.Close ();
	}

	int code;

	string GetNewCode ()
	{
		return String.Format ("{0}", code++);
	}

	public string PackFile (string file)
	{
		CheckWriteMode ();

		string entry_name = GetNewCode ();
		return PackFile (file, entry_name);
	}

	public string PackFile (string file, string entry_name)
	{
		CheckWriteMode ();

		using (FileStream input = File.OpenRead (file)) {
			PackStream (input, entry_name, file);
		}

		return entry_name;
	}
	
	public void PackStream (Stream s, string entry_name)
	{
		CheckWriteMode ();

		PackStream (s, entry_name, null);
	}
	
	void PackStream (Stream s, string entry_name, string realPath)
	{
		CheckWriteMode ();

		ZipEntry entry = new ZipEntry (entry_name);
				
		if (realPath != null)
			entry.ExtraData = ConvertToArray (realPath);
		
		zip_output.PutNextEntry (entry);
		int n;
			
		while ((n = s.Read (buffer, 0, buffer_size)) > 0){
			zip_output.Write (buffer, 0, n);
		}	
	}
	
	public void PackXml (string fname, XmlDocument doc)
	{
		CheckWriteMode ();

		zip_output.PutNextEntry (new ZipEntry (fname));
		XmlTextWriter xmlWriter = new XmlTextWriter (zip_output, Encoding.UTF8);
		doc.WriteContentTo (xmlWriter);
		xmlWriter.Flush ();
	}

	// Util

	static string ConvertToString (byte[] data)
	{
		return Encoding.UTF8.GetString(data);
	}
	
	static byte[] ConvertToArray (string str)
	{
		return Encoding.UTF8.GetBytes(str);
	}
}
}

--=-8EJ1AW5KRODhV30cSSOg--