note
	description: "[
		w_wad.c
		Handles WAD file header, directory, lump I/O.
	]"
	license: "[
				Copyright (C) 1993-1996 by id Software, Inc.
				Copyright (C) 2005-2014 Simon Howard
				Copyright (C) 2021 Ilgiz Mustafin
		
				This program is free software; you can redistribute it and/or modify
				it under the terms of the GNU General Public License as published by
				the Free Software Foundation; either version 2 of the License, or
				(at your option) any later version.
		
				This program is distributed in the hope that it will be useful,
				but WITHOUT ANY WARRANTY; without even the implied warranty of
				MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
				GNU General Public License for more details.
		
				You should have received a copy of the GNU General Public License along
				with this program; if not, write to the Free Software Foundation, Inc.,
				51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
	]"

class 
	W_WAD

create 
	make

feature 

	i_main: I_MAIN

	make (a_i_main: like i_main)
		do
			i_main := a_i_main
		end
	
feature 

	reloadname: detachable STRING_8

	reloadlump: INTEGER_32
	
feature 

	lumpinfo: detachable ARRAY [LUMPINFO_T]

	lumpcache: detachable ARRAY [detachable MANAGED_POINTER]
	
feature 

	w_initmultiplefiles (a_filenames: LIST [STRING_8])
		do
			create lumpinfo.make_empty
			across
				a_filenames as filename
			loop
				w_addfile (filename.item)
			end
			check
					attached lumpinfo as li
			then
				if li.is_empty then
					i_main.i_error ("W_InitFiles: no files found")
				end
				create lumpcache.make_filled (Void, 0, li.count)
			end
		end

	w_addfile (a_filename: STRING_8)
			--	// W_AddFile
			--// All files are optional, but at least one file must be
			--//  found (PWAD, if all required lumps are present).
			--// Files with a .wad extension are wadlink files
			--//  with multiple lumps.
			--// Other files are single lumps with the base filename
			--//  for the lump name.
			--//
			--// If filename starts with a tilde, the file is handled
			--//  specially to allow map reloads.
			--// But: the reload feature is a fragile hack...
		local
			l_file: RAW_FILE
			l_fileinfo: ARRAYED_LIST [FILELUMP_T]
			l_header: WADINFO_T
			i: INTEGER_32
			l_storehandle: detachable RAW_FILE
			start: INTEGER_32
		do
			if a_filename.starts_with ("~") then
				reloadname := a_filename.tail (a_filename.count - 1)
				check
						attached lumpinfo as li
				then
					reloadlump := li.count
				end
			end
			create l_file.make_open_read (a_filename)
			if not l_file.is_open_read then
				print (" could not open " + a_filename + "%N")
			else
				print (" adding " + a_filename + "%N")
				if not a_filename.as_upper.ends_with ("WAD") then
					create l_fileinfo.make (1)
					l_fileinfo.extend (create {FILELUMP_T}.make (0, l_file.file_info.size, extractfilebase (a_filename)))
				else
					create l_header.read_bytes (l_file)
					if not l_header.identification.as_upper.starts_with ("IWAD") then
						if not l_header.identification.as_upper.starts_with ("PWAD") then
							{I_MAIN}.i_error ("Wad file " + a_filename + " doesn't have IWAD or PWAD id%N")
						end
					end
					l_file.go (l_header.infotableofs)
					from
						i := 0
						create l_fileinfo.make (l_header.numlumps)
					until
						i >= l_header.numlumps
					loop
						l_fileinfo.extend (create {FILELUMP_T}.read_bytes (l_file))
						i := i + 1
					end
				end
				l_storehandle := if attached reloadname then
					Void
				else
					l_file
				end
				check
						attached lumpinfo as l_lumpinfo
				then
					from
						i := 1
						start := l_lumpinfo.upper
						l_lumpinfo.conservative_resize_with_default (create {LUMPINFO_T}.make ("UNUSED", Void, 0, 0), 0, l_lumpinfo.upper + l_fileinfo.count)
					until
						i > l_fileinfo.upper
					loop
						check
								attached lumpinfo as li
						then
							li [start + i - 1] := create {LUMPINFO_T}.make (l_fileinfo [i].name, l_storehandle, l_fileinfo [i].filepos, l_fileinfo [i].size)
						end
						i := i + 1
					end
				end
			end
		ensure
				attached lumpinfo as li and then {UTILS [LUMPINFO_T]}.all_different (li)
		end

	extractfilebase (a_filename: STRING_8): STRING_8
			-- Should return filename base with <= 8 chars
		local
			i: INTEGER_32
		do
			Result := ""
			from
				i := a_filename.count
			until
				i = 1 or else (a_filename [i - 1] = '/' or a_filename [i - 1] = '\')
			loop
				i := i - 1
			end
			from
			until
				i > a_filename.count or else a_filename [i] = '.'
			loop
				Result.append_character (a_filename [i].as_upper)
				i := i + 1
			end
		ensure
			no_separators: not Result.has ('/') and not Result.has ('\')
			no_dots: not Result.has ('.')
			uppercase: Result.as_upper ~ Result
			substring: a_filename.as_upper.has_substring (Result)
			instance_free: class
		end

	w_checknumforname (name: STRING_8): INTEGER_32
			-- Returns -1 if name not found
		do
			check
					attached lumpinfo as li
			then
				from
					Result := li.upper
				until
					Result < 0 or else li [Result].name.is_case_insensitive_equal (name)
				loop
					Result := Result - 1
				end
			end
		ensure
			minus_one_if_not_present: attached lumpinfo as li and then across
					li as l
				all
					not l.item.name.is_case_insensitive_equal (name)
				end implies Result = -1
			index_if_present: Result > -1 implies attached lumpinfo as li and then li [Result].name.is_case_insensitive_equal (name)
		end

	w_cachelumpname (name: STRING_8): MANAGED_POINTER
		do
			Result := w_cachelumpnum (w_getnumforname (name))
		ensure
				Result.count = w_lumplength (w_getnumforname (name))
		end

	w_getnumforname (name: STRING_8): INTEGER_32
		do
			Result := w_checknumforname (name)
			if Result = -1 then
				i_main.i_error ("W_GetNumForName: " + name + " not found!")
			end
		end

	w_cachelumpnum (lump: INTEGER_32): MANAGED_POINTER
		do
			check
					attached lumpinfo as li
			then
				if lump > li.count then
					i_main.i_error ("W_CacheLumpNum: " + lump.out + " >= numlumps")
				end
			end
			if attached lumpcache as lc and then attached lc [lump] as l then
				Result := l
			else
				Result := w_readlump (lump)
				check
						attached lumpcache as lc
				then
					lc [lump] := Result
				end
			end
		ensure
				Result.count = w_lumplength (lump)
		end

	w_lumplength (lump: INTEGER_32): INTEGER_32
		do
			check
					attached lumpinfo as li
			then
				if lump > li.count then
					i_main.i_error ("W_LumpLength: " + lump.out + " >= numlumps")
				end
				Result := li [lump].size
			end
		end

	w_readlump (lump: INTEGER_32): MANAGED_POINTER
			-- Loads the lump and returns it
			-- (originally wrote to a given buffer which must be >= W_LumpLength)
		local
			l: LUMPINFO_T
			handle: RAW_FILE
		do
			check
					attached lumpinfo as li
			then
				if lump > li.upper then
					i_main.i_error ("W_ReadLump: " + lump.out + " >= numlumps")
				end
				l := li [lump]
			end
			if not attached l.handle then
				check
						attached reloadname as rn
				then
					create handle.make_open_read (rn)
					if not handle.is_open_read then
						i_main.i_error ("W_ReadLump: couldn't open " + rn)
					end
				end
			else
				handle := l.handle
			end
			check
					handle /= Void
			then
				handle.go (l.position)
				create Result.make (l.size)
				handle.read_to_managed_pointer (Result, 0, l.size)
				if not attached l.handle then
					handle.close
				end
			end
		ensure
				Result.count = w_lumplength (lump)
		end

	w_releaselumpnum (lump: INTEGER_32)
		do
			{NOT_IMPLEMENTED}.not_implemented ("W_ReleaseLumpNum", False)
		end

	w_reload
		do
			if reloadname /= Void then
				{NOT_IMPLEMENTED}.not_implemented ("W_Reload", True)
			end
		end
	
end -- class W_WAD

Generated by ISE EiffelStudio