// METHODS

	public void readBSP() {
		try {
			version = Version;
			byte[] theLump = new byte[0];
			BSPObject = new BSP(BSPFile.FullName, version);
			switch(version) {
				case mapType.TYPE_VINDICTUS:
				case mapType.TYPE_TACTICALINTERVENTION:
				case mapType.TYPE_SOURCE17:
				case mapType.TYPE_SOURCE18:
				case mapType.TYPE_SOURCE19:
				case mapType.TYPE_SOURCE20:
				case mapType.TYPE_SOURCE21:
				case mapType.TYPE_SOURCE22:
				case mapType.TYPE_SOURCE23:
				case mapType.TYPE_SOURCE27:
				case mapType.TYPE_DMOMAM:
					DecompilerThread.OnMessage(this, "Source BSP");
					stream.Seek(8, SeekOrigin.Begin);
					int test = br.ReadInt32();
					if(bigEndian) { test = DataReader.swapEndian(test); }
					if(test < 1032) { // If what's usually the offset is less than the length of the header and directory
						isL4D2 = true; // This is Left 4 Dead 2
					}
					
					// Lump 35, Game lump
					// Need to handle this here in order to detect Vindictus maps.
					// This lump SUCKS. It's a lump containing nested lumps for game specific data.
					// What we need out of it is the static prop lump.
					theLump = readLumpNum(35);
					try {
						readGameLump(theLump, lumpOffset);
					} catch {
						dumpLump(theLump);
					}

					for(int i=0;i<64;i++) {
						try {
							switch(i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 2:
									theLump = readLumpNum(i);
									BSPObject.TexDatas = SourceTexData.createLump(theLump);
									break;
								case 3:
									theLump = readLumpNum(i);
									BSPObject.Vertices = Vertex.createLump(theLump, version);
									break;
								case 5:
									theLump = readLumpNum(i);
									BSPObject.Nodes = Node.createLump(theLump, version);
									break;
								case 6:
									theLump = readLumpNum(i);
									BSPObject.TexInfo = TexInfo.createLump(theLump, version);
									break;
								case 7:
									theLump = readLumpNum(i);
									BSPObject.Faces = Face.createLump(theLump, version);
									break;
								case 10:
									theLump = readLumpNum(i);
									BSPObject.Leaves = Leaf.createLump(theLump, version);
									break;
								case 12:
									theLump = readLumpNum(i);
									BSPObject.Edges = Edge.createLump(theLump, version);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT);
									break;
								case 14:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 17:
									theLump = readLumpNum(i);
									if(version == mapType.TYPE_VINDICTUS) {
										BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT);
									} else {
										BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.USHORT);
									}
									break;
								case 18:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 19:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 26:
									theLump = readLumpNum(i);
									BSPObject.DispInfos = SourceDispInfo.createLump(theLump, version);
									break;
								case 27:
									theLump = readLumpNum(i);
									BSPObject.OriginalFaces = Face.createLump(theLump, version);
									break;
								case 33:
									theLump = readLumpNum(i);
									BSPObject.DispVerts = SourceDispVertex.createLump(theLump);
									break;
								case 40:
									theLump = readLumpNum(i);
									if (Settings.extractZip) {
										Console.Write("Extracting internal PAK file... ");
										writeLump(BSPObject.MapName+".zip", theLump);
									}
									break;
								case 42:
									theLump = readLumpNum(i);
									BSPObject.Cubemaps = SourceCubemap.createLump(theLump, version);
									break;
								case 43:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 44:
									theLump = readLumpNum(i);
									BSPObject.TexTable = new NumList(theLump, NumList.dataType.INT);
									break;
								case 48:
									theLump = readLumpNum(i);
									BSPObject.DispTris = new NumList(theLump, NumList.dataType.USHORT);
									break;
							}
						} catch {
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_NIGHTFIRE:
					DecompilerThread.OnMessage(this, "BSP v42 (Nightfire)");
					for(int i=0;i<18;i++) {
						try {
							switch(i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 2:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 3:
									theLump = readLumpNum(i);
									BSPObject.Materials = Texture.createLump(theLump, version);
									break;
								case 4:
									theLump = readLumpNum(i);
									BSPObject.Vertices = Vertex.createLump(theLump, version);
									break;
								case 9:
									theLump = readLumpNum(i);
									BSPObject.Faces = Face.createLump(theLump, version);
									break;
								case 11:
									theLump = readLumpNum(i);
									BSPObject.Leaves = Leaf.createLump(theLump, version);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT);
									break;
								case 14:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 15:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 16:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 17:
									theLump = readLumpNum(i);
									BSPObject.TexInfo = TexInfo.createLump(theLump, version);
									break;
							}
						} catch {
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_QUAKE2:
				case mapType.TYPE_SIN: 
				case mapType.TYPE_DAIKATANA: 
				case mapType.TYPE_SOF:
					DecompilerThread.OnMessage(this, "BSP v38 (Quake 2/SiN/Daikatana/Soldier of Fortune)");
					for(int i=0;i<19;i++) {
						try {
							switch(i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 2:
									theLump = readLumpNum(i);
									BSPObject.Vertices = Vertex.createLump(theLump, version);
									break;
								case 4:
									theLump = readLumpNum(i);
									BSPObject.Nodes = Node.createLump(theLump, version);
									break;
								case 5:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 6:
									theLump = readLumpNum(i);
									BSPObject.Faces = Face.createLump(theLump, version);
									break;
								case 8:
									theLump = readLumpNum(i);
									BSPObject.Leaves = Leaf.createLump(theLump, version);
									break;
								case 10:
									theLump = readLumpNum(i);
									BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.USHORT);
									break;
								case 11:
									theLump = readLumpNum(i);
									BSPObject.Edges = Edge.createLump(theLump, version);
									break;
								case 12:
									theLump = readLumpNum(i);
									BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 14:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 15:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								/*case 18:
									theLump = readLumpNum(i);
									BSPObject.AreaPortals = AreaPortal.createLump(theLump, version);
									break;*/
							}
						} catch {
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_QUAKE:
					DecompilerThread.OnMessage(this, "Quake 1/Half-life BSP");
					for (int i = 0; i < 15; i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 2:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 3:
									theLump = readLumpNum(i);
									BSPObject.Vertices = Vertex.createLump(theLump, version);
									break;
								case 5:
									theLump = readLumpNum(i);
									BSPObject.Nodes = Node.createLump(theLump, version);
									break;
								case 6:
									theLump = readLumpNum(i);
									BSPObject.TexInfo = TexInfo.createLump(theLump, version);
									break;
								case 7:
									theLump = readLumpNum(i);
									BSPObject.Faces = Face.createLump(theLump, version);
									break;
								case 10:
									theLump = readLumpNum(i);
									BSPObject.Leaves = Leaf.createLump(theLump, version);
									break;
								case 11:
									theLump = readLumpNum(i);
									BSPObject.MarkSurfaces = new NumList(theLump, NumList.dataType.USHORT);
									break;
								case 12:
									theLump = readLumpNum(i);
									BSPObject.Edges = Edge.createLump(theLump, version);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.SurfEdges = new NumList(theLump, NumList.dataType.INT);
									break;
								case 14:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_STEF2:
				case mapType.TYPE_STEF2DEMO:
					DecompilerThread.OnMessage(this, "Star Trek Elite Force 2 BSP");
					for (int i = 0; i < 30; i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 5:
									theLump = readLumpNum(i);
									BSPObject.Faces = Face.createLump(theLump, version);
									break;
								case 6:
									theLump = readLumpNum(i);
									BSPObject.Vertices = Vertex.createLump(theLump, version);
									break;
								case 12:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 15:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 16:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_MOHAA: 
					DecompilerThread.OnMessage(this, "MOHAA BSP (modified id Tech 3)");
					for(int i=0;i<28;i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 3:
									theLump = readLumpNum(i);
									BSPObject.Faces = Face.createLump(theLump, version);
									break;
								case 4:
									theLump = readLumpNum(i);
									BSPObject.Vertices = Vertex.createLump(theLump, version);
									break;
								case 11:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 12:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 14:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
								//case 24:
								//	theLump = readLumpNum(i);
								//	BSPObject.StaticProps = StaticProp.createLump(theLump);
								//	break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_FAKK: 
					DecompilerThread.OnMessage(this, "Heavy Metal FAKK² BSP");
					for(int i=0;i<20;i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 10:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 11:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 14:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_RAVEN: 
				case mapType.TYPE_QUAKE3: 
					DecompilerThread.OnMessage(this, "BSP v46 (id Tech 3)");
					for(int i=0;i<18;i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
								case 1:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 2:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 7:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 8:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 9:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 10:
									theLump = readLumpNum(i);
									BSPObject.Vertices = Vertex.createLump(theLump, version);
									break;
								case 13:
									theLump = readLumpNum(i);
									BSPObject.Faces = Face.createLump(theLump, version);
									break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_COD: 
					DecompilerThread.OnMessage(this, "BSP v59 (Call of Duty)");
					for(int i=0;i<33;i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 2:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 3:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 4:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 27:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 29:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
					
				case mapType.TYPE_COD2: 
					DecompilerThread.OnMessage(this, "Call of Duty 2 BSP");
					for(int i=0;i<40;i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 4:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 5:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 6:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 35:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 37:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_COD4:
					DecompilerThread.OnMessage(this, "Call of Duty 4 BSP");
					for(int i=0;i<55;i++) {
						try {
							switch (i) {
								case 0:
									theLump = readLumpNum(i);
									BSPObject.Textures = Texture.createLump(theLump, version);
									break;
								case 4:
									theLump = readLumpNum(i);
									BSPObject.Planes = Plane.createLump(theLump, version);
									break;
								case 5:
									theLump = readLumpNum(i);
									BSPObject.BrushSides = BrushSide.createLump(theLump, version);
									break;
								case 8:
									theLump = readLumpNum(i);
									BSPObject.Brushes = Brush.createLump(theLump, version);
									break;
								case 37:
									theLump = readLumpNum(i);
									BSPObject.Models = Model.createLump(theLump, version);
									break;
								case 39:
									theLump = readLumpNum(i);
									BSPObject.Entities = Entity.createLump(theLump);
									break;
							}
						}
						catch
						{
							dumpLump(theLump);
						}
					}
					break;
				case mapType.TYPE_DOOM:
				case mapType.TYPE_HEXEN:
					DecompilerThread.OnMessage(this, "WAD file found");
					stream.Seek(4, SeekOrigin.Begin);
					int numLumps = br.ReadInt32();
					for(int i=0;i<numLumps;i++) {
						string name = getLumpName(i);
						if((name.Length == 5 && name[0] == 'M' && name[1] == 'A' && name[2] == 'P' && name[3] >= '0' && name[3] <= '9' && name[4] >= '0' && name[4] <= '9')
						|| ((name.Length == 4 && name[0] == 'E' && name[1] >= '0' && name[1] <= '9' && name[2] == 'M' && name[3] >= '0' && name[3] <= '9'))) {
							if(getLumpName(i+11) == "BEHAVIOR") {
								version = mapType.TYPE_HEXEN;
							}
							DecompilerThread.OnMessage(this, "Map: " + name);
							DoomMap currentMap = new DoomMap(BSPFile.FullName, name, version);
							int[] headerInfo = getLumpInfo(i);
							if (headerInfo[1] > 0 && Settings.extractZip) {
								Console.Write("Extracting Map Header ");
								writeLump(name+".txt", readLumpNum(i));
							}
							
							currentMap.Things = DThing.createLump(readLumpNum(i+1), version);
							currentMap.Linedefs = DLinedef.createLump(readLumpNum(i+2), version);
							currentMap.Sidedefs = DSidedef.createLump(readLumpNum(i+3));
							currentMap.Vertices = Vertex.createLump(readLumpNum(i+4), version);
							currentMap.Segments = DSegment.createLump(readLumpNum(i+5));
							currentMap.SubSectors = Edge.createLump(readLumpNum(i+6), version);
							currentMap.Nodes = DNode.createLump(readLumpNum(i+7));
							currentMap.Sectors = DSector.createLump(readLumpNum(i+8));

							doomMaps.Add(currentMap);
							currentMap.printBSPReport();
						}
					}
					break;
				default:
					DecompilerThread.OnMessage(this, "Tried to populate structures for a format not implemented yet!");
					break;
			}
			BSPObject.printBSPReport();
		}
		catch (System.IO.IOException) {
			DecompilerThread.OnMessage(this, "Unable to access BSP file! Is it open in another program?");
		}
		br.Close();
	}
    // METHODS

    public void readBSP()
    {
        try {
            byte[] theLump = new byte[0];
            byte[] vis     = new byte[0];
            BSPObject = new BSP(BSPFile.FullName);
            Console.WriteLine("Opening " + BSPFile.FullName);
            for (int i = 0; i < 18; i++)
            {
                try {
                    theLump = readLumpNum(i);
                    switch (i)
                    {
                    case 0:
                        BSPObject.Entities = Entity.createLump(theLump);
                        break;

                    case 1:
                        BSPObject.Planes = Plane.createLump(theLump);
                        break;

                    case 2:
                        BSPObject.Textures = Texture.createLump(theLump);
                        break;

                    case 3:
                        BSPObject.Materials = Texture.createLump(theLump);
                        break;

                    case 4:
                        BSPObject.Vertices = Vertex.createLump(theLump);
                        break;

                    case 5:
                        BSPObject.Normals = new Lump <LumpObject>(theLump.Length, 0);
                        break;

                    case 6:
                        BSPObject.Indices = new NumList(theLump, NumList.dataType.UINT);
                        break;

                    case 7:
                        vis = theLump;
                        break;

                    case 8:
                        BSPObject.Nodes = Node.createLump(theLump);
                        break;

                    case 9:
                        BSPObject.Faces = Face.createLump(theLump);
                        break;

                    case 10:
                        BSPObject.Lightmaps = new NumList(theLump, NumList.dataType.UBYTE);
                        break;

                    case 11:
                        BSPObject.Leaves = Leaf.createLump(theLump);
                        break;

                    case 12:
                        BSPObject.MarkSurfaces = new NumList(theLump, NumList.dataType.UINT);
                        break;

                    case 13:
                        BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT);
                        break;

                    case 14:
                        BSPObject.Models = Model.createLump(theLump);
                        break;

                    case 15:
                        BSPObject.Brushes = Brush.createLump(theLump);
                        break;

                    case 16:
                        BSPObject.BrushSides = BrushSide.createLump(theLump);
                        break;

                    case 17:
                        BSPObject.TexInfo = TexInfo.createLump(theLump);
                        break;
                    }
                } catch {
                    dumpLump(theLump);
                }
            }
            try {
                int visLength = BSPObject.Leaves[2].PVS;
                if (visLength > 0 && vis.Length > 0)
                {
                    BSPObject.Vis = new Lump <LumpObject>(vis, visLength);
                }
            } catch (ArgumentOutOfRangeException) {; }
            if (BSPObject.Vis == null)
            {
                BSPObject.Vis = new Lump <LumpObject>(0, 0);
            }
            BSPObject.printBSPReport();
        }
        catch (System.IO.IOException) {
            Console.WriteLine("Unable to access BSP file! Is it open in another program?");
        }
        br.Close();
    }