view Loaders/ArmyBuilderABFileLoader.cs @ 5:ec77b60e5369 default tip

Re #121: Migrate to AGPL license * Update all Army Builder API files to AGPL license * Include AGPL license and remove GPL/LGPL documents
author IBBoard <dev@ibboard.co.uk>
date Sat, 15 Aug 2009 10:51:59 +0000
parents 1a54f6afafe7
children
line wrap: on
line source

//  This file (ArmyBuilderFileLoader.cs) is a part of the IBBoard.ArmyBuilder.API project and is copyright 2009 IBBoard
// 
// The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license.

using System;
using System.IO;

namespace IBBoard.ArmyBuilder.API.Loaders
{
	public class ArmyBuilderABFileLoader
	{
		private static byte HEADER_DELIMITER = 0x09;
		private static byte HEADER_TYPE_DELIMITER = 0x3A;
		private static byte TABLE_HEADER_OFFSET_FROM = 4;
		private static byte FILE_TABLE_OFFSET_LENGTH = 2;

		public static ABFile LoadFile(FileInfo file)
		{
			ABFile abFile = ReadFileInfo(file);
			ReadFileTable(abFile);
			return abFile;
		}

		private static ABFile ReadFileInfo(FileInfo file)
		{			
			BinaryReaderBigEndian reader = new BinaryReaderBigEndian(file.OpenRead());
			ABFile abFile = null;

			try
			{
				abFile = ReadFileInfo(file, reader);
			}
			finally
			{
				reader.Close();
			}	
			
			return abFile;
		}

		private static ABFile ReadFileInfo(FileInfo file, BinaryReaderBigEndian reader)
		{
			int tableOffset = reader.ReadInt();
			reader.Move(tableOffset);
			ushort fileTableOffset = reader.ReadUShort();
			string header = reader.ReadDelimitedString(HEADER_TYPE_DELIMITER);

			ABFile abFile = CreateFile(file, header);
			ReadExtraHeaders(abFile, reader);
			int fileTablePosition = TABLE_HEADER_OFFSET_FROM + tableOffset + FILE_TABLE_OFFSET_LENGTH + fileTableOffset;
			abFile.FileTablePosition = fileTablePosition;
			int readerPosition = (int)reader.Position;

			if (fileTablePosition > readerPosition)
			{
				abFile.Comment = reader.ReadString(fileTablePosition - readerPosition);
			}

			return abFile;
		}

		private static ABFile CreateFile(FileInfo file, string header)
		{
			ABFile abFile = null;
			header = header.Trim();
			
			if ("LWDExport".Equals(header))
			{
				abFile = new ABv3File(file);
			}
			else if ("ArmyBuilder".Equals(header))
			{
				abFile = new ABv2File(file);
			}
			else
			{
				throw new InvalidDataException("Unsupported file table header: "+header);
			}

			abFile.Header = header;
			return abFile;
		}

		private static void ReadExtraHeaders(ABFile abFile, BinaryReaderBigEndian reader)
		{
			if (abFile is ABv3File)
			{
				ABv3File ab3File = (ABv3File)abFile;
				ab3File.GameName = reader.ReadDelimitedString(HEADER_DELIMITER);
				ab3File.FolderName = reader.ReadDelimitedString(HEADER_DELIMITER);
				ab3File.ReleaseMajor = reader.ReadDelimitedString(HEADER_DELIMITER);
				ab3File.ReleaseMinor = reader.ReadDelimitedString(HEADER_DELIMITER);
				ab3File.RequiredMajorVersion = reader.ReadDelimitedString(HEADER_DELIMITER);
				ab3File.RequiredMinorVersion = reader.ReadDelimitedString(HEADER_DELIMITER);
				ab3File.UniqueID = reader.ReadDelimitedString(HEADER_DELIMITER);
				ab3File.Exporter = reader.ReadDelimitedString(HEADER_DELIMITER);
			}
		}

		private static void ReadFileTable(ABFile abFile)
		{	
			BinaryReaderBigEndian reader = new BinaryReaderBigEndian(abFile.File.OpenRead());

			try
			{
				ReadFileTable(abFile, reader);
			}
			finally
			{
				reader.Close();
			}
		}

		private static void ReadFileTable(ABFile abFile, BinaryReaderBigEndian reader)
		{			
			FileTableEntry entry = null;
			reader.Seek(abFile.FileTablePosition);
			
			do
			{
				entry = ReadFileTableEntry(reader);
				abFile.AddFileTableEntry(entry);
			}
			while (entry!=null);
		}

		private static FileTableEntry ReadFileTableEntry(BinaryReaderBigEndian reader)
		{
			FileTableEntry entry = null;
			string name = reader.ReadUShortLengthString();

			if (name!="" && name!=null)
			{
				entry = new FileTableEntry(name);
				entry.FirstBytes = reader.ReadBytes(8);
				entry.FileSize = reader.ReadInt();
				entry.CompressedSize = reader.ReadInt();
				entry.MidBytes = reader.ReadBytes(4);
				entry.Location = reader.ReadInt();
				entry.EndBytes = reader.ReadBytes(8);
			}

			return entry;
		}
	}
}