context: 
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.IO;
  using ScrewTurn.Wiki.SearchEngine;
  
  namespace ScrewTurn.Wiki {
  
  	/// <summary>
  	/// Stores index data to disk.
  	/// </summary>
  	/// <remarks>Instance and static members are <b>thread-safe</b>.</remarks>
  	public class IndexStorer : IndexStorerBase {
  
  		private static readonly byte[] ReservedBytes = new byte[] { 2, 0, 0, 0, 0, 0, 0, 0 };
  		private static readonly int Zero = 0;
  
  		private string documentsFile, wordsFile, mappingsFile;
  
  		private uint firstFreeDocumentId = 1;
  		private uint firstFreeWordId = 1;
  
  		// Documents file binary format
  		// Reserved(8bytes) Count(int) Entries...
  		//		ID(int) Name(string) Title(string) TypeTag(string) DateTime(long)
  
  		// Words file binary format
  		// Reserved(8bytes) Count(int) Entries...
  		//		ID(int) Text(string)
  
  		// Mappings file binary format
  		// Reserved(8bytes) Count(int) Entries...
  		//		WordID(int) DocumentID(int) FirstCharIndex(int) WordIndex(int) Location(int)
  
  		/// <summary>
  		/// Initializes a new instance of the <see cref="IndexStorer" /> class.
  		/// </summary>
  		/// <param name="documentsFile">The file that contains the documents list.</param>
  		/// <param name="wordsFile">The file that contains the words list.</param>
  		/// <param name="mappingsFile">The file that contains the index mappings data.</param>
  		/// <param name="index">The index to manage.</param>
  		public IndexStorer(string documentsFile, string wordsFile, string mappingsFile, IInMemoryIndex index)
  			: base(index) {
  
  			if(documentsFile == null) throw new ArgumentNullException("documentsFile");
  			if(wordsFile == null) throw new ArgumentNullException("wordsFile");
  			if(mappingsFile == null) throw new ArgumentNullException("mappingsFile");
  
  			if(documentsFile.Length == 0) throw new ArgumentException("Documents File cannot be empty", "documentsFile");
  			if(wordsFile.Length == 0) throw new ArgumentException("Words File cannot be emtpy", "wordsFile");
  			if(mappingsFile.Length == 0) throw new ArgumentException("Mappings File cannot be empty", "mappingsFile");
  
  			this.documentsFile = documentsFile;
  			this.wordsFile = wordsFile;
  			this.mappingsFile = mappingsFile;
  			
  			InitFiles();
  		}
  
  		/// <summary>
  		/// Gets the approximate size, in bytes, of the search engine index.
  		/// </summary>
  		public override long Size {
  			get {
  				lock(this) {
  					long size = 0;
  					FileInfo fi;
  
  					fi = new FileInfo(documentsFile);
  					size += fi.Length;
  
  					fi = new FileInfo(wordsFile);
  					size += fi.Length;
  
  					fi = new FileInfo(mappingsFile);
  					size += fi.Length;
  
  					return size;
  				}
  			}
  		}
  
  		/// <summary>
  		/// Loads the index from the data store the first time.
  		/// </summary>
  		/// <param name="documents">The dumped documents.</param>
  		/// <param name="words">The dumped words.</param>
  		/// <param name="mappings">The dumped word mappings.</param>
  		protected override void LoadIndexInternal(out DumpedDocument[] documents, out DumpedWord[] words, out DumpedWordMapping[] mappings) {
  			uint maxDocumentId = 0;
  			uint maxWordId = 0;
  
  			// 1. Load Documents
  			using(FileStream fs = new FileStream(documentsFile, FileMode.Open, FileAccess.Read, FileShare.None)) {
  				int count = ReadCount(fs);
  				BinaryReader reader = new BinaryReader(fs, Encoding.UTF8);
  				documents = new DumpedDocument[count];
  				for(int i = 0; i < count; i++) {
  					documents[i] = ReadDumpedDocument(reader);
  					if(documents[i].ID > maxDocumentId) maxDocumentId = documents[i].ID;
  				}
  				firstFreeDocumentId = maxDocumentId + 1;
  			}
  
  			// 2. Load Words
  			using(FileStream fs = new FileStream(wordsFile, FileMode.Open, FileAccess.Read, FileShare.None)) {
  				int count = ReadCount(fs);
  				BinaryReader reader = new BinaryReader(fs, Encoding.UTF8);
  				words = new DumpedWord[count];
  				for(int i = 0; i < count; i++) {
  					words[i] = ReadDumpedWord(reader);
  					if(words[i].ID > maxWordId) maxWordId = words[i].ID;
  				}
  				firstFreeWordId = maxWordId + 1;
  			}
  
  			// 3. Load Mappings
  			using(FileStream fs = new FileStream(mappingsFile, FileMode.Open, FileAccess.Read, FileShare.None)) {
  				int count = ReadCount(fs);
  				BinaryReader reader = new BinaryReader(fs, Encoding.UTF8);
  				mappings = new DumpedWordMapping[count];
  				for(int i = 0; i < count; i++) {
  					mappings[i] = ReadDumpedWordMapping(reader);
  				}
  			}
  		}
  
  		/// <summary>
  		/// Reads the reserved bytes.
  		/// </summary>
  		/// <param name="reader">The <see cref="BinaryReader" /> to read from.</param>
  		/// <returns><c>true</c> if read bytes are equal to expected bytes, <c>false</c> otherwise.</returns>
  		private static bool ReadReserved(BinaryReader reader) {
  			bool allEqual = true;
  			for(int i = 0; i < ReservedBytes.Length; i++) {
  				int r = reader.ReadByte();
  				if(r != ReservedBytes[i]) allEqual = false;
  			}
  			return allEqual;
  		}
  
  		/// <summary>
  		/// Initializes the data files, if needed.
  		/// </summary>
  		private void InitFiles() {
  			if(!File.Exists(documentsFile)) {
  				using(FileStream fs = new FileStream(documentsFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
  					BinaryWriter writer = new BinaryWriter(fs, Encoding.UTF8);
  					WriteHeader(writer);
  				}
  			}
  
  			if(!File.Exists(wordsFile)) {
  				using(FileStream fs = new FileStream(wordsFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
  					BinaryWriter writer = new BinaryWriter(fs, Encoding.UTF8);
  					WriteHeader(writer);
  				}
  			}
  
  			if(!File.Exists(mappingsFile)) {
  				using(FileStream fs = new FileStream(mappingsFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
  					BinaryWriter writer = new BinaryWriter(fs, Encoding.UTF8);
  					WriteHeader(writer);
  				}
  			}
  		}
  
  		/// <summary>
  		/// Initializes the data storage.
  		/// </summary>
  		/// <param name="state">A state object passed from the index.</param>
  		protected override void InitDataStore(object state) {
  			using(FileStream fs = new FileStream(documentsFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
  				BinaryWriter writer = new BinaryWriter(fs, Encoding.UTF8);
  				WriteHeader(writer);
  			}
  
  			using(FileStream fs = new FileStream(wordsFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
  				BinaryWriter writer = new BinaryWriter(fs, Encoding.UTF8);
  				WriteHeader(writer);
  			}
  
  			using(FileStream fs = new FileStream(mappingsFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
  				BinaryWriter writer = new BinaryWriter(fs, Encoding.UTF8);
  				WriteHeader(writer);
  			}
  		}
  
  		/// <summary>
  		/// Writes the binary file header.
  		/// </summary>
  		/// <param name="writer">The <see cref="BinaryWriter" /> to write into.</param>
  		private static void WriteHeader(BinaryWriter writer) {
  			writer.Write(ReservedBytes);
  			writer.Write(Zero);
  		}
  
  		/// <summary>
  		/// Reads a <see cref="DumpedDocument" /> from a <see cref="BinaryReader" />.
  		/// </summary>
  		/// <param name="reader">The <see cref="BinaryReader" />.</param>
  		/// <returns>The <see cref="DumpedDocument" />.</returns>
  		private static DumpedDocument ReadDumpedDocument(BinaryReader reader) {
  			uint id;
  			string name, title, typeTag;
  			DateTime dateTime;
  
  			id = reader.ReadUInt32();
  
gt: 			name = reader.ReadString();