/****************************************************** * ROMVault2 is written by Gordon J. * * Contact gordon@romvault.com * * Copyright 2014 * ******************************************************/ using System.Collections.Generic; using System.IO; using ROMVault2.Properties; using ROMVault2.SupportedFiles; using ROMVault2.Utils; namespace ROMVault2.RvDB { public class RvDir : RvBase { public RvTreeRow Tree; public RvGame Game; private readonly List _dirDats = new List(); private readonly List _children = new List(); public readonly ReportStatus DirStatus = new ReportStatus(); public ZipStatus ZipStatus; public RvDir(FileType type) : base(type) { if (type != FileType.Dir && type != FileType.Zip && type !=FileType.SevenZip) ReportError.SendAndShow("Trying to set Dir type to " + type); } public override void Write(BinaryWriter bw) { base.Write(bw); if (Tree == null) bw.Write(false); else { bw.Write(true); Tree.Write(bw); } if (Game == null) bw.Write(false); else { bw.Write(true); Game.Write(bw); } int count = _dirDats.Count; bw.Write(count); for (int i = 0; i < count; i++) { _dirDats[i].Write(bw); } count = _children.Count; bw.Write(count); for (int i = 0; i < count; i++) { FileType type = _children[i].FileType; bw.Write((byte)type); _children[i].Write(bw); } if (DBTypeGet.isCompressedDir(FileType)) bw.Write((byte)ZipStatus); } public override void Read(BinaryReader br, List parentDirDats) { base.Read(br, parentDirDats); bool foundTree = br.ReadBoolean(); if (foundTree) { Tree = new RvTreeRow(); Tree.Read(br); } else Tree = null; bool foundGame = br.ReadBoolean(); if (foundGame) { Game = new RvGame(); Game.Read(br); } else Game = null; int count = br.ReadInt32(); _dirDats.Clear(); for (int i = 0; i < count; i++) { RvDat dat = new RvDat { DatIndex = i }; dat.Read(br); _dirDats.Add(dat); string datname = TreeFullName + @"\" + dat.GetData(RvDat.DatData.DatName); if (datname.Length >= 9 && datname.Substring(0, 9) == @"RomVault\") datname = datname.Substring(9); DB.Bgw.ReportProgress(0, new bgwText("Loading: " + datname)); DB.Bgw.ReportProgress((int)br.BaseStream.Position); } if (_dirDats.Count > 0) parentDirDats = _dirDats; count = br.ReadInt32(); _children.Clear(); for (int i = 0; i < count; i++) { RvBase tChild = DBTypeGet.GetRvType((FileType)br.ReadByte()); tChild.Parent = this; tChild.Read(br, parentDirDats); _children.Add(tChild); } if (DBTypeGet.isCompressedDir(FileType)) ZipStatus = (ZipStatus)br.ReadByte(); } public override EFile DatRemove() { Tree = null; Game = null; _dirDats.Clear(); return base.DatRemove(); } public override void DatAdd(RvBase b) { Tree = ((RvDir)b).Tree; Game = ((RvDir)b).Game; if (_dirDats.Count > 0) ReportError.SendAndShow(Resources.RvDir_SetDat_Setting_Dir_with_a_dat_list); base.DatAdd(b); } public override EFile FileRemove() { ZipStatus = ZipStatus.None; return base.FileRemove(); } public int DirDatCount { get { return _dirDats.Count; } } public RvDat DirDat(int index) { return _dirDats[index]; } public void DirDatAdd(RvDat dat) { int index; DirDatSearch(dat, out index); _dirDats.Insert(index, dat); for (int i = 0; i < _dirDats.Count; i++) _dirDats[i].DatIndex = i; } public void DirDatRemove(int index) { _dirDats.RemoveAt(index); for (int i = 0; i < _dirDats.Count; i++) _dirDats[i].DatIndex = i; } private void DirDatSearch(RvDat dat, out int index) { int intBottom = 0; int intTop = _dirDats.Count; int intMid = 0; int intRes = -1; //Binary chop to find the closest match while (intBottom < intTop && intRes != 0) { intMid = (intBottom + intTop) / 2; intRes = DBHelper.DatCompare(dat, _dirDats[intMid]); if (intRes < 0) intTop = intMid; else if (intRes > 0) intBottom = intMid + 1; } index = intMid; // if match was found check up the list for the first match if (intRes == 0) { int intRes1 = 0; while (index > 0 && intRes1 == 0) { intRes1 = DBHelper.DatCompare(dat, _dirDats[index - 1]); if (intRes1 == 0) index--; } } // if the search is greater than the closest match move one up the list else if (intRes > 0) index++; } public int ChildCount { get { return _children.Count; } } public RvBase Child(int index) { return _children[index]; } public int ChildAdd(RvBase child) { int index; ChildNameSearch(child, out index); ChildAdd(child, index); return index; } public void ChildAdd(RvBase child, int index) { if ( (FileType == FileType.Dir && child.FileType == FileType.ZipFile) || (FileType == FileType.Zip && child.FileType != FileType.ZipFile) ) ReportError.SendAndShow("Typing to add a " + child.FileType + " to a " + FileType); _children.Insert(index, child); child.Parent = this; UpdateRepStatusArrUpTree(child, 1); } public void ChildRemove(int index) { UpdateRepStatusArrUpTree(_children[index], -1); if (_children[index].Parent == this) _children[index].Parent = null; _children.RemoveAt(index); } public int ChildNameSearch(RvBase lName, out int index) { int intBottom = 0; int intTop = _children.Count; int intMid = 0; int intRes = -1; //Binary chop to find the closest match while (intBottom < intTop && intRes != 0) { intMid = (intBottom + intTop) / 2; intRes = DBHelper.CompareName(lName, _children[intMid]); if (intRes < 0) intTop = intMid; else if (intRes > 0) intBottom = intMid + 1; } index = intMid; // if match was found check up the list for the first match if (intRes == 0) { int intRes1 = 0; while (index > 0 && intRes1 == 0) { intRes1 = DBHelper.CompareName(lName, _children[index - 1]); if (intRes1 == 0) index--; } } // if the search is greater than the closest match move one up the list else if (intRes > 0) index++; return intRes; } public bool FindChild(RvBase lName, out int index) { if (ChildNameSearch(lName, out index) != 0) { ReportError.UnhandledExceptionHandler("Could not find self in Parent " + FullName); return false; } do { if (_children[index] == lName) return true; index++; } while (index < _children.Count && DBHelper.CompareName(lName, _children[index]) == 0); return false; } public void UpdateRepStatusUpTree(RepStatus rStat, int dir) { DirStatus.UpdateRepStatus(rStat, dir); if (Parent != null) Parent.UpdateRepStatusUpTree(rStat, dir); } private void UpdateRepStatusArrUpTree(RvBase child, int dir) { DirStatus.UpdateRepStatus(child.RepStatus, dir); RvDir rvDir = child as RvDir; if (rvDir != null) DirStatus.UpdateRepStatus(rvDir.DirStatus, dir); if (Parent != null) Parent.UpdateRepStatusArrUpTree(child, dir); } } }