summaryrefslogtreecommitdiff
path: root/hammer/prefabs.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/prefabs.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'hammer/prefabs.cpp')
-rw-r--r--hammer/prefabs.cpp991
1 files changed, 991 insertions, 0 deletions
diff --git a/hammer/prefabs.cpp b/hammer/prefabs.cpp
new file mode 100644
index 0000000..0ae1444
--- /dev/null
+++ b/hammer/prefabs.cpp
@@ -0,0 +1,991 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements a system for managing prefabs. There are two types
+// of prefabs implemented here: Half-Life style prefabs, and Half-Life 2
+// style prefabs.
+//
+// For Half-Life, prefab libraries are stored as binary .OL files, each of
+// which contains multiple .RMF files that are the prefabs.
+//
+// For Half-Life 2, prefabs are stored in a tree of folders, each folder
+// representing a library, and the each .VMF file in the folder containing
+// a single prefab.
+//
+//=============================================================================//
+
+
+#include "stdafx.h"
+#include "Prefabs.h"
+#include "Prefab3D.h"
+#include "hammer.h"
+#include <io.h>
+#include <fcntl.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+BOOL CPrefab::bCacheEnabled = TRUE;
+CPrefabList CPrefab::PrefabList;
+CPrefabList CPrefab::MRU;
+CPrefabLibraryList CPrefabLibrary::PrefabLibraryList;
+
+
+static char *pLibHeader = "Worldcraft Prefab Library\r\n\x1a";
+static float fLibVersion = 0.1f;
+
+
+typedef struct
+{
+ DWORD dwOffset;
+ DWORD dwSize;
+ char szName[31];
+ char szNotes[MAX_NOTES];
+ int iType;
+} PrefabHeader;
+
+
+typedef struct
+{
+ float fVersion;
+ DWORD dwDirOffset;
+ DWORD dwNumEntries;
+ char szNotes[MAX_NOTES];
+} PrefabLibraryHeader;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a prefab library from a given path.
+// Input : szFile -
+// Output :
+//-----------------------------------------------------------------------------
+CPrefabLibrary *CreatePrefabLibrary(const char *szFile)
+{
+ CPrefabLibrary *pLibrary;
+
+ if (stricmp(&szFile[strlen(szFile) - 2], ".ol") != 0)
+ {
+ pLibrary = new CPrefabLibraryVMF;
+ }
+ else
+ {
+ pLibrary = new CPrefabLibraryRMF;
+ }
+
+ if (pLibrary->Load(szFile) == -1)
+ {
+ delete pLibrary;
+ return(NULL);
+ }
+
+ return(pLibrary);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefab::CPrefab()
+{
+ static DWORD dwRunningID = 1;
+ // assign running ID
+ dwID = dwRunningID++;
+ PrefabList.AddTail(this);
+
+ // assign blank name/notes
+ szName[0] = szNotes[0] = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefab::~CPrefab()
+{
+ POSITION p = PrefabList.Find(this);
+ if(p)
+ PrefabList.RemoveAt(p);
+ p = MRU.Find(this);
+ if(p)
+ MRU.RemoveAt(p);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : dwID -
+// Output : CPrefab *
+//-----------------------------------------------------------------------------
+CPrefab * CPrefab::FindID(DWORD dwID)
+{
+ POSITION p = PrefabList.GetHeadPosition();
+ while(p)
+ {
+ CPrefab *pPrefab = PrefabList.GetNext(p);
+ if(pPrefab->dwID == dwID)
+ return pPrefab;
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : b -
+//-----------------------------------------------------------------------------
+void CPrefab::EnableCaching(BOOL b)
+{
+ bCacheEnabled = b;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPrefab -
+//-----------------------------------------------------------------------------
+void CPrefab::AddMRU(CPrefab *pPrefab)
+{
+ if(!bCacheEnabled)
+ return;
+
+ POSITION p = MRU.Find(pPrefab);
+ if(p)
+ {
+ // remove there and add to head
+ MRU.RemoveAt(p);
+ }
+ else if(MRU.GetCount() == 5)
+ {
+ // uncache tail object
+ p = MRU.GetTailPosition();
+ if(p) // might not be any yet
+ {
+ CPrefab *pUncache = MRU.GetAt(p);
+ pUncache->FreeData();
+ MRU.RemoveAt(p);
+ }
+ }
+
+ // add to head
+ MRU.AddHead(pPrefab);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPrefab::FreeAllData()
+{
+ // free all prefab data memory
+ POSITION p = PrefabList.GetHeadPosition();
+ while(p)
+ {
+ CPrefab *pPrefab = PrefabList.GetNext(p);
+ pPrefab->FreeData();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszFilename -
+// Output : CPrefab::pfiletype_t
+//-----------------------------------------------------------------------------
+CPrefab::pfiletype_t CPrefab::CheckFileType(LPCTSTR pszFilename)
+{
+ // first check extensions
+ const char *p = strrchr(pszFilename, '.');
+ if(p)
+ {
+ if(!strcmpi(p, ".rmf"))
+ return pftRMF;
+ else if(!strcmpi(p, ".map"))
+ return pftMAP;
+ else if(!strcmpi(p, ".os"))
+ return pftScript;
+ }
+
+ std::fstream file(pszFilename, std::ios::in | std::ios::binary);
+
+ // read first 16 bytes of file
+ char szBuf[255];
+ file.read(szBuf, 16);
+
+ // check 1: RMF
+ float f = ((float*) szBuf)[0];
+
+ // 0.8 was version at which RMF tag was started
+ if(f <= 0.7f || !strncmp(szBuf+sizeof(float), "RMF", 3))
+ {
+ return pftRMF;
+ }
+
+ // check 2: script
+ if(!strnicmp(szBuf, "[Script", 7))
+ {
+ return pftScript;
+ }
+
+ // check 3: MAP
+ int i = 500;
+ while(i--)
+ {
+ file >> std::ws;
+ file.getline(szBuf, 255);
+ if(szBuf[0] == '{')
+ return pftMAP;
+ if(file.eof())
+ break;
+ }
+
+ return pftUnknown;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefabLibrary::CPrefabLibrary()
+{
+ static DWORD dwRunningID = 1;
+ // assign running ID
+ dwID = dwRunningID++;
+ m_szName[0] = '\0';
+ szNotes[0] = '\0';
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefabLibrary::~CPrefabLibrary()
+{
+ FreePrefabs();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPrefabLibrary::FreePrefabs()
+{
+ // nuke prefabs
+ POSITION p = Prefabs.GetHeadPosition();
+ while (p != NULL)
+ {
+ CPrefab *pPrefab = Prefabs.GetNext(p);
+ delete pPrefab;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *a -
+// *b -
+// Output : static int
+//-----------------------------------------------------------------------------
+static int __cdecl SortPrefabs(CPrefab *a, CPrefab *b)
+{
+ return(strcmpi(a->GetName(), b->GetName()));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPrefabLibrary::Sort(void)
+{
+ int nPrefabs = Prefabs.GetCount();
+ if (nPrefabs < 2)
+ {
+ return;
+ }
+
+ CPrefab **TmpPrefabArray = new CPrefab *[nPrefabs];
+
+ //
+ // Make an array we can pass to qsort.
+ //
+ POSITION p = ENUM_START;
+ CPrefab *pPrefab = EnumPrefabs(p);
+ int iPrefab = 0;
+ while (pPrefab != NULL)
+ {
+ TmpPrefabArray[iPrefab++] = pPrefab;
+ pPrefab = EnumPrefabs(p);
+ }
+
+ //
+ // Sort the prefabs array by name.
+ //
+ qsort(TmpPrefabArray, nPrefabs, sizeof(CPrefab *), (int (__cdecl *)(const void *, const void *))SortPrefabs);
+
+ //
+ // Store back in list in sorted order.
+ //
+ Prefabs.RemoveAll();
+ for (int i = 0; i < nPrefabs; i++)
+ {
+ Prefabs.AddTail(TmpPrefabArray[i]);
+ }
+
+ delete[] TmpPrefabArray;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszFilename -
+//-----------------------------------------------------------------------------
+void CPrefabLibrary::SetNameFromFilename(LPCTSTR pszFilename)
+{
+ const char *cp = strrchr(pszFilename, '\\');
+ strcpy(m_szName, cp ? (cp + 1) : pszFilename);
+ char *p = strchr(m_szName, '.');
+ if (p != NULL)
+ {
+ p[0] = '\0';
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees all the libraries in the prefab library list.
+//-----------------------------------------------------------------------------
+void CPrefabLibrary::FreeAllLibraries(void)
+{
+ POSITION pos = PrefabLibraryList.GetHeadPosition();
+ while (pos != NULL)
+ {
+ CPrefabLibrary *pPrefabLibrary = PrefabLibraryList.GetNext(pos);
+ if (pPrefabLibrary != NULL)
+ {
+ delete pPrefabLibrary;
+ }
+ }
+
+ PrefabLibraryList.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Load all libraries in the prefabs directory.
+//-----------------------------------------------------------------------------
+void CPrefabLibrary::LoadAllLibraries()
+{
+ char szDir[MAX_PATH];
+ char szFile[MAX_PATH];
+ ((CHammer *)AfxGetApp())->GetDirectory(DIR_PREFABS, szDir);
+
+ //
+ // Add one prefab library for the root prefabs folder in case they put something there.
+ //
+ CPrefabLibrary *pLibrary = FindOpenLibrary(szDir);
+ if (pLibrary == NULL)
+ {
+ pLibrary = CreatePrefabLibrary(szDir);
+ if (pLibrary != NULL)
+ {
+ PrefabLibraryList.AddTail(pLibrary);
+ }
+ }
+ else
+ {
+ pLibrary->Load(szDir);
+ }
+
+ strcat(szDir, "\\*.*");
+
+ WIN32_FIND_DATA fd;
+ HANDLE hnd = FindFirstFile(szDir, &fd);
+ strrchr(szDir, '\\')[0] = 0; // truncate that
+
+ if (hnd == INVALID_HANDLE_VALUE)
+ {
+ return; // no libraries
+ }
+
+ do
+ {
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (fd.cFileName[0] != '.'))
+ {
+ sprintf(szFile, "%s\\%s", szDir, fd.cFileName);
+
+ pLibrary = FindOpenLibrary(szFile);
+ if (pLibrary == NULL)
+ {
+ pLibrary = CreatePrefabLibrary(szFile);
+ if (pLibrary != NULL)
+ {
+ PrefabLibraryList.AddTail(pLibrary);
+ }
+ }
+ else
+ {
+ pLibrary->Load(szDir);
+ }
+ }
+ } while (FindNextFile(hnd, &fd));
+
+ FindClose(hnd);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPrefab -
+//-----------------------------------------------------------------------------
+void CPrefabLibrary::Add(CPrefab *pPrefab)
+{
+ if(!Prefabs.Find(pPrefab))
+ Prefabs.AddTail(pPrefab);
+ pPrefab->dwLibID = dwID;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPrefab -
+//-----------------------------------------------------------------------------
+void CPrefabLibrary::Remove(CPrefab *pPrefab)
+{
+ POSITION p = Prefabs.Find(pPrefab);
+ if(p)
+ Prefabs.RemoveAt(p);
+ if(pPrefab->dwLibID == dwID) // make sure it doesn't reference this
+ pPrefab->dwLibID = 0xffff;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &p -
+// Output : CPrefab *
+//-----------------------------------------------------------------------------
+CPrefab * CPrefabLibrary::EnumPrefabs(POSITION &p)
+{
+ if(p == ENUM_START)
+ p = Prefabs.GetHeadPosition();
+ if(!p)
+ return NULL;
+ return Prefabs.GetNext(p);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : dwID -
+// Output : CPrefabLibrary *
+//-----------------------------------------------------------------------------
+CPrefabLibrary * CPrefabLibrary::FindID(DWORD dwID)
+{
+ POSITION p = PrefabLibraryList.GetHeadPosition();
+ while(p)
+ {
+ CPrefabLibrary *pPrefabLibrary = PrefabLibraryList.GetNext(p);
+ if(pPrefabLibrary->dwID == dwID)
+ return pPrefabLibrary;
+ }
+
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszFilename -
+// Output :
+//-----------------------------------------------------------------------------
+CPrefabLibrary *CPrefabLibrary::FindOpenLibrary(LPCTSTR pszFilename)
+{
+ // checks to see if a library is open under that filename
+ POSITION p = ENUM_START;
+ CPrefabLibrary *pLibrary = EnumLibraries(p);
+ while (pLibrary != NULL)
+ {
+ if (pLibrary->IsFile(pszFilename))
+ {
+ return(pLibrary);
+ }
+ pLibrary = EnumLibraries(p);
+ }
+
+ return(NULL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Enumerates the prefab libraries of a given type.
+// Input : p - Iterator.
+// eType - Type of library to return, LibType_None returns all
+// library types.
+// Output : Returns the next library of the given type.
+//-----------------------------------------------------------------------------
+CPrefabLibrary *CPrefabLibrary::EnumLibraries(POSITION &p, LibraryType_t eType)
+{
+ if (p == ENUM_START)
+ {
+ p = PrefabLibraryList.GetHeadPosition();
+ }
+
+ while (p != NULL)
+ {
+ CPrefabLibrary *pLibrary = PrefabLibraryList.GetNext(p);
+ if ((eType == LibType_None) || pLibrary->IsType(eType))
+ {
+ return(pLibrary);
+ }
+ }
+
+ return(NULL);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefabLibraryRMF::CPrefabLibraryRMF()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefabLibraryRMF::~CPrefabLibraryRMF()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if this prefab represents the given filename, false if not.
+// Input : szFilename - Path of a prefab library or folder.
+//-----------------------------------------------------------------------------
+bool CPrefabLibraryRMF::IsFile(const char *szFilename)
+{
+ return(strcmpi(m_strOpenFileName, szFilename) == 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszFilename -
+// Output : int
+//-----------------------------------------------------------------------------
+int CPrefabLibraryRMF::Load(LPCTSTR pszFilename)
+{
+ FreePrefabs();
+
+ m_eType = LibType_HalfLife;
+
+ // open file
+ m_file.open(pszFilename, std::ios::in | std::ios::binary);
+ m_strOpenFileName = pszFilename;
+
+ if(!m_file.is_open())
+ return -1;
+
+ char szBuf[128];
+
+ // read string header
+ m_file.read(szBuf, strlen(pLibHeader));
+ if(strncmp(szBuf, pLibHeader, strlen(pLibHeader)))
+ {
+ // return
+ return -1;
+ }
+
+ // read binary header
+ PrefabLibraryHeader plh;
+ m_file.read((char*)&plh, sizeof(plh));
+ strcpy(szNotes, plh.szNotes);
+
+ // set name from filename
+ SetNameFromFilename(pszFilename);
+
+ // read directory
+ PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
+ m_dwDirOffset = plh.dwDirOffset;
+ m_file.seekg(plh.dwDirOffset);
+ m_file.read((char*)ph, plh.dwNumEntries * sizeof(PrefabHeader));
+
+ //
+ // Read each prefab.
+ //
+ for(DWORD i = 0; i < plh.dwNumEntries; i++)
+ {
+ Assert(ph[i].iType == pt3D);
+ CPrefabRMF *pPrefab = new CPrefabRMF;
+
+ // seek to prefab
+ m_file.seekg(ph[i].dwOffset);
+ pPrefab->Init(m_file);
+
+ // set its other info frm the dir entry
+ pPrefab->SetName(ph[i].szName);
+ pPrefab->SetNotes(ph[i].szNotes);
+ pPrefab->dwFileSize = ph[i].dwSize;
+ pPrefab->dwFileOffset = ph[i].dwOffset;
+
+ Add(pPrefab);
+ }
+
+ // delete directory
+ delete[] ph;
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes this prefab library from disk.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CPrefabLibraryRMF::DeleteFile(void)
+{
+ return(remove(m_strOpenFileName) == 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszFilename -
+// bIndexOnly -
+// Output : int
+//-----------------------------------------------------------------------------
+int CPrefabLibraryRMF::Save(LPCTSTR pszFilename, BOOL bIndexOnly)
+{
+ // temp storage
+ static char szFile[MAX_PATH];
+
+ // if only saving index, special code -
+ if(bIndexOnly && m_file.is_open())
+ {
+ // close file, reopen in binary write
+ m_file.close();
+ if(Prefabs.GetCount())
+ {
+ // change size of file first
+ int iHandle = _open(m_strOpenFileName, _O_BINARY | _O_WRONLY);
+ _chsize(iHandle, m_dwDirOffset);
+ _close(iHandle);
+ }
+
+ std::fstream file(m_strOpenFileName, std::ios::binary | std::ios::out);
+
+ // write string header
+ file << pLibHeader;
+ // write binary header (in case notes have changed)
+ PrefabLibraryHeader plh;
+ plh.dwNumEntries = Prefabs.GetCount();
+ plh.fVersion = fLibVersion;
+ plh.dwDirOffset = m_dwDirOffset;
+ strcpy(plh.szNotes, szNotes);
+ file.write((char*)&plh, sizeof plh);
+
+ // recreate a directory and write it
+ PrefabHeader *ph = new PrefabHeader[Prefabs.GetCount()];
+ int iCur = 0;
+
+ POSITION p = Prefabs.GetHeadPosition();
+ while(p)
+ {
+ CPrefab *pPrefab = Prefabs.GetNext(p);
+
+ // setup this dir entry
+ ph[iCur].dwOffset = pPrefab->dwFileOffset;
+ ph[iCur].dwSize = pPrefab->dwFileSize;
+ V_strcpy_safe(ph[iCur].szName, pPrefab->GetName());
+ V_strcpy_safe(ph[iCur].szNotes, pPrefab->GetNotes());
+ ph[iCur].iType = pPrefab->GetType();
+
+ ++iCur; // increase current directory entry
+ }
+
+ // write directory
+ file.seekp(m_dwDirOffset);
+ file.write((char*)ph, sizeof(*ph) * Prefabs.GetCount());
+ file.close();
+
+ // re-open
+ m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
+ return 1;
+ }
+
+ if(pszFilename == NULL)
+ {
+ pszFilename = szFile;
+
+ if(m_strOpenFileName.IsEmpty())
+ {
+ char szNewFilename[MAX_PATH];
+ CHammer *pApp = (CHammer*) AfxGetApp();
+ pApp->GetDirectory(DIR_PREFABS, szNewFilename);
+
+ sprintf(szNewFilename + strlen(szNewFilename), "\\%s.ol", m_szName);
+
+ // make a name
+ m_strOpenFileName = szNewFilename;
+ }
+
+ strcpy(szFile, m_strOpenFileName);
+ }
+ else
+ {
+ strcpy(szFile, pszFilename);
+ SetNameFromFilename(pszFilename);
+ }
+
+ // open temp file to save to.. then delete & rename old one.
+ CString strTempFileName = "Temporary Prefab Library.$$$";
+ std::fstream file;
+ file.open(strTempFileName, std::ios::binary | std::ios::out);
+
+ // write string header
+ file << pLibHeader;
+
+ // write binary header
+ // save current position so we can seek back and rewrite it
+ DWORD dwBinaryHeaderOffset = file.tellp();
+ PrefabLibraryHeader plh;
+ plh.dwNumEntries = Prefabs.GetCount();
+ plh.fVersion = fLibVersion;
+ strcpy(plh.szNotes, szNotes);
+ file.write((char*)&plh, sizeof plh);
+
+ // allocate memory for directory
+ PrefabHeader *ph = new PrefabHeader[plh.dwNumEntries];
+ int iCur = 0;
+
+ char *pCopyBuf = new char[64000];
+
+ // write each prefab
+ POSITION p = Prefabs.GetHeadPosition();
+ while (p)
+ {
+ CPrefabRMF *pPrefab = (CPrefabRMF *)Prefabs.GetNext(p);
+
+ // setup this dir entry
+ ph[iCur].dwOffset = file.tellp();
+ V_strcpy_safe( ph[iCur].szName, pPrefab->GetName() );
+ V_strcpy_safe( ph[iCur].szNotes, pPrefab->GetNotes() );
+ ph[iCur].iType = pPrefab->GetType();
+
+ if(pPrefab->IsLoaded())
+ {
+ // it's loaded - save in native method
+ pPrefab->Save(file, CPrefab::lsUpdateFilePos);
+ }
+ else
+ {
+ // it's not loaded - save with quick method by copying
+ // bytes directly from the existing file
+ Assert(m_file.is_open());
+ m_file.seekg(pPrefab->dwFileOffset);
+ DWORD dwToRead = 64000, dwCopied = 0;
+ while(dwToRead == 64000)
+ {
+ if(dwCopied + dwToRead > pPrefab->dwFileSize)
+ dwToRead = pPrefab->dwFileSize - dwCopied;
+ m_file.read(pCopyBuf, dwToRead);
+ file.write(pCopyBuf, dwToRead);
+ dwCopied += dwToRead;
+ }
+ }
+
+ // set offset info HERE because we might use it above
+ pPrefab->dwFileOffset = ph[iCur].dwOffset;
+
+ // set size info
+ ph[iCur].dwSize = pPrefab->dwFileSize =
+ file.tellp() - (std::streamoff)ph[iCur].dwOffset;
+
+ ++iCur; // increase current directory entry
+ }
+
+ // delete copy buf
+ delete[] pCopyBuf;
+
+ // rewrite binary header
+ plh.dwDirOffset = m_dwDirOffset = file.tellp();
+ file.seekp(dwBinaryHeaderOffset);
+ file.write((char*)&plh, sizeof(plh));
+ file.seekp(0, std::ios::end);
+
+ // write directory
+ file.write((char*)ph, sizeof(*ph) * plh.dwNumEntries);
+ file.close(); // close temp file
+
+ // delete original and rename
+ m_file.close(); // might already be open.. might not.
+ remove(m_strOpenFileName);
+
+ m_strOpenFileName = szFile;
+ rename(strTempFileName, m_strOpenFileName);
+
+ // reopen original
+ m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: A library's name is based on its filename. We set the name here
+// and rename the file if it exists, then re-open it.
+// Input : pszName -
+// Output : Returns zero on error, nonzero on success.
+//-----------------------------------------------------------------------------
+int CPrefabLibraryRMF::SetName(LPCTSTR pszName)
+{
+ // set szName
+ strcpy(m_szName, pszName);
+
+ char szNewFilename[MAX_PATH];
+ CHammer *pApp = (CHammer*) AfxGetApp();
+ pApp->GetDirectory(DIR_PREFABS, szNewFilename);
+
+ sprintf(szNewFilename + strlen(szNewFilename), "\\%s.ol", pszName);
+
+ if(m_file.is_open())
+ {
+ // close it -
+ m_file.close();
+ }
+ else
+ {
+ // ensure destination name doesn't exist already -
+ if(GetFileAttributes(szNewFilename) != 0xFFFFFFFF)
+ return 0; // exists.
+ }
+
+ // rename and reopen
+ rename(m_strOpenFileName, szNewFilename);
+ m_strOpenFileName = szNewFilename;
+ m_file.open(m_strOpenFileName, std::ios::in | std::ios::binary);
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefabLibraryVMF::CPrefabLibraryVMF()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPrefabLibraryVMF::~CPrefabLibraryVMF()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns true if this prefab represents the given filename, false if not.
+// Input : szFilename - Path of a prefab library or folder.
+//-----------------------------------------------------------------------------
+bool CPrefabLibraryVMF::IsFile(const char *szFilename)
+{
+ return(strcmpi(m_szFolderName, szFilename) == 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszFilename -
+// Output : int
+//-----------------------------------------------------------------------------
+int CPrefabLibraryVMF::Load(LPCTSTR pszFilename)
+{
+ FreePrefabs();
+
+ SetNameFromFilename(pszFilename);
+ strcpy(m_szFolderName, pszFilename);
+
+ m_eType = LibType_HalfLife2;
+
+ // dvs: new prefab libs have no notes! who cares?
+
+ //
+ // Read the prefabs - they are stored as individual VMF files.
+ //
+ char szDir[MAX_PATH];
+ strcpy(szDir, pszFilename);
+ strcat(szDir, "\\*.vmf");
+
+ WIN32_FIND_DATA fd;
+ HANDLE hnd = FindFirstFile(szDir, &fd);
+ if (hnd == INVALID_HANDLE_VALUE)
+ {
+ // No prefabs in this folder.
+ return(1);
+ }
+
+ *strrchr(szDir, '*') = '\0';
+
+ do
+ {
+ if (fd.cFileName[0] != '.')
+ {
+ //
+ // Build the full path to the prefab file.
+ //
+ char szFile[MAX_PATH];
+ strcpy(szFile, szDir);
+ strcat(szFile, fd.cFileName);
+
+ CPrefabVMF *pPrefab = new CPrefabVMF;
+ pPrefab->SetFilename(szFile);
+
+ Add(pPrefab);
+ }
+ } while (FindNextFile(hnd, &fd));
+
+ FindClose(hnd);
+
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes this prefab library from disk.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CPrefabLibraryVMF::DeleteFile(void)
+{
+ // dvs: can't remove the prefab folder yet
+ return(false);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pszFilename -
+// bIndexOnly -
+// Output : int
+//-----------------------------------------------------------------------------
+int CPrefabLibraryVMF::Save(LPCTSTR pszFilename, BOOL bIndexOnly)
+{
+ return 1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Set's the library's name by renaming the folder.
+// Input : pszName -
+// Output : Returns zero on error, nonzero on success.
+//-----------------------------------------------------------------------------
+int CPrefabLibraryVMF::SetName(LPCTSTR pszName)
+{
+ // dvs: rename the folder - or maybe don't implement for VMF prefabs
+ strcpy(m_szName, pszName);
+ return 1;
+}
+
+