From 13f100fbfcaab43e61325e80ceb38e7dca92d054 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Sat, 1 Apr 2023 20:46:51 +0800 Subject: [PATCH] Initial commit: the original DAT2 v2.32 --- dat2.exe | Bin 0 -> 282624 bytes src/DatFile1.cpp | 991 ++++++++++++++++++++++++++++++++++++++++++++ src/DatFile1.h | 91 ++++ src/DatFile2.cpp | 868 ++++++++++++++++++++++++++++++++++++++ src/DatFile2.h | 90 ++++ src/DatFileBase.cpp | 163 ++++++++ src/DatFileBase.h | 71 ++++ src/LZ77C.cpp | 304 ++++++++++++++ src/LZ77C.h | 7 + src/OnAdd.cpp | 98 +++++ src/OnDelete.cpp | 31 ++ src/OnExtract.cpp | 69 +++ src/OnList.cpp | 28 ++ src/OnShrink.cpp | 31 ++ src/Resource.h | 15 + src/Util.cpp | 177 ++++++++ src/Util.h | 24 ++ src/XGetopt.cpp | 219 ++++++++++ src/XGetopt.h | 23 + src/dat2.cpp | 320 ++++++++++++++ src/dat2.h | 31 ++ src/dat2.rc | 114 +++++ src/dat2.sln | 20 + src/dat2.vcproj | 310 ++++++++++++++ src/stdafx.cpp | 8 + src/stdafx.h | 19 + 26 files changed, 4122 insertions(+) create mode 100644 dat2.exe create mode 100644 src/DatFile1.cpp create mode 100644 src/DatFile1.h create mode 100644 src/DatFile2.cpp create mode 100644 src/DatFile2.h create mode 100644 src/DatFileBase.cpp create mode 100644 src/DatFileBase.h create mode 100644 src/LZ77C.cpp create mode 100644 src/LZ77C.h create mode 100644 src/OnAdd.cpp create mode 100644 src/OnDelete.cpp create mode 100644 src/OnExtract.cpp create mode 100644 src/OnList.cpp create mode 100644 src/OnShrink.cpp create mode 100644 src/Resource.h create mode 100644 src/Util.cpp create mode 100644 src/Util.h create mode 100644 src/XGetopt.cpp create mode 100644 src/XGetopt.h create mode 100644 src/dat2.cpp create mode 100644 src/dat2.h create mode 100644 src/dat2.rc create mode 100644 src/dat2.sln create mode 100644 src/dat2.vcproj create mode 100644 src/stdafx.cpp create mode 100644 src/stdafx.h diff --git a/dat2.exe b/dat2.exe new file mode 100644 index 0000000000000000000000000000000000000000..0b31f3d94fa897888629401717838fe61a28e98d GIT binary patch literal 282624 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 literal 0 HcmV?d00001 diff --git a/src/DatFile1.cpp b/src/DatFile1.cpp new file mode 100644 index 0000000..e6981b6 --- /dev/null +++ b/src/DatFile1.cpp @@ -0,0 +1,991 @@ +// DatFile1.cpp : implementation file +// + +#include "stdafx.h" +#include "DatFile1.h" +#include "LZ77C.h" +#include "Util.h" + + +#if defined(_UNICODE) || defined(UNICODE) +#error UNICODE not supported +#endif + + +// CFileList1::CFileTreeItem +CFileList1::CFileTreeItem::CFileTreeItem() +{ +} + +CFileList1::CFileTreeItem::CFileTreeItem(const CFileList1::CFileTreeItem& item) +{ + m_strDirectoryName = item.m_strDirectoryName; + m_FileList.Copy(item.m_FileList); +} + +CFileList1::CFileTreeItem& CFileList1::CFileTreeItem::operator = (const CFileList1::CFileTreeItem& item) +{ + if (&item != this) { + m_strDirectoryName = item.m_strDirectoryName; + m_FileList.Copy(item.m_FileList); + } + + return (*this); +} + +// CFileList1 +IMPLEMENT_DYNAMIC(CFileList1, CObject) + +CFileList1::CFileList1() +{ +} + +CFileList1::~CFileList1() +{ +} + +void CFileList1::Serialize(CArchive& ar) +{ + if (ar.IsStoring()) { + // Directories count + DWORD dwDirCount = DWORD(m_FileTree.GetSize()); + WriteMSBDWord(ar, dwDirCount); + + // Unknown fields + WriteMSBDWord(ar, dwDirCount); + WriteMSBDWord(ar, 0); + WriteMSBDWord(ar, 0); + + // Directories names + CString strDirName; + + for(DWORD i = 0; i < dwDirCount; i++) { + strDirName = m_FileTree[i].m_strDirectoryName; + + if (strDirName.IsEmpty()) { + strDirName = "."; + } + + WriteString(ar, strDirName); + } + + // Directories descriptors + for(DWORD i = 0; i < dwDirCount; i++) { + // FileCount + DWORD dwFileCount = DWORD(m_FileTree[i].m_FileList.GetSize()); + + WriteMSBDWord(ar, dwFileCount); + + // Unknown fields + WriteMSBDWord(ar, dwFileCount); + WriteMSBDWord(ar, 16); + WriteMSBDWord(ar, 0); + + // File descriptors + CString strFileName; + CFileDescriptorBase descriptor; + DWORD dwFlags; + DWORD dwPackedFileLength; + + for(DWORD j = 0; j < dwFileCount; j++) { + descriptor = m_FileTree[i].m_FileList[j]; + strFileName = ExtractFileName(descriptor.m_strFileName); + + WriteString(ar, strFileName); + + if (descriptor.m_nType == 1) { + dwFlags = 0x40; + dwPackedFileLength = descriptor.m_dwPackedFileLength; + } + else { + dwFlags = 0x20; + dwPackedFileLength = 0; + } + + WriteMSBDWord(ar, dwFlags); + + WriteMSBDWord(ar, descriptor.m_dwOffset); + WriteMSBDWord(ar, descriptor.m_dwFileLength); + WriteMSBDWord(ar, dwPackedFileLength); + } + } + } + else { + m_FileTree.RemoveAll(); + + // Directories count + DWORD dwDirCount; + + if (ReadMSBDWord(ar, dwDirCount) != sizeof(DWORD)) { + AfxThrowUserException(); + } + + // Unknown fields + DWORD dwUnknown; + + for(DWORD u = 0; u < 3; u++) { + if (ReadMSBDWord(ar, dwUnknown) != sizeof(DWORD)) { + AfxThrowUserException(); + } + } + + // Directories names + CFileTreeItem directory; + CString strDirName; + + + for(DWORD i = 0; i < dwDirCount; i++) { + if (!ReadString(ar, strDirName)) { + AfxThrowUserException(); + } + + if (strDirName == ".") { + strDirName = ""; + } + + directory.m_strDirectoryName = strDirName; + m_FileTree.Add(directory); + } + + // Directories descriptors + for(DWORD i = 0; i < dwDirCount; i++) { + // FileCount + DWORD dwFileCount; + + if (ReadMSBDWord(ar, dwFileCount) != sizeof(DWORD)) { + AfxThrowUserException(); + } + + // Unknown fields + for(DWORD u = 0; u < 3; u++) { + if (ReadMSBDWord(ar, dwUnknown) != sizeof(DWORD)) { + AfxThrowUserException(); + } + } + + // File descriptors + CFileDescriptorBase descriptor; + DWORD dwFlags; + + for(DWORD j = 0; j < dwFileCount; j++) { + if (!ReadString(ar, descriptor.m_strFileName)) { + AfxThrowUserException(); + } + + if (ReadMSBDWord(ar, dwFlags) != sizeof(DWORD)) { + AfxThrowUserException(); + } + + if (ReadMSBDWord(ar, descriptor.m_dwOffset) != sizeof(DWORD)) { + AfxThrowUserException(); + } + + if (ReadMSBDWord(ar, descriptor.m_dwFileLength) != sizeof(DWORD)) { + AfxThrowUserException(); + } + + if (ReadMSBDWord(ar, descriptor.m_dwPackedFileLength) != sizeof(DWORD)) { + AfxThrowUserException(); + } + + if (dwFlags == 0x40) { + descriptor.m_nType = 1; + } + else { + descriptor.m_nType = 0; + descriptor.m_dwPackedFileLength = descriptor.m_dwFileLength; + } + + if (!m_FileTree[i].m_strDirectoryName.IsEmpty()) { + descriptor.m_strFileName = m_FileTree[i].m_strDirectoryName + "\\" + descriptor.m_strFileName; + } + + m_FileTree[i].m_FileList.Add(descriptor); + } + } + } +} + +INT_PTR CFileList1::GetSize() const +{ + INT_PTR nResult = 0; + + for(INT_PTR i = 0; i < m_FileTree.GetSize(); i++) { + nResult += m_FileTree[i].m_FileList.GetSize(); + } + + return nResult; +} + +DWORD CFileList1::GetLength() +{ + DWORD dwResult = sizeof(DWORD) * 4; + CString strDirectoryName; + + for(INT_PTR i = 0; i < m_FileTree.GetSize(); i++) { + strDirectoryName = m_FileTree[i].m_strDirectoryName; + + if (strDirectoryName.IsEmpty()) { + strDirectoryName = "."; + } + + dwResult += strDirectoryName.GetLength() + 1; + dwResult += sizeof(DWORD) * 4; + + for(INT_PTR j = 0; j < m_FileTree[i].m_FileList.GetSize(); j++) { + dwResult += ExtractFileName(m_FileTree[i].m_FileList[j].m_strFileName).GetLength() + 1; + dwResult += sizeof(DWORD) * 4; + } + } + + return dwResult; +} + + +INT_PTR CFileList1::Add(const CFileDescriptorBase& newElement) +{ + CString strDirectoryName = ExtractFilePath(newElement.m_strFileName, FALSE); + CString strFileName = ExtractFileName(newElement.m_strFileName); + + if (!strDirectoryName.IsEmpty()) { + strDirectoryName = strDirectoryName.Left(strDirectoryName.GetLength() - 1); + } + + // ========= Directory ========= + INT_PTR nDirectoryIndex; + CFileTreeItem directory; + + directory.m_strDirectoryName = strDirectoryName; + + // No elements + if (m_FileTree.IsEmpty()) { + nDirectoryIndex = m_FileTree.Add(directory); + } + else if (MakeLower(strDirectoryName) < + MakeLower(m_FileTree[0].m_strDirectoryName)) { + // Less than first + m_FileTree.InsertAt(0, directory); + nDirectoryIndex = 0; + } + else if (MakeLower(strDirectoryName) > + MakeLower(m_FileTree[m_FileTree.GetUpperBound()].m_strDirectoryName)) { + // Greater than last + nDirectoryIndex = m_FileTree.Add(directory); + } + else if (MakeLower(strDirectoryName) == + MakeLower(m_FileTree[0].m_strDirectoryName)) { + // Equal first + nDirectoryIndex = 0; + } + else if (MakeLower(strDirectoryName) == + MakeLower(m_FileTree[m_FileTree.GetUpperBound()].m_strDirectoryName)) { + // Equal last + nDirectoryIndex = m_FileTree.GetUpperBound(); + } + else { + // Other + BOOL bNeedInsert = TRUE; + INT_PTR nLeft = 0; + INT_PTR nRight = m_FileTree.GetUpperBound(); + INT_PTR nCurrent; + + while(nRight - nLeft > 1) { + nCurrent = (nRight + nLeft) >> 1; // divide by 2 + + if (MakeLower(strDirectoryName) == MakeLower(m_FileTree[nCurrent].m_strDirectoryName)) { + bNeedInsert = FALSE; + break; + } + else if (MakeLower(strDirectoryName) < MakeLower(m_FileTree[nCurrent].m_strDirectoryName)) { + nRight = nCurrent; + } + else { + nLeft = nCurrent; + } + } + + if (bNeedInsert) { + m_FileTree.InsertAt(nLeft + 1, directory); + nDirectoryIndex = nLeft + 1; + } + else { + nDirectoryIndex = nCurrent; + } + } + + // ========= File ========= + INT_PTR nFileIndex; + + + if (m_FileTree[nDirectoryIndex].m_FileList.IsEmpty()) { + // No elements + nFileIndex = m_FileTree[nDirectoryIndex].m_FileList.Add(newElement); + } + else if (MakeLower(newElement.m_strFileName) < + MakeLower(m_FileTree[nDirectoryIndex].m_FileList[0].m_strFileName)) { + // Less than first + m_FileTree[nDirectoryIndex].m_FileList.InsertAt(0, newElement); + nFileIndex = 0; + } + else if (MakeLower(newElement.m_strFileName) > + MakeLower(m_FileTree[nDirectoryIndex].m_FileList[m_FileTree[nDirectoryIndex].m_FileList.GetUpperBound()].m_strFileName)) { + // Greater than last + nFileIndex = m_FileTree[nDirectoryIndex].m_FileList.Add(newElement); + } + else if (MakeLower(newElement.m_strFileName) == + MakeLower(m_FileTree[nDirectoryIndex].m_FileList[0].m_strFileName)) { + // Equal first + m_FileTree[nDirectoryIndex].m_FileList[0] = newElement; + nFileIndex = 0; + } + else if (MakeLower(newElement.m_strFileName) == + MakeLower(m_FileTree[nDirectoryIndex].m_FileList[m_FileTree[nDirectoryIndex].m_FileList.GetUpperBound()].m_strFileName)) { + // Equal last + m_FileTree[nDirectoryIndex].m_FileList[m_FileTree[nDirectoryIndex].m_FileList.GetUpperBound()] = newElement; + nFileIndex = m_FileTree[nDirectoryIndex].m_FileList.GetUpperBound(); + } + else { + // Other + BOOL bNeedInsert = TRUE; + INT_PTR nLeft = 0; + INT_PTR nRight = m_FileTree[nDirectoryIndex].m_FileList.GetUpperBound(); + INT_PTR nCurrent; + + while(nRight - nLeft > 1) { + nCurrent = (nRight + nLeft) >> 1; // divide by 2 + + if (MakeLower(newElement.m_strFileName) == MakeLower(m_FileTree[nDirectoryIndex].m_FileList[nCurrent].m_strFileName)) { + m_FileTree[nDirectoryIndex].m_FileList[nCurrent] = newElement; + bNeedInsert = FALSE; + break; + } + else if (MakeLower(newElement.m_strFileName) < MakeLower(m_FileTree[nDirectoryIndex].m_FileList[nCurrent].m_strFileName)) { + nRight = nCurrent; + } + else { + nLeft = nCurrent; + } + } + + if (bNeedInsert) { + m_FileTree[nDirectoryIndex].m_FileList.InsertAt(nLeft + 1, newElement); + nFileIndex = nLeft + 1; + } + else { + nFileIndex = nCurrent; + } + } + + INT_PTR nResult = 0; + + for(INT_PTR i = 0; i < nDirectoryIndex; i++) { + nResult += m_FileTree[nDirectoryIndex].m_FileList.GetSize(); + } + + nResult += nFileIndex; + + return nResult; +} + +void CFileList1::RemoveAt(INT_PTR nIndex) +{ + ASSERT(nIndex >= 0); + ASSERT(nIndex < GetSize()); + + for(INT_PTR nDirectoryIndex = 0; nDirectoryIndex < m_FileTree.GetSize(); nDirectoryIndex++) { + if (nIndex < m_FileTree[nDirectoryIndex].m_FileList.GetSize()) { + m_FileTree[nDirectoryIndex].m_FileList.RemoveAt(nIndex); + + if (m_FileTree[nDirectoryIndex].m_FileList.IsEmpty()) { + m_FileTree.RemoveAt(nDirectoryIndex); + } + + break; + } + else { + nIndex -= m_FileTree[nDirectoryIndex].m_FileList.GetSize(); + } + } +} + +CFileDescriptorBase& CFileList1::operator [] (INT_PTR nIndex) +{ + ASSERT(nIndex >= 0); + ASSERT(nIndex < GetSize()); + + for(INT_PTR nDirectoryIndex = 0; nDirectoryIndex < m_FileTree.GetSize(); nDirectoryIndex++) { + if (nIndex < m_FileTree[nDirectoryIndex].m_FileList.GetSize()) { + return m_FileTree[nDirectoryIndex].m_FileList[nIndex]; + } + else { + nIndex -= m_FileTree[nDirectoryIndex].m_FileList.GetSize(); + } + } + + // Fake return (avoid warning) + return m_FileTree[0].m_FileList[0]; +} + +CFileDescriptorBase CFileList1::operator [] (INT_PTR nIndex) const +{ + ASSERT(nIndex >= 0); + ASSERT(nIndex < GetSize()); + + for(INT_PTR nDirectoryIndex = 0; nDirectoryIndex < m_FileTree.GetSize(); nDirectoryIndex++) { + if (nIndex < m_FileTree[nDirectoryIndex].m_FileList.GetSize()) { + return m_FileTree[nDirectoryIndex].m_FileList[nIndex]; + } + else { + nIndex -= m_FileTree[nDirectoryIndex].m_FileList.GetSize(); + } + } + + // Fake return (avoid warning) + return m_FileTree[0].m_FileList[0]; +} + +#ifdef _DEBUG +void CFileList1::AssertValid() const +{ + CObject::AssertValid(); + m_FileTree.AssertValid(); + + for(INT_PTR i = 0; i < GetSize(); i++) { + (operator [] (i)).AssertValid(); + } +} + +template<> +void AFXAPI DumpElements(CDumpContext& dc, const CFileDescriptorBase* pElements, INT_PTR nCount) +{ + ASSERT(nCount == 0 || + AfxIsValidAddress(pElements, (size_t)nCount * sizeof(CFileDescriptorBase), FALSE)); + + for(INT_PTR i = 0; i < nCount; i++) { + dc << "Element " << i << ":\n"; + pElements[i].Dump(dc); + } +} + +void CFileList1::Dump(CDumpContext& dc) const +{ + CObject::Dump(dc); + dc.SetDepth(1); + m_FileTree.Dump(dc); +} +#endif + + +// CDatFile1 +IMPLEMENT_DYNAMIC(CDatFile1, CObject) + +CDatFile1::CDatFile1() +{ +} + +CDatFile1::~CDatFile1() +{ + Close(); +} + +BOOL CDatFile1::Open(LPCTSTR lpszFileName, UINT nOpenFlags) +{ + if (!m_Dat.Open(lpszFileName, nOpenFlags)) { + return FALSE; + } + + if (m_Dat.GetLength() == 0) { + return TRUE; + } + + CArchive arFileList(&m_Dat, CArchive::load); + + TRY { + m_FileList.Serialize(arFileList); + } + + CATCH(CUserException, e) { + return FALSE; + } + + END_CATCH + + return TRUE; +} + +void CDatFile1::Close() +{ + Flush(); + + if (m_Dat.m_hFile != CFile::hFileNull) { + m_Dat.Close(); + } +} + +void CDatFile1::Flush() +{ + if (m_bNeedFlush) { + FreeSpaceForCatalog(); + m_Dat.SeekToBegin(); + CArchive arFileList(&m_Dat, CArchive::store); + m_FileList.Serialize(arFileList); + arFileList.Flush(); + m_bNeedFlush = FALSE; + } +} + +INT_PTR CDatFile1::GetFileCount() +{ + return m_FileList.GetSize(); +} + +CFileDescriptorBase CDatFile1::operator [](INT_PTR nIndex) const +{ + return m_FileList[nIndex]; +} + +INT_PTR CDatFile1::FindNext() +{ + for(++m_nCurrent; m_nCurrent < m_FileList.GetSize(); m_nCurrent++) { + if (MatchPattern(m_FileList[m_nCurrent].m_strFileName, m_strPattern, FALSE)) { + break; + } + } + + if (m_nCurrent == m_FileList.GetSize()) { + m_nCurrent = -1; + } + + return m_nCurrent; +} + +BOOL CDatFile1::Inflate(CArchive& ar) +{ + if (m_nCurrent == -1) { + return FALSE; + } + + CFileDescriptorBase descriptor = m_FileList[m_nCurrent]; + + m_Dat.Seek(descriptor.m_dwOffset, CFile::begin); + + const DWORD c_dwBufferSize = 65536; + BYTE buffer[c_dwBufferSize]; + + DWORD dwBytesLeft = descriptor.m_dwPackedFileLength; + DWORD dwBytesToRead; + DWORD dwRead; + DWORD dwBytesOut = 0; + + // Uncompressed file + if (descriptor.m_nType == 0) { + do { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + dwRead = m_Dat.Read(buffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + return FALSE; + } + + ar.Write(buffer, dwBytesToRead); + dwBytesOut += dwRead; + } while((dwBytesLeft -= dwRead ) > 0); + + return TRUE; + } + + BOOL bResult = TRUE; + BOOL bEndLoop = FALSE; + + do { + WORD wBlockDescriptor; + + if (ReadMSBWord(m_Dat, wBlockDescriptor) != sizeof(WORD)) { + bResult = FALSE; + break; + } + + dwBytesToRead = wBlockDescriptor & 0x7FFF; + + dwRead = m_Dat.Read(buffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + bResult = FALSE; + break; + } + + if (wBlockDescriptor & 0x8000) { + // Uncompressed block + ar.Write(buffer, dwRead); + } + else { + // Compressed block + LZSSDecodeBuffer(buffer, dwRead, ar); + } + } while((dwBytesLeft -= dwRead + sizeof(WORD)) > 0); + + return bResult; +} + +BOOL CDatFile1::Deflate(CArchive& ar, DWORD dwLength, LPCTSTR lpszName, int level) +{ + ULONGLONG ullDatLength = m_Dat.SeekToEnd(); + + // File descriptor + CFileDescriptorBase descriptor; + descriptor.m_dwFileLength = dwLength; + descriptor.m_strFileName = lpszName; + descriptor.m_dwOffset = DWORD(ullDatLength); + + // Buffers + const DWORD c_dwBufferSize = 65536; + BYTE buffer[c_dwBufferSize]; +// BYTE outBuffer[c_dwBufferSize]; + + DWORD dwBytesLeft = dwLength; + DWORD dwBytesToRead; + DWORD dwRead; + DWORD dwBytesOut = 0; + + // Flags + BOOL bResult = TRUE; + BOOL bUseInputArchive = TRUE; + + // Temporary file + char lpszTempFileName[MAX_PATH]; + CFile fileTemp; + BOOL bDeleteTempFile = FALSE; + + // Try compress file + if (level != 0) { + // Save position in input archive + ar.Flush(); + ULONGLONG ullArPosition = ar.GetFile()->GetPosition(); + + // Create temporary file + char lpszTempPath[MAX_PATH - 14]; + HANDLE hTempFile; + + GetTempPath(MAX_PATH - 14, lpszTempPath); + GetTempFileName(lpszTempPath, "DAT", 0, lpszTempFileName); + + hTempFile = ::CreateFile(lpszTempFileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY, + NULL); + + if (hTempFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + + fileTemp.m_hFile = hTempFile; + bDeleteTempFile = TRUE; + + // Deflate file + const DWORD c_dwBlockSize = 0x4000; + WORD wBlockDescriptor = 0; + ULONGLONG ullBlockDescPos; + + do { + // Read block of data + dwBytesToRead = (dwBytesLeft < c_dwBlockSize) ? dwBytesLeft : c_dwBlockSize; + + dwRead = ar.Read(buffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + bResult = FALSE; + break; + } + + // Write descriptor placeholder + ullBlockDescPos = fileTemp.GetPosition(); + WriteMSBWord(fileTemp, wBlockDescriptor); + + // Compress block + LZSSEncodeBuffer(buffer, dwRead, fileTemp); + + // Check length of compressed block + DWORD dwBlockLength = DWORD(fileTemp.GetPosition()) - DWORD(ullBlockDescPos) - sizeof(WORD); + + // More than uncompressed + if (dwBlockLength > dwRead) { + fileTemp.SetLength(ullBlockDescPos + sizeof(WORD)); + fileTemp.SeekToEnd(); + fileTemp.Write(buffer, dwRead); + wBlockDescriptor = WORD(dwRead) | 0x8000; + } + else { + wBlockDescriptor = WORD(dwBlockLength); + } + + // Patch descriptor + fileTemp.Seek(ullBlockDescPos, CFile::begin); + WriteMSBWord(fileTemp, wBlockDescriptor); + fileTemp.SeekToEnd(); + } while((dwBytesLeft -= dwRead) > 0); + + fileTemp.SeekToBegin(); + + // Check compression result + if (!bResult) { + fileTemp.Close(); + CFile::Remove(lpszTempFileName); + return FALSE; + } + + // Check length + ULONGLONG ullTempFileLength = fileTemp.GetLength(); + + if (ullTempFileLength < dwLength) { + bUseInputArchive = FALSE; + descriptor.m_dwPackedFileLength = DWORD(ullTempFileLength); + descriptor.m_nType = 1; + dwBytesLeft = DWORD(ullTempFileLength); + } + else { + ar.Flush(); + ar.GetFile()->Seek(ullArPosition, CFile::begin); + descriptor.m_dwPackedFileLength = dwLength; + descriptor.m_nType = 0; + dwBytesLeft = dwLength; + } + } + else { + descriptor.m_dwPackedFileLength = dwLength; + descriptor.m_nType = 0; + } + + // Set source archive + CArchive arTemp(&fileTemp, CArchive::load); // Temporary archive + CArchive* pArSource; + + if (bUseInputArchive) { + pArSource = &ar; + } + else { + pArSource = &arTemp; + } + + // Write data + TRY { + m_Dat.SeekToEnd(); + + do { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + dwRead = pArSource->Read(buffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + bResult = FALSE; + break; + } + + m_Dat.Write(buffer, dwBytesToRead); + dwBytesOut += dwRead; + } while((dwBytesLeft -= dwRead ) > 0); + + if (bResult) { + // Add descriptor + m_FileList.Add(descriptor); + m_bNeedFlush = TRUE; + } + else { + // Restore dat-file length on error + m_Dat.SetLength(ullDatLength); + } + + // Destroy temporary file + if (bDeleteTempFile) { + arTemp.Abort(); + fileTemp.Close(); + CFile::Remove(lpszTempFileName); + } + + return bResult; + } + + CATCH_ALL(e) { + m_Dat.SetLength(ullDatLength); + THROW_LAST(); + } + + END_CATCH_ALL +} + +BOOL CDatFile1::Delete() +{ + if (m_nCurrent == -1) { + return FALSE; + } + + m_FileList.RemoveAt(m_nCurrent); + m_nCurrent = -1; + m_bNeedFlush = TRUE; + + return TRUE; +} + + +CDatFile1* g_pDatFile1ForSort; + +int CompareDescriptorIndex1(const void* pIndex1, const void* pIndex2) +{ + INT_PTR nIndex1 = *((INT_PTR*)pIndex1); + INT_PTR nIndex2 = *((INT_PTR*)pIndex2); + + CFileDescriptorBase descriptor1; + CFileDescriptorBase descriptor2; + + descriptor1 = (*g_pDatFile1ForSort)[nIndex1]; + descriptor2 = (*g_pDatFile1ForSort)[nIndex2]; + + if (descriptor1.m_dwOffset < descriptor2.m_dwOffset) { + return -1; + } + else if (descriptor1.m_dwOffset > descriptor2.m_dwOffset) { + return 1; + } + else { + return 0; + } +} + +BOOL CDatFile1::Shrink(void (*pCallback)(INT_PTR nIndex)) +{ + if (m_Dat.GetLength() == 0) { + return FALSE; + } + + // Sort files by offset + INT_PTR nFileCount = GetFileCount(); + INT_PTR* pIndexArray = new INT_PTR[nFileCount]; + + if (pIndexArray == NULL) { + return FALSE; + } + + for(INT_PTR i = 0; i < nFileCount; i++) { + pIndexArray[i] = i; + } + + g_pDatFile1ForSort = this; + qsort(pIndexArray, nFileCount, sizeof(INT_PTR), CompareDescriptorIndex1); + + // Move files + const DWORD c_dwBufferSize = 65536; + BYTE buffer[c_dwBufferSize]; + + DWORD dwWritePos = m_FileList.GetLength(); + DWORD dwShift; + DWORD dwBytesToRead; + DWORD dwBytesLeft; + DWORD dwReadPos; + DWORD dwRead; + + CFileDescriptorBase descriptor; + + for(INT_PTR i = 0; i < nFileCount; i++) { + descriptor = (*this)[pIndexArray[i]]; + dwShift = descriptor.m_dwOffset - dwWritePos; + + if (dwShift > 0) { + m_bNeedFlush = TRUE; + + if (pCallback) { + pCallback(pIndexArray[i]); + } + + dwBytesLeft = descriptor.m_dwPackedFileLength; + dwReadPos = descriptor.m_dwOffset; + + descriptor.m_dwOffset = dwWritePos; + + do { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + + m_Dat.Seek(dwReadPos, CFile::begin); + dwRead = m_Dat.Read(buffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + delete [] pIndexArray; + return FALSE; + } + + m_Dat.Seek(dwWritePos, CFile::begin); + m_Dat.Write(buffer, dwRead); + dwWritePos += dwRead; + dwReadPos += dwRead; + } while((dwBytesLeft -= dwRead ) > 0); + + // Patch offsets + m_FileList[pIndexArray[i]].m_dwOffset = descriptor.m_dwOffset; + } + else { + dwWritePos += descriptor.m_dwPackedFileLength; + } + } + + m_Dat.SetLength(dwWritePos); + delete [] pIndexArray; + + Flush(); + return TRUE; +} + +void CDatFile1::FreeSpaceForCatalog() +{ + if (m_FileList.GetSize() != 0) { + DWORD dwCatalogSize = m_FileList.GetLength(); + + // Find offset + CFileDescriptorBase descriptor; + DWORD dwMinimalOffset = m_FileList[0].m_dwOffset; + + for(INT_PTR i = 1; i < m_FileList.GetSize(); i++) { + descriptor = m_FileList[i]; + + if (dwMinimalOffset > descriptor.m_dwOffset) { + dwMinimalOffset = descriptor.m_dwOffset; + } + } + + // Free space + if (dwMinimalOffset < dwCatalogSize) { + printf("Freeing space for catalog...\n"); + DWORD dwShift = dwCatalogSize - dwMinimalOffset; + DWORD dwBytesLeft = DWORD(m_Dat.GetLength()) - dwMinimalOffset; + DWORD dwTotalBytesToMove = dwBytesLeft; + DWORD dwReadPos = DWORD(m_Dat.GetLength()); + DWORD dwWritePos; + + const DWORD c_dwBufferSize = 65536; + BYTE buffer[c_dwBufferSize]; + DWORD dwBytesToRead; + DWORD dwRead; + + do { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + dwReadPos -= dwBytesToRead; + dwWritePos = dwReadPos + dwShift; + + m_Dat.Seek(dwReadPos, CFile::begin); + dwRead = m_Dat.Read(buffer, dwBytesToRead); + + m_Dat.Seek(dwWritePos, CFile::begin); + m_Dat.Write(buffer, dwRead); + + dwBytesLeft -= dwRead; + printf("Moved: %d of %d byte(s)\r", dwTotalBytesToMove - dwBytesLeft, dwTotalBytesToMove); + } while(dwBytesLeft > 0); + + // Patch offsets + for(INT_PTR i = 0; i < m_FileList.GetSize(); i++) { + m_FileList[i].m_dwOffset += dwShift; + } + } + + printf("\nSpace are freed.\n"); + } +} diff --git a/src/DatFile1.h b/src/DatFile1.h new file mode 100644 index 0000000..325880b --- /dev/null +++ b/src/DatFile1.h @@ -0,0 +1,91 @@ +#pragma once + +#include "DatFileBase.h" + +// CFileList1 +class CFileList1 : public CObject { +public: + CFileList1(); + virtual ~CFileList1(); + + DECLARE_DYNAMIC(CFileList1) + + virtual void Serialize(CArchive& ar); + INT_PTR GetSize() const; + + DWORD GetLength(); + + INT_PTR Add(const CFileDescriptorBase& newElement); + void RemoveAt(INT_PTR nIndex); + + CFileDescriptorBase& operator [] (INT_PTR nIndex); + CFileDescriptorBase operator [] (INT_PTR nIndex) const; + +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +private: + // Assignment and copy not allowed + CFileList1(const CFileList1&); + CFileList1& operator = (const CFileList1&); + +private: + // CFileDescriptorBaseArray + typedef CArray CFileDescriptorBaseArray; + + // CFileTreeItem + class CFileTreeItem { + public: + CFileTreeItem(); + CFileTreeItem(const CFileTreeItem& item); + + public: + CFileTreeItem& operator = (const CFileTreeItem& item); + + public: + CString m_strDirectoryName; + CFileDescriptorBaseArray m_FileList; + }; + + // CFileTree + typedef CArray CFileTree; + + CFileTree m_FileTree; +}; + +// CDatFile1 +class CDatFile1 : public CDatFileBase { +public: + CDatFile1(); + virtual ~CDatFile1(); + + DECLARE_DYNAMIC(CDatFile1) + + virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags); + virtual void Close(); + virtual void Flush(); + + virtual INT_PTR GetFileCount(); + virtual CFileDescriptorBase operator [] (INT_PTR nIndex) const; + + virtual INT_PTR FindNext(); + + virtual BOOL Inflate(CArchive& ar); + virtual BOOL Deflate(CArchive& ar, DWORD dwLength, LPCTSTR lpszName, int level); + virtual BOOL Delete(); + virtual BOOL Shrink(void (*pCallback)(INT_PTR nIndex)); + +private: + void FreeSpaceForCatalog(); + +private: + // Restricted operations + CDatFile1(const CDatFile1&); + CDatFile1& operator = (const CDatFile1&); + virtual void Serialize(CArchive&) {}; + +private: + CFileList1 m_FileList; +}; diff --git a/src/DatFile2.cpp b/src/DatFile2.cpp new file mode 100644 index 0000000..2538107 --- /dev/null +++ b/src/DatFile2.cpp @@ -0,0 +1,868 @@ +// DatFile2.cpp : implementation file +// + +#include "stdafx.h" +#include "DatFile2.h" + +#include + +#if defined(_UNICODE) || defined(UNICODE) +#error UNICODE not supported +#endif + + +// CFileDescriptor2 +IMPLEMENT_DYNAMIC(CFileDescriptor2, CFileDescriptorBase) + +CFileDescriptor2::CFileDescriptor2() +{ +} + +CFileDescriptor2::CFileDescriptor2(const CFileDescriptor2& item) : + CFileDescriptorBase(item) +{ +} + +CFileDescriptor2::~CFileDescriptor2() +{ +} + +CFileDescriptor2& CFileDescriptor2::operator = (const CFileDescriptor2& item) +{ + CFileDescriptorBase::operator = (item); + return (*this); +} + +void CFileDescriptor2::Serialize(CArchive& ar) +{ + if (ar.IsStoring()) { + ASSERT(!m_strFileName.IsEmpty()); + + DWORD dwFileNameLength = m_strFileName.GetLength(); + + ar.Write(&dwFileNameLength, sizeof(dwFileNameLength)); + ar.WriteString(m_strFileName); + ar.Write(&m_nType, sizeof(m_nType)); + ar.Write(&m_dwFileLength, sizeof(m_dwFileLength)); + ar.Write(&m_dwPackedFileLength, sizeof(m_dwPackedFileLength)); + ar.Write(&m_dwOffset, sizeof(m_dwOffset)); + } + else { + DWORD dwFileNameLength; + LPTSTR lpszFileName; + + ar.Read(&dwFileNameLength, sizeof(dwFileNameLength)); + lpszFileName = m_strFileName.GetBufferSetLength(dwFileNameLength); + ar.Read(lpszFileName, dwFileNameLength); + m_strFileName.ReleaseBufferSetLength(dwFileNameLength); + + ar.Read(&m_nType, sizeof(m_nType)); + ar.Read(&m_dwFileLength, sizeof(m_dwFileLength)); + ar.Read(&m_dwPackedFileLength, sizeof(m_dwPackedFileLength)); + ar.Read(&m_dwOffset, sizeof(m_dwOffset)); + } +} + +int CFileDescriptor2::GetSize() const +{ + return sizeof(DWORD) + + m_strFileName.GetLength() + + sizeof(m_nType) + + sizeof(m_dwFileLength) + + sizeof(m_dwPackedFileLength) + + sizeof(m_dwOffset); +} + +#ifdef _DEBUG +void CFileDescriptor2::AssertValid() const +{ + CObject::AssertValid(); + ASSERT(!m_strFileName.IsEmpty()); + ASSERT(m_nType <= 1); + ASSERT(m_dwFileLength != 0); + ASSERT(m_dwPackedFileLength != 0); + ASSERT(m_dwPackedFileLength >= m_dwFileLength); +} + +void CFileDescriptor2::Dump(CDumpContext& dc) const +{ + CFileDescriptorBase::Dump(dc); + dc << "Size of descriptor:\t" << GetSize() << " bytes\n"; +} +#endif + + +// CFileList2 +IMPLEMENT_DYNAMIC(CFileList2, CObject) + +CFileList2::CFileList2() +{ +} + +CFileList2::~CFileList2() +{ +} + +void CFileList2::Serialize(CArchive& ar) +{ + if (ar.IsStoring()) { + DWORD dwFileCount = DWORD(m_FileList.GetSize()); + ar.Write(&dwFileCount, sizeof(dwFileCount)); + + CFileDescriptor2 descriptor; + DWORD dwListLength = 0; + + for(DWORD i = 0; i < dwFileCount; i++) { + descriptor = m_FileList[i]; + descriptor.Serialize(ar); + dwListLength += descriptor.GetSize(); + } + + dwListLength += sizeof(DWORD); + ar.Write(&dwListLength, sizeof(dwListLength)); + } + else { + DWORD dwFileCount; + ar.Read(&dwFileCount, sizeof(dwFileCount)); + m_FileList.SetSize(dwFileCount); + + CFileDescriptor2 descriptor; + DWORD dwListLength; + + for(DWORD i = 0; i < dwFileCount; i++) { + descriptor.Serialize(ar); + m_FileList[i] = descriptor; + } + + ar.Read(&dwListLength, sizeof(dwListLength)); + } +} + +INT_PTR CFileList2::GetSize() const +{ + return m_FileList.GetSize(); +} + +INT_PTR CFileList2::Add(const CFileDescriptor2& newElement) +{ + // No elements + if (m_FileList.GetSize() == 0) { + return m_FileList.Add(newElement); + } + + // Less than first + if (MakeLower(newElement.m_strFileName) < + MakeLower(m_FileList[0].m_strFileName)) { + m_FileList.InsertAt(0, newElement); + return 0; + } + + // Greater than last + if (MakeLower(newElement.m_strFileName) > + MakeLower(m_FileList[m_FileList.GetUpperBound()].m_strFileName)) { + m_FileList.Add(newElement); + return m_FileList.GetUpperBound(); + } + + // Equally first + if (MakeLower(newElement.m_strFileName) == + MakeLower(m_FileList[0].m_strFileName)) { + m_FileList[0] = newElement; + return 0; + } + + // Equally last + if (MakeLower(newElement.m_strFileName) == + MakeLower(m_FileList[m_FileList.GetUpperBound()].m_strFileName)) { + m_FileList[m_FileList.GetUpperBound()] = newElement; + return m_FileList.GetUpperBound(); + } + + // Other + INT_PTR nLeft = 0; + INT_PTR nRight = m_FileList.GetUpperBound(); + INT_PTR nCurrent; + + while(nRight - nLeft > 1) { + nCurrent = (nRight + nLeft) >> 1; // divide by 2 + + if (MakeLower(newElement.m_strFileName) == MakeLower(m_FileList[nCurrent].m_strFileName)) { + m_FileList[nCurrent] = newElement; + return nCurrent; + } + else if (MakeLower(newElement.m_strFileName) < MakeLower(m_FileList[nCurrent].m_strFileName)) { + nRight = nCurrent; + } + else { + nLeft = nCurrent; + } + } + + m_FileList.InsertAt(nLeft + 1, newElement); + return (nLeft + 1); +} + +void CFileList2::RemoveAt(INT_PTR nIndex) +{ + m_FileList.RemoveAt(nIndex); +} + +CFileDescriptor2& CFileList2::operator [] (INT_PTR nIndex) +{ + return m_FileList[nIndex]; +} + +CFileDescriptor2 CFileList2::operator [] (INT_PTR nIndex) const +{ + return m_FileList[nIndex]; +} + +#ifdef _DEBUG +void CFileList2::AssertValid() const +{ + CObject::AssertValid(); + m_FileList.AssertValid(); + + for(INT_PTR i = 0; i < m_FileList.GetSize(); i++) { + m_FileList[i].AssertValid(); + } +} + +template<> +void AFXAPI DumpElements(CDumpContext& dc, const CFileDescriptor2* pElements, INT_PTR nCount) +{ + ASSERT(nCount == 0 || + AfxIsValidAddress(pElements, (size_t)nCount * sizeof(CFileDescriptor2), FALSE)); + + for(INT_PTR i = 0; i < nCount; i++) { + dc << "Element " << i << ":\n"; + pElements[i].Dump(dc); + } +} + +void CFileList2::Dump(CDumpContext& dc) const +{ + CObject::Dump(dc); + dc.SetDepth(1); + m_FileList.Dump(dc); +} +#endif + + +// CDatFile2 +IMPLEMENT_DYNAMIC(CDatFile2, CObject) + +CDatFile2::CDatFile2() +{ +} + +CDatFile2::~CDatFile2() +{ + Close(); +} + +BOOL CDatFile2::Open(LPCTSTR lpszFileName, UINT nOpenFlags) +{ + if (!m_Dat.Open(lpszFileName, nOpenFlags)) { + return FALSE; + } + + if (m_Dat.GetLength() == 0) { + return TRUE; + } + + DWORD dwDatLength; + DWORD dwFileListLength; + + ULONGLONG ullFileLength = m_Dat.GetLength(); + + if (ullFileLength < 12) { + m_Dat.Close(); + return FALSE; + } + + m_Dat.Seek(-8, CFile::end); + m_Dat.Read(&dwFileListLength, sizeof(dwFileListLength)); + m_Dat.Read(&dwDatLength, sizeof(dwDatLength)); + + if ((dwDatLength < 12) || (dwDatLength != ullFileLength)) { + m_Dat.Close(); + return FALSE; + } + + m_Dat.Seek(dwDatLength - dwFileListLength - 8, CFile::begin); + + CArchive arFileList(&m_Dat, CArchive::load); + + m_FileList.Serialize(arFileList); + return TRUE; +} + +void CDatFile2::Close() +{ + Flush(); + + if (m_Dat.m_hFile != CFile::hFileNull) { + m_Dat.Close(); + } +} + +void CDatFile2::Flush() +{ + if (m_bNeedFlush) { + ULONGLONG ullLength; + + TRY { + ullLength = m_Dat.SeekToEnd(); + CArchive arFileList(&m_Dat, CArchive::store); + m_FileList.Serialize(arFileList); + arFileList.Flush(); + DWORD dwTotalLength = DWORD(m_Dat.GetLength()) + 4; + m_Dat.Write(&dwTotalLength, sizeof(dwTotalLength)); + m_bNeedFlush = FALSE; + } + + CATCH_ALL(e) { + m_Dat.SetLength(ullLength); + THROW_LAST(); + } + + END_CATCH_ALL + } +} + +INT_PTR CDatFile2::GetFileCount() +{ + return m_FileList.GetSize(); +} + +CFileDescriptorBase CDatFile2::operator [](INT_PTR nIndex) const +{ + return m_FileList[nIndex]; +} + +INT_PTR CDatFile2::FindNext() +{ + for(++m_nCurrent; m_nCurrent < m_FileList.GetSize(); m_nCurrent++) { + if (MatchPattern(m_FileList[m_nCurrent].m_strFileName, m_strPattern, FALSE)) { + break; + } + } + + if (m_nCurrent == m_FileList.GetSize()) { + m_nCurrent = -1; + } + + return m_nCurrent; +} + +BOOL CDatFile2::Inflate(CArchive& ar) +{ + if (m_nCurrent == -1) { + return FALSE; + } + + CFileDescriptorBase descriptor = m_FileList[m_nCurrent]; + + m_Dat.Seek(descriptor.m_dwOffset, CFile::begin); + + const DWORD c_dwBufferSize = 65536; + BYTE inBuffer[c_dwBufferSize]; + BYTE outBuffer[c_dwBufferSize]; + + DWORD dwBytesLeft = descriptor.m_dwPackedFileLength; + DWORD dwBytesToRead; + DWORD dwRead; + DWORD dwBytesOut = 0; + + // Uncompressed file + if (descriptor.m_nType == 0) { + do { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + dwRead = m_Dat.Read(inBuffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + return FALSE; + } + + ar.Write(inBuffer, dwBytesToRead); + dwBytesOut += dwRead; + } while((dwBytesLeft -= dwRead ) > 0); + + return TRUE; + } + + int rc; + z_stream stream; + + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.next_in = Z_NULL; + stream.avail_in = 0; + + rc = ::inflateInit(&stream); + + if (rc != Z_OK) { + return FALSE; + } + + stream.next_out = outBuffer; + stream.avail_out = c_dwBufferSize; + + BOOL bNeedData = TRUE; + BOOL bResult = TRUE; + BOOL bEndLoop = FALSE; + BOOL bWriteOutData = FALSE; + + do { + if (bNeedData) { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + dwRead = m_Dat.Read(inBuffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + bResult = FALSE; + bWriteOutData = FALSE; + break; + } + else { + dwBytesLeft -= dwRead; + } + + stream.next_in = inBuffer; + stream.avail_in = dwRead; + bNeedData = FALSE; + } + + rc = ::inflate(&stream, Z_SYNC_FLUSH); + + switch(rc) { + case Z_OK: { + if (stream.avail_in == 0) { + if (dwBytesLeft != 0) { + // Need more input + bNeedData = TRUE; + } + else { + // All data inflated, but Z_STREAM_END not returned + bEndLoop = TRUE; + bWriteOutData = TRUE; + break; + } + } + + if (stream.avail_out == 0) { // Need more output + bWriteOutData = TRUE; + } + + break; + } + + case Z_STREAM_END: { // Inflated + bEndLoop = TRUE; + bWriteOutData = TRUE; + break; + } + + default: { // Error + bEndLoop = TRUE; + bResult = FALSE; + } + } + + if (bWriteOutData) { + ar.Write(outBuffer, c_dwBufferSize - stream.avail_out); + bWriteOutData = FALSE; + stream.next_out = outBuffer; + stream.avail_out = c_dwBufferSize; + } + } while(!bEndLoop); + + rc = ::inflateEnd(&stream); + return bResult; +} + +BOOL CDatFile2::Deflate(CArchive& ar, DWORD dwLength, LPCTSTR lpszName, int level) +{ + // Cut tail of file with files list + if (m_Dat.GetLength() != 0) { + if (!m_bNeedFlush) { + DWORD dwDatLength; + DWORD dwFileListLength; + + m_Dat.Seek(-8, CFile::end); + m_Dat.Read(&dwFileListLength, sizeof(dwFileListLength)); + m_Dat.Read(&dwDatLength, sizeof(dwDatLength)); + m_Dat.SetLength(dwDatLength - dwFileListLength - 8); + } + } + + ULONGLONG ullDatLength = m_Dat.SeekToEnd(); + + // File descriptor + CFileDescriptor2 descriptor; + descriptor.m_dwFileLength = dwLength; + descriptor.m_strFileName = lpszName; + descriptor.m_dwOffset = DWORD(ullDatLength); + + // Buffers + const DWORD c_dwBufferSize = 65536; + BYTE inBuffer[c_dwBufferSize]; + BYTE outBuffer[c_dwBufferSize]; + + DWORD dwBytesLeft = dwLength; + DWORD dwBytesToRead; + DWORD dwRead; + DWORD dwBytesOut = 0; + + // Flags + BOOL bResult = TRUE; + BOOL bUseInputArchive = TRUE; + + // Temporary file + char lpszTempFileName[MAX_PATH]; + CFile fileTemp; + BOOL bDeleteTempFile = FALSE; + + // Try compress file + if (level != 0) { + // Save position in input archive + ar.Flush(); + ULONGLONG ullArPosition = ar.GetFile()->GetPosition(); + + // Create temporary file + char lpszTempPath[MAX_PATH - 14]; + HANDLE hTempFile; + + GetTempPath(MAX_PATH - 14, lpszTempPath); + GetTempFileName(lpszTempPath, "DAT", 0, lpszTempFileName); + + hTempFile = ::CreateFile(lpszTempFileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY, + NULL); + + if (hTempFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + + fileTemp.m_hFile = hTempFile; + bDeleteTempFile = TRUE; + + // Deflate file + if (level < 0 || level > 9) { + level = 9; + } + + int rc; + z_stream stream; + int flush; + + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + stream.next_in = Z_NULL; + stream.avail_in = 0; + + rc = ::deflateInit(&stream, level); + + if (rc != Z_OK) { + return FALSE; + } + + stream.next_out = outBuffer; + stream.avail_out = c_dwBufferSize; + + BOOL bNeedData = TRUE; + BOOL bEndLoop = FALSE; + BOOL bWriteOutData = FALSE; + + do { + if (bNeedData) { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + dwRead = ar.Read(inBuffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + bResult = FALSE; + bWriteOutData = FALSE; + break; + } + else { + dwBytesLeft -= dwRead; + flush = (dwBytesLeft == 0) ? Z_FINISH : Z_SYNC_FLUSH; + } + + stream.next_in = inBuffer; + stream.avail_in = dwRead; + + bNeedData = FALSE; + } + + rc = ::deflate(&stream, flush); + + switch(rc) { + case Z_OK: { + if (stream.avail_in == 0) { // Need more input + bNeedData = TRUE; + } + + if (stream.avail_out == 0) { // Need more output + bWriteOutData = TRUE; + } + + break; + } + + case Z_STREAM_END: { // Deflated + bEndLoop = TRUE; + bWriteOutData = TRUE; + break; + } + + default: { // Error + bEndLoop = TRUE; + bResult = FALSE; + } + } + + if (bWriteOutData) { + fileTemp.Write(outBuffer, c_dwBufferSize - stream.avail_out); + bWriteOutData = FALSE; + stream.next_out = outBuffer; + stream.avail_out = c_dwBufferSize; + } + } while(!bEndLoop); + + rc = ::deflateEnd(&stream); + fileTemp.SeekToBegin(); + + // Check compression result + if (!bResult) { + fileTemp.Close(); + CFile::Remove(lpszTempFileName); + return FALSE; + } + + // Check length + ULONGLONG ullTempFileLength = fileTemp.GetLength(); + + if (ullTempFileLength < dwLength) { + bUseInputArchive = FALSE; + descriptor.m_dwPackedFileLength = DWORD(ullTempFileLength); + descriptor.m_nType = 1; + dwBytesLeft = DWORD(ullTempFileLength); + } + else { + ar.Flush(); + ar.GetFile()->Seek(ullArPosition, CFile::begin); + descriptor.m_dwPackedFileLength = dwLength; + descriptor.m_nType = 0; + dwBytesLeft = dwLength; + } + } + else { + descriptor.m_dwPackedFileLength = dwLength; + descriptor.m_nType = 0; + } + + // Set source archive + CArchive arTemp(&fileTemp, CArchive::load); // Temporary archive + CArchive* pArSource; + + if (bUseInputArchive) { + pArSource = &ar; + } + else { + pArSource = &arTemp; + } + + // Write data + TRY { + do { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + dwRead = pArSource->Read(inBuffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + bResult = FALSE; + break; + } + + m_Dat.Write(inBuffer, dwBytesToRead); + dwBytesOut += dwRead; + } while((dwBytesLeft -= dwRead ) > 0); + + if (bResult) { + // Add descriptor + m_FileList.Add(descriptor); + m_bNeedFlush = TRUE; + } + else { + // Restore dat-file length on error + m_Dat.SetLength(ullDatLength); + } + + // Destroy temporary file + if (bDeleteTempFile) { + arTemp.Abort(); + fileTemp.Close(); + CFile::Remove(lpszTempFileName); + } + + return bResult; + } + + CATCH_ALL(e) { + m_Dat.SetLength(ullDatLength); + THROW_LAST(); + } + + END_CATCH_ALL +} + +BOOL CDatFile2::Delete() +{ + if (m_nCurrent == -1) { + return FALSE; + } + + // Cut tail of file with files list + if (m_Dat.GetLength() != 0) { + if (!m_bNeedFlush) { + DWORD dwDatLength; + DWORD dwFileListLength; + + m_Dat.Seek(-8, CFile::end); + m_Dat.Read(&dwFileListLength, sizeof(dwFileListLength)); + m_Dat.Read(&dwDatLength, sizeof(dwDatLength)); + m_Dat.SetLength(dwDatLength - dwFileListLength - 8); + } + } + + m_FileList.RemoveAt(m_nCurrent); + m_nCurrent = -1; + m_bNeedFlush = TRUE; + + return TRUE; +} + + +CDatFile2* g_pDatFile2ForSort; + +int CompareDescriptorIndex2(const void* pIndex1, const void* pIndex2) +{ + INT_PTR nIndex1 = *((INT_PTR*)pIndex1); + INT_PTR nIndex2 = *((INT_PTR*)pIndex2); + + CFileDescriptorBase descriptor1; + CFileDescriptorBase descriptor2; + + descriptor1 = (*g_pDatFile2ForSort)[nIndex1]; + descriptor2 = (*g_pDatFile2ForSort)[nIndex2]; + + if (descriptor1.m_dwOffset < descriptor2.m_dwOffset) { + return -1; + } + else if (descriptor1.m_dwOffset > descriptor2.m_dwOffset) { + return 1; + } + else { + return 0; + } +} + +BOOL CDatFile2::Shrink(void (*pCallback)(INT_PTR nIndex)) +{ + if (m_Dat.GetLength() == 0) { + return FALSE; + } + + // Sort files by offset + INT_PTR nFileCount = GetFileCount(); + INT_PTR* pIndexArray = new INT_PTR[nFileCount]; + + if (pIndexArray == NULL) { + return FALSE; + } + + for(INT_PTR i = 0; i < nFileCount; i++) { + pIndexArray[i] = i; + } + + g_pDatFile2ForSort = this; + qsort(pIndexArray, nFileCount, sizeof(INT_PTR), CompareDescriptorIndex2); + + // Move files + const DWORD c_dwBufferSize = 65536; + BYTE buffer[c_dwBufferSize]; + + DWORD dwWritePos = 0; + DWORD dwShift; + DWORD dwBytesToRead; + DWORD dwBytesLeft; + DWORD dwReadPos; + DWORD dwRead; + + CFileDescriptorBase descriptor; + + for(INT_PTR i = 0; i < nFileCount; i++) { + descriptor = (*this)[pIndexArray[i]]; + dwShift = descriptor.m_dwOffset - dwWritePos; + + if (dwShift > 0) { + if (pCallback) { + pCallback(pIndexArray[i]); + } + + if (!m_bNeedFlush) { + DWORD dwDatLength; + DWORD dwFileListLength; + + m_Dat.Seek(-8, CFile::end); + m_Dat.Read(&dwFileListLength, sizeof(dwFileListLength)); + m_Dat.Read(&dwDatLength, sizeof(dwDatLength)); + m_Dat.SetLength(dwDatLength - dwFileListLength - 8); + m_bNeedFlush = TRUE; + } + + dwBytesLeft = descriptor.m_dwPackedFileLength; + dwReadPos = descriptor.m_dwOffset; + + descriptor.m_dwOffset = dwWritePos; + + do { + dwBytesToRead = (dwBytesLeft < c_dwBufferSize) ? dwBytesLeft : c_dwBufferSize; + + m_Dat.Seek(dwReadPos, CFile::begin); + dwRead = m_Dat.Read(buffer, dwBytesToRead); + + if (dwRead != dwBytesToRead) { + delete [] pIndexArray; + return FALSE; + } + + m_Dat.Seek(dwWritePos, CFile::begin); + m_Dat.Write(buffer, dwRead); + dwWritePos += dwRead; + dwReadPos += dwRead; + } while((dwBytesLeft -= dwRead ) > 0); + + // Patch offsets + m_FileList[pIndexArray[i]].m_dwOffset = descriptor.m_dwOffset; + } + else { + dwWritePos += descriptor.m_dwPackedFileLength; + } + } + + m_Dat.SetLength(dwWritePos); + delete [] pIndexArray; + + m_bNeedFlush = TRUE; + + Flush(); + + return TRUE; +} diff --git a/src/DatFile2.h b/src/DatFile2.h new file mode 100644 index 0000000..ac5c146 --- /dev/null +++ b/src/DatFile2.h @@ -0,0 +1,90 @@ +#pragma once + +#include "DatFileBase.h" + +// CFileDescriptor2 +class CFileDescriptor2 : public CFileDescriptorBase { +public: + CFileDescriptor2(); + CFileDescriptor2(const CFileDescriptor2& item); + virtual ~CFileDescriptor2(); + + DECLARE_DYNAMIC(CFileDescriptor2) + + virtual void Serialize(CArchive& ar); + int GetSize() const; + + CFileDescriptor2& operator = (const CFileDescriptor2& item); + +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif +}; + + +// CFileList2 +class CFileList2 : public CObject { +public: + CFileList2(); + virtual ~CFileList2(); + + DECLARE_DYNAMIC(CFileList2) + + virtual void Serialize(CArchive& ar); + INT_PTR GetSize() const; + + INT_PTR Add(const CFileDescriptor2& newElement); + void RemoveAt(INT_PTR nIndex); + + CFileDescriptor2& operator [] (INT_PTR nIndex); + CFileDescriptor2 operator [] (INT_PTR nIndex) const; + +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +private: + // Assignment and copy not allowed + CFileList2(const CFileList2&); + CFileList2& operator = (const CFileList2&); + +private: + typedef CArray CFileDescriptor2Array; + + CFileDescriptor2Array m_FileList; +}; + +// CDatFile2 +class CDatFile2 : public CDatFileBase { +public: + CDatFile2(); + virtual ~CDatFile2(); + + DECLARE_DYNAMIC(CDatFile2) + + virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags); + virtual void Close(); + virtual void Flush(); + + virtual INT_PTR GetFileCount(); + virtual CFileDescriptorBase operator [](INT_PTR nIndex) const; + + virtual INT_PTR FindNext(); + + virtual BOOL Inflate(CArchive& ar); + virtual BOOL Deflate(CArchive& ar, DWORD dwLength, LPCTSTR lpszName, int level); + virtual BOOL Delete(); + + virtual BOOL Shrink(void (*pCallback)(INT_PTR nIndex)); + +private: + // Restricted operations + CDatFile2(const CDatFile2&); + CDatFile2& operator = (const CDatFile2&); + virtual void Serialize(CArchive&) {}; + +private: + CFileList2 m_FileList; +}; diff --git a/src/DatFileBase.cpp b/src/DatFileBase.cpp new file mode 100644 index 0000000..8f5acaf --- /dev/null +++ b/src/DatFileBase.cpp @@ -0,0 +1,163 @@ +// DatFile.cpp : implementation file +// + +#include "stdafx.h" +#include "DatFileBase.h" +#include ".\datfilebase.h" + +#if defined(_UNICODE) || defined(UNICODE) +#error UNICODE not supported +#endif + +// Utility function +CString MakeLower(CString str) +{ + return str.MakeLower(); +} + +// CFileDescriptorBase +IMPLEMENT_DYNAMIC(CFileDescriptorBase, CObject) + +CFileDescriptorBase::CFileDescriptorBase() : + m_strFileName(""), + m_nType(0), + m_dwFileLength(0), + m_dwPackedFileLength(0), + m_dwOffset(0) +{ +} + +CFileDescriptorBase::CFileDescriptorBase(const CFileDescriptorBase& item) : + m_strFileName(item.m_strFileName), + m_nType(item.m_nType), + m_dwFileLength(item.m_dwFileLength), + m_dwPackedFileLength(item.m_dwPackedFileLength), + m_dwOffset(item.m_dwOffset) +{ +} + +CFileDescriptorBase::~CFileDescriptorBase() +{ +} + +CFileDescriptorBase& CFileDescriptorBase::operator = (const CFileDescriptorBase& item) +{ + if (&item != this) { + m_strFileName = item.m_strFileName; + m_nType = item.m_nType; + m_dwFileLength = item.m_dwFileLength; + m_dwPackedFileLength = item.m_dwPackedFileLength; + m_dwOffset = item.m_dwOffset; + } + + return (*this); +} + +void CFileDescriptorBase::Serialize(CArchive& ar) +{ + ASSERT(FALSE); +} + +#ifdef _DEBUG +void CFileDescriptorBase::AssertValid() const +{ + CObject::AssertValid(); + ASSERT(!m_strFileName.IsEmpty()); + ASSERT(m_nType <= 1); + ASSERT(m_dwFileLength != 0); + ASSERT(m_dwPackedFileLength != 0); + ASSERT(m_dwPackedFileLength >= m_dwFileLength); +} + +void CFileDescriptorBase::Dump(CDumpContext& dc) const +{ + CObject::Dump(dc); + dc << "File name length:\t" << m_strFileName.GetLength() << "\n"; + dc << "File name:\t\t\t" << m_strFileName << "\n"; + dc << "Type:\t\t\t\t" << m_nType << "\n"; + dc << "File length:\t\t\t" << m_dwFileLength << " ("; + dc.DumpAsHex(m_dwFileLength); + dc << ")\n"; + dc << "Packed file length:\t" << m_dwPackedFileLength << " ("; + dc.DumpAsHex(m_dwPackedFileLength); + dc << ")\n"; + dc << "Offset:\t\t\t\t" << m_dwOffset << " ("; + dc.DumpAsHex(m_dwOffset); + dc << ")\n"; +} +#endif + +// CDatFileBase +IMPLEMENT_DYNAMIC(CDatFileBase, CObject) + +CDatFileBase::CDatFileBase() : + m_strPattern("*"), + m_bNeedFlush(FALSE), + m_nCurrent(-1) +{ +} + +CDatFileBase::~CDatFileBase() +{ +} + +DWORD CDatFileBase::GetLength(void) +{ + return DWORD(m_Dat.GetLength()); +} + +INT_PTR CDatFileBase::FindFirst(LPCTSTR lpszPattern) +{ + m_strPattern = lpszPattern; + m_nCurrent = -1; + return FindNext(); +} + +INT_PTR CDatFileBase::GetCurrentFileIndex() +{ + return m_nCurrent; +} + +CString CDatFileBase::GetFindFilePattern() +{ + return m_strPattern; +} + +BOOL CDatFileBase::MatchPattern(LPCTSTR lpszString, LPCTSTR lpszPattern, BOOL bCaseSensitive) +{ + char c, p; + + for(; ;) { + switch(p = ConvertCase(*lpszPattern++, bCaseSensitive)) { + case 0: // end of lpszPattern + return *lpszString ? FALSE : TRUE; // if end of lpszString TRUE + + case '*': + while (*lpszString) { // match zero or more char + if (MatchPattern(lpszString++, lpszPattern, bCaseSensitive)) + return TRUE; + } + + return MatchPattern (lpszString, lpszPattern, bCaseSensitive ); + + case '?': + if (*lpszString++ == 0) // match any one char + return FALSE; // not end of lpszString + + break; + + default: + c = ConvertCase(*lpszString++, bCaseSensitive); + + if (c != p) // check for exact char + return FALSE; // not a match + + break; + } + } +} + +char CDatFileBase::ConvertCase(char c, BOOL bCaseSensetive) +{ + return bCaseSensetive ? c : char(CharUpper(LPTSTR(c))); +} diff --git a/src/DatFileBase.h b/src/DatFileBase.h new file mode 100644 index 0000000..dcad5a1 --- /dev/null +++ b/src/DatFileBase.h @@ -0,0 +1,71 @@ +#pragma once + +// CFileDescriptorBase +class CFileDescriptorBase : public CObject { +public: + CFileDescriptorBase(); + CFileDescriptorBase(const CFileDescriptorBase& item); + virtual ~CFileDescriptorBase(); + + DECLARE_DYNAMIC(CFileDescriptorBase) + + virtual void Serialize(CArchive& ar); + + CFileDescriptorBase& operator = (const CFileDescriptorBase& item); + +#ifdef _DEBUG + virtual void AssertValid() const; + virtual void Dump(CDumpContext& dc) const; +#endif + +public: + CString m_strFileName; + BYTE m_nType; + DWORD m_dwFileLength; + DWORD m_dwPackedFileLength; + DWORD m_dwOffset; +}; + + +// CDatFileBase +class CDatFileBase : public CObject { +public: + CDatFileBase(); + virtual ~CDatFileBase(); + + DECLARE_DYNAMIC(CDatFileBase) + + virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags) = 0; + virtual void Close() = 0; + virtual void Flush() = 0; + + DWORD GetLength(); + + virtual INT_PTR GetFileCount() = 0; + virtual CFileDescriptorBase operator [](INT_PTR nIndex) const = 0; + + INT_PTR FindFirst(LPCTSTR lpszPattern); + virtual INT_PTR FindNext() = 0; + INT_PTR GetCurrentFileIndex(); + CString GetFindFilePattern(); + + virtual BOOL Inflate(CArchive& ar) = 0; + virtual BOOL Deflate(CArchive& ar, DWORD dwLength, LPCTSTR lpszName, int level) = 0; + virtual BOOL Delete() = 0; + virtual BOOL Shrink(void (*pCallback)(INT_PTR nIndex)) = 0; + +protected: + BOOL MatchPattern(LPCTSTR lpszString, LPCTSTR lpszPattern, BOOL bCaseSensitive); + char ConvertCase(char c, BOOL bCaseSensetive); + +protected: + CString m_strPattern; + CFile m_Dat; + + BOOL m_bNeedFlush; + INT_PTR m_nCurrent; +}; + + +// Utility function +CString MakeLower(CString str); diff --git a/src/LZ77C.cpp b/src/LZ77C.cpp new file mode 100644 index 0000000..47be675 --- /dev/null +++ b/src/LZ77C.cpp @@ -0,0 +1,304 @@ +#include "stdafx.h" + +#define N 4096 /* size of ring buffer */ +#define F 18 /* upper limit for match_length */ +#define THRESHOLD 2 /* encode string into position and length if match_length is greater than this */ +#define NIL N /* index for root of binary search trees */ + +//unsigned long int textsize = 0; /* text size counter */ +//unsigned long int codesize = 0; /* code size counter */ + +BYTE text_buf[N + F - 1]; /* Ring buffer of size N, with extra F-1 bytes to facilitate string comparison */ + +int match_position; /* Longest match. These are set by the InsertNode() procedure. */ +int match_length; + +int lson[N + 1]; /* left children */ +int rson[N + 257]; /* right children */ +int dad[N + 1]; /* parents -- These constitute binary search trees. */ + +void InitTree() +{ + int i; + + for(i = N + 1; i <= N + 256; i++) { + rson[i] = NIL; + } + + for(i = 0; i < N; i++) { + dad[i] = NIL; + } +} + +void InsertNode(int r) +{ + int i; + int p; + int cmp; + BYTE* key; + + cmp = 1; + key = &text_buf[r]; + p = N + 1 + key[0]; + + rson[r] = lson[r] = NIL; + match_length = 0; + + for( ; ; ) { + if (cmp >= 0) { + if (rson[p] != NIL) { + p = rson[p]; + } + else { + rson[p] = r; + dad[r] = p; + return; + } + } + else { + if (lson[p] != NIL) { + p = lson[p]; + } + else { + lson[p] = r; + dad[r] = p; + return; + } + } + + for (i = 1; i < F; i++) { + if ((cmp = key[i] - text_buf[p + i]) != 0) { + break; + } + } + + if (i > match_length) { + match_position = p; + + if ((match_length = i) >= F) { + break; + } + } + } + + dad[r] = dad[p]; + lson[r] = lson[p]; + rson[r] = rson[p]; + + dad[lson[p]] = r; + dad[rson[p]] = r; + + if (rson[dad[p]] == p) { + rson[dad[p]] = r; + } + else { + lson[dad[p]] = r; + } + + dad[p] = NIL; /* remove p */ +} + +void DeleteNode(int p) +{ + int q; + + if (dad[p] == NIL) { + return; /* not in tree */ + } + + if (rson[p] == NIL) { + q = lson[p]; + } + else if (lson[p] == NIL) { + q = rson[p]; + } + else { + q = lson[p]; + + if (rson[q] != NIL) { + do { + q = rson[q]; + } while (rson[q] != NIL); + + rson[dad[q]] = lson[q]; + dad[lson[q]] = dad[q]; + lson[q] = lson[p]; + dad[lson[p]] = q; + } + + rson[q] = rson[p]; + dad[rson[p]] = q; + } + + dad[q] = dad[p]; + + if (rson[dad[p]] == p) { + rson[dad[p]] = q; + } + else { + lson[dad[p]] = q; + } + + dad[p] = NIL; +} + +#define GETBYTE() ((dwInputCurrent < dwInputLength) ? int(buffer[dwInputCurrent++]) & 0xFF : (-1)) + +void LZSSEncodeBuffer(BYTE* buffer, DWORD dwInputLength, CFile& fileOut) +{ + ASSERT(buffer); + + int i; + int c; + int len; + int r; + int s; + int last_match_length; + int code_buf_ptr; + + BYTE code_buf[17]; + BYTE mask; + + DWORD dwInputCurrent = 0; + + InitTree(); + + code_buf[0] = 0; + code_buf_ptr = mask = 1; + s = 0; + r = N - F; + + for(i = s; i < r; i++) { + text_buf[i] = ' '; + } + + for(len = 0; len < F && (c = GETBYTE()) != (-1); len++) { + text_buf[r + len] = c; + } + + if (len == 0) { + return; + } + + for(i = 1; i <= F; i++) { + InsertNode(r - i); + } + + InsertNode(r); + + do { + if (match_length > len) { + match_length = len; + } + + if (match_length <= THRESHOLD) { + match_length = 1; + code_buf[0] |= mask; + code_buf[code_buf_ptr++] = text_buf[r]; + } + else { + code_buf[code_buf_ptr++] = (BYTE) match_position; + code_buf[code_buf_ptr++] = (BYTE)(((match_position >> 4) & 0xf0) | (match_length - (THRESHOLD + 1))); + } + + if ((mask <<= 1) == 0) { + for (i = 0; i < code_buf_ptr; i++) { + fileOut.Write(code_buf + i, 1); + } + + code_buf[0] = 0; + code_buf_ptr = mask = 1; + } + + last_match_length = match_length; + + for (i = 0; i < last_match_length && (c = GETBYTE()) != (-1); i++) { + DeleteNode(s); + text_buf[s] = c; + + if (s < F - 1) { + text_buf[s + N] = c; + } + + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + InsertNode(r); + } + + while (i++ < last_match_length) { + DeleteNode(s); + s = (s + 1) & (N - 1); + r = (r + 1) & (N - 1); + + if (--len) { + InsertNode(r); + } + } + } while(len > 0); + + if (code_buf_ptr > 1) { + for (i = 0; i < code_buf_ptr; i++) { + fileOut.Write(code_buf + i, 1); + } + } +} + +void LZSSDecodeBuffer(BYTE* buffer, DWORD dwInputLength, CArchive& arOut) +{ + ASSERT(buffer); + + int i; + int j; + int k; + int r; + int c; + unsigned int flags; + + DWORD dwInputCurrent = 0; + + for (i = 0; i < N - F; i++) { + text_buf[i] = ' '; + } + + r = N - F; + flags = 0; + + for ( ; ; ) { + if (((flags >>= 1) & 256) == 0) { + if ((c = GETBYTE()) == (-1)) { + break; + } + + flags = c | 0xff00; /* uses higher byte cleverly */ + } /* to count eight */ + + if (flags & 1) { + if ((c = GETBYTE()) == (-1)) { + break; + } + + arOut.Write(&c, 1); + text_buf[r++] = c; + r &= (N - 1); + } + else { + if ((i = GETBYTE()) == (-1)) { + break; + } + + if ((j = GETBYTE()) == (-1)) { + break; + } + + i |= ((j & 0xf0) << 4); + j = (j & 0x0f) + THRESHOLD; + + for (k = 0; k <= j; k++) { + c = text_buf[(i + k) & (N - 1)]; + arOut.Write(&c, 1); + text_buf[r++] = c; + r &= (N - 1); + } + } + } +} diff --git a/src/LZ77C.h b/src/LZ77C.h new file mode 100644 index 0000000..e5d260f --- /dev/null +++ b/src/LZ77C.h @@ -0,0 +1,7 @@ +#ifndef LZ77C_H +#define LZ77C_H + +void LZSSEncodeBuffer(BYTE* buffer, DWORD dwInputLength, CFile& fileOut); +void LZSSDecodeBuffer(BYTE* buffer, DWORD dwInputLength, CArchive& arOut); + +#endif /* LZ77C_H */ diff --git a/src/OnAdd.cpp b/src/OnAdd.cpp new file mode 100644 index 0000000..e0f1e37 --- /dev/null +++ b/src/OnAdd.cpp @@ -0,0 +1,98 @@ +#include "stdafx.h" +#include "dat2.h" +#include "Util.h" + +extern CString g_strTargetDir; + +DWORD g_dwTotalAdded; + +BOOL ProcessTree(CString strPattern, CString strRoot, BOOL bRecursive) +{ + BOOL bResult = TRUE; + + CString strPath = ExtractFilePath(strPattern); + CString strFilePattern = ExtractFileName(strPattern); + + WIN32_FIND_DATA fd; + HANDLE hSearchHandle = FindFirstFile(strPattern, &fd); + + if (hSearchHandle != INVALID_HANDLE_VALUE) { + do { + if (CString(fd.cFileName) != CString(_T(".")) && + CString(fd.cFileName) != CString(_T(".."))) { + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (bRecursive) { + ProcessTree(strPath + fd.cFileName + "\\" + strFilePattern, + strRoot.IsEmpty() ? fd.cFileName : strRoot + "\\" + fd.cFileName, // + _T("\\"), + bRecursive); + } + } + else { + CFile fileIn; + + if (fileIn.Open(strPath + fd.cFileName, CFile::modeRead | CFile::shareDenyWrite)) { + CArchive arIn(&fileIn, CArchive::load); + CString strFileDescriptorName = g_strTargetDir; + strFileDescriptorName += strRoot.IsEmpty() ? fd.cFileName : strRoot + _T("\\") + fd.cFileName; + + printf("Adding: %s", strFileDescriptorName); + + if (g_pDatFile->Deflate(arIn, DWORD(fileIn.GetLength()), + strFileDescriptorName, g_nCompressMethod)) { + printf("\n"); + g_dwTotalAdded++; + } + else { + printf(" Error!!!\n"); + bResult = FALSE; + break; + } + } + else { + bResult = FALSE; + break; + } + } + } + } while(FindNextFile(hSearchHandle, &fd)); + + FindClose(hSearchHandle); + return bResult; + } + else { + return FALSE; + } +} + +int OnAdd() +{ + g_dwTotalAdded = 0; + + if (g_pDatFile->Open(g_strDatFileName, CFile::modeCreate | CFile::modeNoTruncate | CFile::modeReadWrite | CFile::shareDenyWrite)) { + for(INT_PTR j = 0; j < g_FileList.GetCount(); j++) { + CString strRoot = ExtractFilePath(g_FileList[j], FALSE); + + if (strRoot[0] == '\\') { + strRoot = strRoot.Right(strRoot.GetLength() - 1); + } + + if (strRoot.Right(1) == '\\') { + strRoot = strRoot.Left(strRoot.GetLength() - 1); + } + + if (!ProcessTree(g_FileList[j], strRoot, g_bRecurseIntoDir)) { + return 4; + } + } + + printf("----------\n"); + printf("%u file(s) added\n", g_dwTotalAdded); + + return 0; + } + else { + printf("Error: Unable open file %s\n", LPCTSTR(g_strDatFileName)); + return 1; + } +} \ No newline at end of file diff --git a/src/OnDelete.cpp b/src/OnDelete.cpp new file mode 100644 index 0000000..5b4bb31 --- /dev/null +++ b/src/OnDelete.cpp @@ -0,0 +1,31 @@ +#include "stdafx.h" +#include "dat2.h" + +int OnDelete() +{ + CFileDescriptorBase descriptor; + DWORD dwTotalDeleted = 0; + + for(INT_PTR j = 0; j < g_FileList.GetCount(); j++) { + if (g_pDatFile->FindFirst(g_FileList[j]) != -1) { + do { + descriptor = (*g_pDatFile)[g_pDatFile->GetCurrentFileIndex()]; + printf("Deleting: %s", descriptor.m_strFileName); + + if (g_pDatFile->Delete()) { + dwTotalDeleted++; + printf("\n"); + } + else { + printf(" Error!!!\n"); + return 2; + } + } while(g_pDatFile->FindNext() != -1); + } + } + + printf("----------\n"); + printf("%u file(s) deleted\n", dwTotalDeleted); + + return 0; +} \ No newline at end of file diff --git a/src/OnExtract.cpp b/src/OnExtract.cpp new file mode 100644 index 0000000..dd5b23c --- /dev/null +++ b/src/OnExtract.cpp @@ -0,0 +1,69 @@ +#include "stdafx.h" +#include "dat2.h" +#include "Util.h" + +int OnExtract() +{ + CFileDescriptorBase descriptor; + DWORD dwTotalExtracted = 0; + CString strDirectory; + CString strFileName; + int nLastSlashPos; + CString strOutFileName; + CFile fileOut; + + // Create output directory + if (!g_strOutFolder.IsEmpty()) { + if (!ForceCreateDirectory(g_strOutFolder)) { + printf("Error: Unable create output directory\n"); + return 3; + } + } + + for(INT_PTR j = 0; j < g_FileList.GetCount(); j++) { + if (g_pDatFile->FindFirst(g_FileList[j]) != -1) { + do { + descriptor = (*g_pDatFile)[g_pDatFile->GetCurrentFileIndex()]; + printf("Extracting: %s", descriptor.m_strFileName); + nLastSlashPos = descriptor.m_strFileName.ReverseFind('\\'); + strDirectory = descriptor.m_strFileName.Left(nLastSlashPos + 1); + strFileName = descriptor.m_strFileName.Right(descriptor.m_strFileName.GetLength() - nLastSlashPos - 1); + + + if (g_bExtractWithoutPaths) { + strOutFileName = g_strOutFolder + strFileName; + } + else { + if (!ForceCreateDirectory(g_strOutFolder + strDirectory)) { + return 3; + } + + strOutFileName = g_strOutFolder + strDirectory + strFileName; + } + + if (fileOut.Open(strOutFileName, CFile::modeCreate | CFile::modeWrite)) { + CArchive arOut(&fileOut, CArchive::store); + + if (g_pDatFile->Inflate(arOut)) { + dwTotalExtracted++; + printf("\n"); + } + else { + printf(" Error!!!\n"); + return 3; + } + } + else { + printf(" Error!!! Unable open out file %s\n", strOutFileName); + return 3; + } + + fileOut.Close(); + } while(g_pDatFile->FindNext() != -1); + } + } + + printf("----------\n"); + printf("%u file(s) extracted\n", dwTotalExtracted); + return 0; +} \ No newline at end of file diff --git a/src/OnList.cpp b/src/OnList.cpp new file mode 100644 index 0000000..8e032c8 --- /dev/null +++ b/src/OnList.cpp @@ -0,0 +1,28 @@ +#include "stdafx.h" +#include "dat2.h" + +int OnList() +{ + CFileDescriptorBase descriptor; + DWORD dwTotalSize = 0; + + printf(" Length Packed Type Name\n"); + printf(" ---------- ----------- -------- ---------------\n"); + + for(INT_PTR i = 0; i < g_pDatFile->GetFileCount(); i++) { + descriptor = (*g_pDatFile)[i]; + dwTotalSize += descriptor.m_dwFileLength; + printf("%11u %11u %s %s\n", + descriptor.m_dwFileLength, + descriptor.m_dwPackedFileLength, + (descriptor.m_nType) ? "Packed" : "Stored", + descriptor.m_strFileName); + } + + printf(" ---------- ---------------\n"); + printf("%11u %u file(s)\n", + dwTotalSize, + DWORD(g_pDatFile->GetFileCount())); + + return 0; +} \ No newline at end of file diff --git a/src/OnShrink.cpp b/src/OnShrink.cpp new file mode 100644 index 0000000..71b1e65 --- /dev/null +++ b/src/OnShrink.cpp @@ -0,0 +1,31 @@ +#include "stdafx.h" +#include "dat2.h" + + +DWORD dwTotalMoved = 0; + +void OutInfo(INT_PTR nIndex) +{ + CFileDescriptorBase descriptor; + descriptor = (*g_pDatFile)[nIndex]; + + + dwTotalMoved++; + printf("Moving: %s\n", descriptor.m_strFileName); +} + + +int OnShrink() +{ + DWORD dwOldLength = g_pDatFile->GetLength(); + + if (g_pDatFile->Shrink(OutInfo)) { + printf("----------\n"); + printf("%u file(s) moved. Old size: %u bytes. New size: %u bytes \n", dwTotalMoved, dwOldLength, g_pDatFile->GetLength()); + return 0; + } + else { + printf("Error: Unable shrink file\n"); + return 5; + } +} \ No newline at end of file diff --git a/src/Resource.h b/src/Resource.h new file mode 100644 index 0000000..65f5d14 --- /dev/null +++ b/src/Resource.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by dat2.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/Util.cpp b/src/Util.cpp new file mode 100644 index 0000000..25de972 --- /dev/null +++ b/src/Util.cpp @@ -0,0 +1,177 @@ +#include "stdafx.h" +#include "Util.h" + +CString ExtractFilePath(const CString& strFileName, BOOL bIncludeDrive) +{ + CString strDrive; + CString strDirectory; + LPTSTR lpszDrive = strDrive.GetBufferSetLength(_MAX_DRIVE); + LPTSTR lpszDirectory = strDirectory.GetBufferSetLength(_MAX_DIR); + _splitpath(strFileName, lpszDrive, lpszDirectory, NULL, NULL); + strDrive.ReleaseBuffer(); + strDirectory.ReleaseBuffer(); + + if (bIncludeDrive) { + return (strDrive + strDirectory); + } + else { + return strDirectory; + } +} + +CString ExtractFileName(const CString& strFileName) +{ + CString strName; + CString strExtension; + LPTSTR lpszName = strName.GetBufferSetLength(_MAX_FNAME); + LPTSTR lpszExtension = strExtension.GetBufferSetLength(_MAX_EXT); + _splitpath(strFileName, NULL, NULL, lpszName, lpszExtension); + strName.ReleaseBuffer(); + strExtension.ReleaseBuffer(); + return (strName + strExtension); +} + +BOOL DirectoryExist(const CString& strDirectory) +{ + DWORD dwResult = ::GetFileAttributes(strDirectory); + return ((dwResult != INVALID_FILE_ATTRIBUTES) && + ((dwResult & FILE_ATTRIBUTE_DIRECTORY) != 0)); +} + +BOOL ForceCreateDirectory(CString strDirectory) +{ + if (strDirectory.GetLength() == 0) { + return TRUE; + } + + if (strDirectory.Right(1) == _T("\\")) { + strDirectory = strDirectory.Left(strDirectory.GetLength() - 1); + } + + if ((strDirectory.GetLength() < 3) || + DirectoryExist(strDirectory) || + (ExtractFilePath(strDirectory) == strDirectory)) { + return TRUE; + } + + return (ForceCreateDirectory(ExtractFilePath(strDirectory)) && + ::CreateDirectory(strDirectory, NULL)); +} + +UINT ReadMSBWord(CArchive& ar, WORD& wValue) +{ + BYTE* pBuffer = reinterpret_cast(&wValue); + return (ar.Read(pBuffer + 1, 1) + ar.Read(pBuffer, 1)); +} + +UINT ReadMSBDWord(CArchive& ar, DWORD& dwValue) +{ + BYTE* pBuffer = reinterpret_cast(&dwValue); + return (ar.Read(pBuffer + 3, 1) + ar.Read(pBuffer + 2, 1) + + ar.Read(pBuffer + 1, 1) + ar.Read(pBuffer, 1)); +} + +UINT ReadMSBWord(CFile& file, WORD& wValue) +{ + BYTE* pBuffer = reinterpret_cast(&wValue); + return (file.Read(pBuffer + 1, 1) + file.Read(pBuffer, 1)); +} + +UINT ReadMSBDWord(CFile& file, DWORD& dwValue) +{ + BYTE* pBuffer = reinterpret_cast(&dwValue); + return (file.Read(pBuffer + 3, 1) + file.Read(pBuffer + 2, 1) + + file.Read(pBuffer + 1, 1) + file.Read(pBuffer, 1)); +} + +BOOL ReadString(CArchive& ar, CString& strString) +{ + BYTE nStrLength; + + if (ar.Read(&nStrLength, 1) != 1) { + return FALSE; + } + + LPTSTR lpszString = strString.GetBufferSetLength(nStrLength + 1); + DWORD dwRead = ar.Read(lpszString, nStrLength); + strString.ReleaseBuffer(nStrLength); + + if (dwRead != nStrLength) { + return FALSE; + } + else { + return TRUE; + } +} + +BOOL ReadString(CFile& file, CString& strString) +{ + BYTE nStrLength; + + if (file.Read(&nStrLength, 1) != 1) { + return FALSE; + } + + LPTSTR lpszString = strString.GetBufferSetLength(nStrLength + 1); + DWORD dwRead = file.Read(lpszString, nStrLength); + strString.ReleaseBuffer(nStrLength); + + if (dwRead != nStrLength) { + return FALSE; + } + else { + return TRUE; + } +} + +void WriteMSBWord(CArchive& ar, WORD wValue) +{ + BYTE* pBuffer = reinterpret_cast(&wValue); + + ar.Write(pBuffer + 1, 1); + ar.Write(pBuffer, 1); +} + +void WriteMSBDWord(CArchive& ar, DWORD dwValue) +{ + BYTE* pBuffer = reinterpret_cast(&dwValue); + + ar.Write(pBuffer + 3, 1); + ar.Write(pBuffer + 2, 1); + ar.Write(pBuffer + 1, 1); + ar.Write(pBuffer, 1); +} + +void WriteMSBWord(CFile& file, WORD wValue) +{ + BYTE* pBuffer = reinterpret_cast(&wValue); + + file.Write(pBuffer + 1, 1); + file.Write(pBuffer, 1); +} + +void WriteMSBDWord(CFile& file, DWORD dwValue) +{ + BYTE* pBuffer = reinterpret_cast(&dwValue); + + file.Write(pBuffer + 3, 1); + file.Write(pBuffer + 2, 1); + file.Write(pBuffer + 1, 1); + file.Write(pBuffer, 1); +} + +void WriteString(CArchive& ar, CString& strString) +{ + BYTE nStrLength = BYTE(strString.GetLength()); + + ar.Write(&nStrLength, 1); + ar.Write(LPCTSTR(strString), nStrLength); +} + +void WriteString(CFile& file, CString& strString) +{ + BYTE nStrLength = BYTE(strString.GetLength()); + + file.Write(&nStrLength, 1); + file.Write(LPCTSTR(strString), nStrLength); +} diff --git a/src/Util.h b/src/Util.h new file mode 100644 index 0000000..35d8c4d --- /dev/null +++ b/src/Util.h @@ -0,0 +1,24 @@ +#pragma once + +CString ExtractFileName(const CString& strFileName); +CString ExtractFilePath(const CString& strFileName, BOOL bIncludeDrive = TRUE); +BOOL DirectoryExist(const CString& strDirectory); +BOOL ForceCreateDirectory(CString strDirectory); + +UINT ReadMSBWord(CArchive& ar, WORD& wValue); +UINT ReadMSBDWord(CArchive& ar, DWORD& dwValue); + +UINT ReadMSBWord(CFile& file, WORD& wValue); +UINT ReadMSBDWord(CFile& file, DWORD& dwValue); + +BOOL ReadString(CArchive& ar, CString& strString); +BOOL ReadString(CFile& file, CString& strString); + +void WriteMSBWord(CArchive& ar, WORD wValue); +void WriteMSBDWord(CArchive& ar, DWORD dwValue); + +void WriteMSBWord(CFile& file, WORD wValue); +void WriteMSBDWord(CFile& file, DWORD dwValue); + +void WriteString(CArchive& ar, CString& strString); +void WriteString(CFile& file, CString& strString); diff --git a/src/XGetopt.cpp b/src/XGetopt.cpp new file mode 100644 index 0000000..0ba3d7a --- /dev/null +++ b/src/XGetopt.cpp @@ -0,0 +1,219 @@ +// XGetopt.cpp Version 1.2 +// +// Author: Hans Dietrich +// hdietrich2@hotmail.com +// +// Description: +// XGetopt.cpp implements getopt(), a function to parse command lines. +// +// History +// Version 1.2 - 2003 May 17 +// - Added Unicode support +// +// Version 1.1 - 2002 March 10 +// - Added example to XGetopt.cpp module header +// +// This software is released into the public domain. +// You are free to use it in any way you like. +// +// This software is provided "as is" with no expressed +// or implied warranty. I accept no liability for any +// damage or loss of business that this software may cause. +// +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// if you are using precompiled headers then include this line: +#include "stdafx.h" +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// if you are not using precompiled headers then include these lines: +//#include +//#include +//#include +/////////////////////////////////////////////////////////////////////////////// + + +#include "XGetopt.h" + + +/////////////////////////////////////////////////////////////////////////////// +// +// X G e t o p t . c p p +// +// +// NAME +// getopt -- parse command line options +// +// SYNOPSIS +// int getopt(int argc, TCHAR *argv[], TCHAR *optstring) +// +// extern TCHAR *optarg; +// extern int optind; +// +// DESCRIPTION +// The getopt() function parses the command line arguments. Its +// arguments argc and argv are the argument count and array as +// passed into the application on program invocation. In the case +// of Visual C++ programs, argc and argv are available via the +// variables __argc and __argv (double underscores), respectively. +// getopt returns the next option letter in argv that matches a +// letter in optstring. (Note: Unicode programs should use +// __targv instead of __argv. Also, all character and string +// literals should be enclosed in _T( ) ). +// +// optstring is a string of recognized option letters; if a letter +// is followed by a colon, the option is expected to have an argument +// that may or may not be separated from it by white space. optarg +// is set to point to the start of the option argument on return from +// getopt. +// +// Option letters may be combined, e.g., "-ab" is equivalent to +// "-a -b". Option letters are case sensitive. +// +// getopt places in the external variable optind the argv index +// of the next argument to be processed. optind is initialized +// to 0 before the first call to getopt. +// +// When all options have been processed (i.e., up to the first +// non-option argument), getopt returns EOF, optarg will point +// to the argument, and optind will be set to the argv index of +// the argument. If there are no non-option arguments, optarg +// will be set to NULL. +// +// The special option "--" may be used to delimit the end of the +// options; EOF will be returned, and "--" (and everything after it) +// will be skipped. +// +// RETURN VALUE +// For option letters contained in the string optstring, getopt +// will return the option letter. getopt returns a question mark (?) +// when it encounters an option letter not included in optstring. +// EOF is returned when processing is finished. +// +// BUGS +// 1) Long options are not supported. +// 2) The GNU double-colon extension is not supported. +// 3) The environment variable POSIXLY_CORRECT is not supported. +// 4) The + syntax is not supported. +// 5) The automatic permutation of arguments is not supported. +// 6) This implementation of getopt() returns EOF if an error is +// encountered, instead of -1 as the latest standard requires. +// +// EXAMPLE +// BOOL CMyApp::ProcessCommandLine(int argc, TCHAR *argv[]) +// { +// int c; +// +// while ((c = getopt(argc, argv, _T("aBn:"))) != EOF) +// { +// switch (c) +// { +// case _T('a'): +// TRACE(_T("option a\n")); +// // +// // set some flag here +// // +// break; +// +// case _T('B'): +// TRACE( _T("option B\n")); +// // +// // set some other flag here +// // +// break; +// +// case _T('n'): +// TRACE(_T("option n: value=%d\n"), atoi(optarg)); +// // +// // do something with value here +// // +// break; +// +// case _T('?'): +// TRACE(_T("ERROR: illegal option %s\n"), argv[optind-1]); +// return FALSE; +// break; +// +// default: +// TRACE(_T("WARNING: no handler for option %c\n"), c); +// return FALSE; +// break; +// } +// } +// // +// // check for non-option args here +// // +// return TRUE; +// } +// +/////////////////////////////////////////////////////////////////////////////// + +TCHAR *optarg; // global argument pointer +int optind = 0; // global argv index + +int getopt(int argc, TCHAR *argv[], TCHAR *optstring) +{ + static TCHAR *next = NULL; + if (optind == 0) + next = NULL; + + optarg = NULL; + + if (next == NULL || *next == _T('\0')) + { + if (optind == 0) + optind++; + + if (optind >= argc || argv[optind][0] != _T('-') || argv[optind][1] == _T('\0')) + { + optarg = NULL; + if (optind < argc) + optarg = argv[optind]; + return EOF; + } + + if (_tcscmp(argv[optind], _T("--")) == 0) + { + optind++; + optarg = NULL; + if (optind < argc) + optarg = argv[optind]; + return EOF; + } + + next = argv[optind]; + next++; // skip past - + optind++; + } + + TCHAR c = *next++; + TCHAR *cp = _tcschr(optstring, c); + + if (cp == NULL || c == _T(':')) + return _T('?'); + + cp++; + if (*cp == _T(':')) + { + if (*next != _T('\0')) + { + optarg = next; + next = NULL; + } + else if (optind < argc) + { + optarg = argv[optind]; + optind++; + } + else + { + return _T('?'); + } + } + + return c; +} diff --git a/src/XGetopt.h b/src/XGetopt.h new file mode 100644 index 0000000..7e75f26 --- /dev/null +++ b/src/XGetopt.h @@ -0,0 +1,23 @@ +// XGetopt.h Version 1.2 +// +// Author: Hans Dietrich +// hdietrich2@hotmail.com +// +// This software is released into the public domain. +// You are free to use it in any way you like. +// +// This software is provided "as is" with no expressed +// or implied warranty. I accept no liability for any +// damage or loss of business that this software may cause. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef XGETOPT_H +#define XGETOPT_H + +extern int optind, opterr; +extern TCHAR *optarg; + +int getopt(int argc, TCHAR *argv[], TCHAR *optstring); + +#endif //XGETOPT_H diff --git a/src/dat2.cpp b/src/dat2.cpp new file mode 100644 index 0000000..db70ff6 --- /dev/null +++ b/src/dat2.cpp @@ -0,0 +1,320 @@ +// dat2.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" +#include "dat2.h" +#include "DatFile1.h" +#include "DatFile2.h" +#include "XGetopt.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif /* _DEBUG */ + +// Globals +Command g_Command = COMMAND_UNKNOWN; +int g_nCompressMethod = 9; +BOOL g_bRecurseIntoDir = FALSE; +BOOL g_bExtractWithoutPaths = FALSE; +CString g_strOutFolder; +CString g_strDatFileName; +CStringArray g_FileList; +BOOL g_bFallout1Dat = FALSE; +CString g_strTargetDir = ""; + +// Dat-file +CDatFile1 g_DatFile1; +CDatFile2 g_DatFile2; +CDatFileBase* g_pDatFile = NULL; + +// Functions +void PrintUsage(char* lpszFileName); +int ParseCommandLine(int argc, char* argv[]); + +// The one and only application object +CWinApp theApp; + +int main(int argc, char* argv[]) +{ + if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)) { + printf("Fatal Error: MFC initialization failed\n"); + return 1; + } + else { + printf("Fallout DAT-files packer/unpacker, version 2.32\n"); + printf("Copyright (C) Anchorite (TeamX), 2004-2006\n"); + printf("anchorite2001@yandex.ru\n"); + printf("\n"); + +// for(int i = 0; i < argc; i++) { +// printf("argv[%d] = %s\n", i, argv[i]); +// } + + if (argc < 3) { + PrintUsage(argv[0]); + return 0; + } + + int nResult = ParseCommandLine(argc, argv); + + switch(nResult) { + case -1: { + printf("Error: Invalid command\n"); + return 1; + } + + case -2: { + printf("Error: Name of output directory is omitted\n"); + return 1; + } + + case -3: { + printf("Error: Name of dat-file is omitted\n"); + return 1; + } + + case -4: { + printf("Error: List of files is omitted\n"); + return 1; + } + + case -5: { + printf("Error: Unable open response file\n"); + return 1; + } + } + + nResult = 0; + UINT nOpenMode; + + switch(g_Command) { + case COMMAND_EXTRACT: + nOpenMode = CFile::modeRead | CFile::shareDenyWrite; + break; + + case COMMAND_DELETE: + nOpenMode = CFile::modeReadWrite | CFile::shareDenyWrite; + break; + + case COMMAND_LIST: + nOpenMode = CFile::modeRead | CFile::shareDenyWrite; + break; + + case COMMAND_SHRINK: + nOpenMode = CFile::modeReadWrite | CFile::shareDenyWrite; + } + + if (g_Command == COMMAND_ADD) { + if (g_bFallout1Dat) { + g_pDatFile = &g_DatFile1; + } + else { + g_pDatFile = &g_DatFile2; + } + } + else { + if (g_DatFile2.Open(g_strDatFileName, nOpenMode)) { + g_pDatFile = &g_DatFile2; + } + else if (g_DatFile1.Open(g_strDatFileName, nOpenMode)) { + g_pDatFile = &g_DatFile1; + } + else { + printf("Error: Unable open file %s\n", LPCTSTR(g_strDatFileName)); + return 1; + } + } + + switch(g_Command) { + case COMMAND_ADD: + nResult = OnAdd(); + break; + + case COMMAND_EXTRACT: + nResult = OnExtract(); + break; + + case COMMAND_DELETE: + nResult = OnDelete(); + break; + + case COMMAND_LIST: + nResult = OnList(); + break; + + case COMMAND_SHRINK: + nResult = OnShrink(); + } + + printf("\n"); + printf("Flushing buffers...\n"); + g_pDatFile->Flush(); + + return nResult; + } +} + +void PrintUsage(char* lpszFileName) +{ + printf("Usage: %s [options] [-t dir] [-d dir] dat-file [list | @response-file]\n", lpszFileName); + printf("\n"); + printf("Commands\n"); + printf(" a: Add files to dat-file. Create new if dat-file not exist\n"); + printf(" x: Extract files from dat-file\n"); + printf(" d: Delete files from dat-file (only info about files)\n"); + printf(" l: List files in dat-file\n"); + printf(" k: Shrink dat-file\n"); + printf("\n"); + printf("Options\n"); + printf(" -s: create Fallout 1 dat-file\n"); + printf(" -r: recurse into directories\n"); + printf(" -0..9: Compression method\n"); + printf(" (Fallout1: 0 - store, other numbers - compress (default)\n"); + printf(" (Fallout2: 0 - store, 1 - best speed, 9 - best compression (default)\n"); + printf(" -p: extract without paths\n"); + printf(" -d: extract files into specified directory\n"); + printf(" -t: add files to specified directory of dat-file\n"); + printf(" --: end of options\n"); + + printf("\n"); +} + +int ParseCommandLine(int argc, char* argv[]) +{ + // Command + if (memcmp(argv[1], "a", lstrlen(argv[1])) == 0) { + g_Command = COMMAND_ADD; + } + else if (memcmp(argv[1], "x", lstrlen(argv[1])) == 0) { + g_Command = COMMAND_EXTRACT; + } + else if (memcmp(argv[1], "d", lstrlen(argv[1])) == 0) { + g_Command = COMMAND_DELETE; + } + else if (memcmp(argv[1], "l", lstrlen(argv[1])) == 0) { + g_Command = COMMAND_LIST; + } + else if (memcmp(argv[1], "k", lstrlen(argv[1])) == 0) { + g_Command = COMMAND_SHRINK; + } + else { + return -1; + } + + // Options + argc--; + argv++; + + int c; + + while((c = getopt(argc, argv, "r0123456789pd:st:")) != EOF) { + switch(c) { + case 'r': + g_bRecurseIntoDir = TRUE; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + g_nCompressMethod = c - '0'; + break; + + case 'p': + g_bExtractWithoutPaths = TRUE; + break; + + case 'd': + g_strOutFolder = optarg; + + if ((!g_strOutFolder.IsEmpty()) && (g_strOutFolder.Right(1) != "\\")) { + g_strOutFolder += "\\"; + } + + break; + + case 's': + g_bFallout1Dat = TRUE; + break; + + case 't': + g_strTargetDir = optarg; + + if ((!g_strTargetDir.IsEmpty()) && (g_strTargetDir.Right(1) != "\\")) { + g_strTargetDir += "\\"; + } + + break; + + case '?': + return -2; + + default: // No more options + break; + } + } + + // Dat-file + if (optind < argc) { + g_strDatFileName = argv[optind]; + } + + if (g_strDatFileName.IsEmpty()) { + return -3; + } + + if ((g_strDatFileName.Right(4).MakeLower() != ".dat") || (g_strDatFileName == ".dat")) { + g_strDatFileName += ".dat"; + } + + // List of files + CString strArgument; + + for(int i = optind + 1; i < argc; i++) { + strArgument = argv[i]; + + int nArglength = strArgument.GetLength(); + + if ((i == optind + 1) && (nArglength > 1) && (strArgument[0] == '@')) { + CStdioFile fileResponse; + + if (!fileResponse.Open(strArgument.Right(nArglength - 1), CFile::modeRead | CFile::shareDenyWrite | CFile::typeText)) { + return -5; + }; + + CArchive arResponse(&fileResponse, CArchive::load); + + while(arResponse.ReadString(strArgument)) { + if (!strArgument.IsEmpty()) { + g_FileList.Add(strArgument); + } + } + + break; + } + else { + g_FileList.Add(strArgument); + } + } + + if ((g_FileList.GetSize() == 0)) { + if (g_Command == COMMAND_EXTRACT) { + g_FileList.Add("*"); + } + else if ((g_Command != COMMAND_LIST) && (g_Command != COMMAND_SHRINK)) { + return -4; + } + } + +// for(int i = 0; i < g_FileList.GetSize(); i++) { +// printf("g_FileList[%d] = %s\n", i, g_FileList[i]); +// } + + return 0; +} \ No newline at end of file diff --git a/src/dat2.h b/src/dat2.h new file mode 100644 index 0000000..a28b82e --- /dev/null +++ b/src/dat2.h @@ -0,0 +1,31 @@ +#pragma once + +#include "DatFileBase.h" +#include "resource.h" + +// Commands +enum Command { + COMMAND_UNKNOWN, + COMMAND_ADD, + COMMAND_EXTRACT, + COMMAND_DELETE, + COMMAND_LIST, + COMMAND_SHRINK +}; + +// Globals +extern Command g_Command; +extern int g_nCompressMethod; +extern BOOL g_bRecurseIntoDir; +extern BOOL g_bExtractWithoutPaths; +extern CString g_strOutFolder; +extern CString g_strDatFileName; +extern CStringArray g_FileList; +extern CDatFileBase* g_pDatFile; + +// Functions +int OnAdd(); +int OnExtract(); +int OnDelete(); +int OnList(); +int OnShrink(); diff --git a/src/dat2.rc b/src/dat2.rc new file mode 100644 index 0000000..d61738f --- /dev/null +++ b/src/dat2.rc @@ -0,0 +1,114 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Russian resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +#ifdef _WIN32 +LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +#pragma code_page(1251) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // Russian resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,3,2,0 + PRODUCTVERSION 2,3,2,0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Anchorite (TeamX)" + VALUE "FileDescription", "Fallout dat-file packer/unpacker" + VALUE "FileVersion", "2, 3, 2, 0" + VALUE "InternalName", "Fallout dat-file packer/unpacker" + VALUE "LegalCopyright", "Copyright (C) Anchorite (TeamX), 2004-2006" + VALUE "OriginalFilename", "dat2.exe" + VALUE "ProductName", "Fallout dat-file packer/unpacker" + VALUE "ProductVersion", "2, 3, 2, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/dat2.sln b/src/dat2.sln new file mode 100644 index 0000000..89698d6 --- /dev/null +++ b/src/dat2.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dat2", "dat2.vcproj", "{00920866-F659-4AF7-87AF-FE86A97044CC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {00920866-F659-4AF7-87AF-FE86A97044CC}.Debug|Win32.ActiveCfg = Debug|Win32 + {00920866-F659-4AF7-87AF-FE86A97044CC}.Debug|Win32.Build.0 = Debug|Win32 + {00920866-F659-4AF7-87AF-FE86A97044CC}.Release|Win32.ActiveCfg = Release|Win32 + {00920866-F659-4AF7-87AF-FE86A97044CC}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/dat2.vcproj b/src/dat2.vcproj new file mode 100644 index 0000000..db6c74b --- /dev/null +++ b/src/dat2.vcproj @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/stdafx.cpp b/src/stdafx.cpp new file mode 100644 index 0000000..dd4fd0b --- /dev/null +++ b/src/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// dat2.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/src/stdafx.h b/src/stdafx.h new file mode 100644 index 0000000..a28a211 --- /dev/null +++ b/src/stdafx.h @@ -0,0 +1,19 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#define WINVER 0x0410 +#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit + +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers +#endif + +#include +#include // MFC core and standard components +#include // MFC extensions + +#include