Initial commit of Command & Conquer Renegade source code.

This commit is contained in:
LFeenanEA
2025-02-27 16:39:46 +00:00
parent 74ab8fa5e0
commit 58ed459113
4918 changed files with 1366710 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stdafx.h"
#include "avassetsuck.h"
#include "ffactory.h"
#include "mixfile.h"
#include "rawfile.h"
#include "bittype.h"
#include "mixcombiningdialog.h"
AVAssetSuckerClass::AVAssetSuckerClass(void) :
Dialog(NULL)
{
}
void AVAssetSuckerClass::Suck(char *input_file, char *output_file)
{
strcpy(InputFile, input_file);
strcpy(OutputFile, output_file);
//
// Kick off the worker thread...
//
::AfxBeginThread (Do_Stuff, (LPVOID)this);
//
// Show the UI
//
MixCombiningDialogClass dialog;
Dialog = &dialog;
dialog.DoModal();
}
unsigned int AVAssetSuckerClass::Do_Stuff(void *param)
{
((AVAssetSuckerClass*)param)->Thread_Suck();
return(1);
}
void AVAssetSuckerClass::Thread_Suck(void)
{
char name[_MAX_PATH];
while (Dialog == NULL) {
Sleep(0);
}
/*
** Get just the file name.
*/
char justname[_MAX_PATH];
_splitpath(InputFile, NULL, NULL, justname, NULL);
char text[_MAX_PATH + 128];
sprintf(text, "Copying files from %s...", justname);
Dialog->Set_Title("Stripping AV assets...");
Dialog->Set_Status_Text(text);
Dialog->Set_Progress_Percent (0);
MixFileFactoryClass mix_in(InputFile, _TheFileFactory);
if (mix_in.Is_Valid() && mix_in.Build_Internal_Filename_List()) {
/*
** Get the list of files in the source mix file.
*/
DynamicVectorClass<StringClass> filename_list;
mix_in.Get_Filename_List(filename_list);
/*
** Create the output mix file.
*/
MixFileCreator mix_out(OutputFile);
/*
** Loop through all the files copying anything that isn't audio or texture.
*/
for (int i=0 ; i<filename_list.Count() ; i++) {
strcpy(name, filename_list[i].Peek_Buffer());
strupr(name);
if (strstr(name, ".WAV") == 0) {
if (strstr(name, ".TGA") == 0) {
if (strstr(name, ".DDS") == 0) {
if (strstr(name, ".MP3") == 0) {
Copy_File(&mix_in, &mix_out, filename_list[i].Peek_Buffer());
}
}
}
}
Dialog->Set_Progress_Percent((float)i / float(filename_list.Count() + 1));
}
}
Dialog->PostMessage(WM_COMMAND, MAKELPARAM(IDOK, BN_CLICKED));
}
void AVAssetSuckerClass::Copy_File(MixFileFactoryClass *src_mix, MixFileCreator *dest_mix, char *filename)
{
//
// Get the file data from the source mix
//
FileClass *src_file = src_mix->Get_File (filename);
src_file->Open ();
int size = src_file->Size();
//
// Create a temporary destination file for the data
//
char temp_file_name[_MAX_PATH];
char temp_path[_MAX_PATH];
int chars = GetTempPath(_MAX_PATH, temp_path);
if (chars) {
int res = GetTempFileName(temp_path, "MIX", 0, temp_file_name);
if (res == 0) {
WWDEBUG_SAY(("GetTempFileName failed with error code %d\n", GetLastError()));
} else {
RawFileClass temp_file(temp_file_name);
if (temp_file.Open(RawFileClass::WRITE)) {
//
// Save the data in the temp file.
//
void *bigbuf = new char [size + 1024];
src_file->Read(bigbuf, size);
temp_file.Write(bigbuf, size);
temp_file.Close();
//
// Add the temp file to the mix file.
//
dest_mix->Add_File(temp_file_name, filename);
//
// Delete the temp file.
//
DeleteFile(temp_file_name);
}
}
}
src_mix->Return_File(src_file);
}

View File

@@ -0,0 +1,51 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef _AVASSETSUCK_H
#define _AVASSETSUCK_H
class MixFileFactoryClass;
class MixFileCreator;
class MixCombiningDialogClass;
class AVAssetSuckerClass
{
public:
AVAssetSuckerClass(void);
void Suck(char *input_file, char *output_file);
static unsigned int Do_Stuff(void *param);
void Thread_Suck(void);
private:
void Copy_File(MixFileFactoryClass *src_mix, MixFileCreator *dest_mix, char *filename);
MixCombiningDialogClass *Dialog;
char InputFile[1024];
char OutputFile[1024];
};
#endif //_AVASSETSUCK_H

View File

@@ -0,0 +1,747 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MainFrm.cpp : implementation of the CMainFrame class
//
#include "stdafx.h"
#include "mixviewer.h"
#include "mainfrm.h"
#include "wwstring.h"
#include "duplicatecombiner.h"
#include "wwfile.h"
#include "ffactory.h"
#include "mixfile.h"
#include "avassetsuck.h"
#include "mixpatchmaker.h"
#include "ffactory.h"
#include "mixfile.h"
#include "mixviewerdoc.h"
#include "makemixfiledialog.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(IDM_COMBINE_DUPLICATES, OnCombineDuplicates)
ON_COMMAND(IDM_CREATE_MIX_FILE, OnCreateMixFile)
ON_COMMAND(IDM_EXPORT_FILES, OnExportFiles)
ON_COMMAND(IDM_REMOVE_AV_ASSETS, OnRemoveAVAssets)
ON_COMMAND(IDM_MAKE_MIX_PATCH, OnMakeMixPatch)
ON_WM_DROPFILES()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
/////////////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
// TODO: add member initialization code here
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
////////////////////////////////////////////////////////////////////////////
//
// Get_Filename_From_Path
//
////////////////////////////////////////////////////////////////////////////
CString
Get_Filename_From_Path (LPCTSTR path)
{
// Find the last occurance of the directory deliminator
LPCTSTR filename = ::strrchr (path, '\\');
if (filename != NULL) {
// Increment past the directory deliminator
filename ++;
} else {
filename = path;
}
// Return the filename part of the path
return CString (filename);
}
////////////////////////////////////////////////////////////////////////////
//
// Strip_Filename_From_Path
//
////////////////////////////////////////////////////////////////////////////
CString
Strip_Filename_From_Path (LPCTSTR path)
{
// Copy the path to a buffer we can modify
TCHAR temp_path[MAX_PATH];
::lstrcpy (temp_path, path);
// Find the last occurance of the directory deliminator
LPTSTR filename = ::strrchr (temp_path, '\\');
if (filename != NULL) {
// Strip off the filename
filename[0] = 0;
} else if ((temp_path[1] != ':') && (temp_path[1] != '\\')) {
temp_path[0] = 0;
}
// Return the path only
return StringClass (temp_path);
}
/////////////////////////////////////////////////////////////////////////////
//
// OnCombineDuplicates
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::OnCombineDuplicates (void)
{
CFileDialog dialog ( TRUE,
".dat",
"always.dat",
OFN_HIDEREADONLY | OFN_EXPLORER,
"Mix File (*.dat, *.mix)|*.dat;*.mix||",
this);
dialog.m_ofn.lpstrTitle = "Pick Shared Mix File";
if (dialog.DoModal () == IDOK) {
DuplicateRemoverClass combiner;
//
// Determine what directory to search
//
StringClass full_path = dialog.GetPathName ();
StringClass directory = Strip_Filename_From_Path (full_path);
combiner.Set_Destination_File (full_path);
WIN32_FIND_DATA find_info = { 0 };
BOOL keep_going = TRUE;
CString search_mask = directory + "\\*.mix";
//
// Loop over all the mix files in the search directory
//
int count = 0;
for (HANDLE find_handle = ::FindFirstFile (search_mask, &find_info);
(find_handle != INVALID_HANDLE_VALUE) && keep_going;
keep_going = ::FindNextFile (find_handle, &find_info))
{
//
// Check to make sure this isn't a directory
//
if (!(find_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
StringClass full_path = directory;
full_path += "\\";
full_path += find_info.cFileName;
combiner.Add_Mix_File (full_path);
count ++;
}
}
//
// Close the handle we needed for the file find routines
//
if (find_handle != INVALID_HANDLE_VALUE) {
::FindClose (find_handle);
}
//
// Combine the files (if necessary)
//
if (count > 0) {
combiner.Process ();
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnCreateMixFile
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::OnCreateMixFile (void)
{
MakeMixFileDialogClass dialog( this );
dialog.DoModal();
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnExportFiles
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::OnExportFiles (void)
{
StringClass current_filename;
CDocument * doc = GetActiveDocument();
if ( doc != NULL ) {
current_filename = doc->GetPathName();
}
if ( !current_filename.Is_Empty() ) {
DynamicVectorClass<StringClass> filenames;
MixFileFactoryClass mix_factory (current_filename, _TheFileFactory);
if ( mix_factory.Build_Filename_List( filenames ) ) {
// Make the destination folder
StringClass export_path = current_filename;
export_path += " Files";
int result = (int)::CreateDirectory( export_path, NULL );
int error = ::GetLastError();
if ( result != 0 || error == ERROR_ALREADY_EXISTS ) {
bool read_error = false;
bool write_error = false;
for (int index = 0; index < filenames.Count (); index ++) {
StringClass source_name = filenames[index];
StringClass dest_name;
dest_name = export_path;
dest_name += "\\";
dest_name += filenames[index];
// If the filename contains a /, create the directory
if ( ::strchr( filenames[index], '\\' ) != NULL ) {
StringClass dest_folder = dest_name;
int length = ::strrchr( dest_folder, '\\' ) - dest_folder;
dest_folder.Erase( length, dest_folder.Get_Length() - length );
int result = (int)::CreateDirectory( dest_folder, NULL );
int error = ::GetLastError();
if ( result == 0 && error != ERROR_ALREADY_EXISTS ) {
StringClass message;
message.Format ("Failed to create folder %s.", dest_folder );
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
return;
}
}
FileClass * source_file = mix_factory.Get_File( source_name );
FileClass * dest_file = _TheFileFactory->Get_File( dest_name );
if ( dest_file ) {
if ( dest_file->Open( FileClass::WRITE ) == 0 ) {
StringClass message;
message.Format ("Failed to open %s for writing.", dest_name );
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
return;
}
}
if ( source_file ) {
if ( source_file->Open() == 0 ) {
StringClass message;
message.Format ("Failed to open %s for reading.", source_name );
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
return;
}
}
if ( source_file && source_file->Is_Available() &&
dest_file && dest_file->Is_Available() ) {
int length = source_file->Size();
unsigned char file_buffer[4096];
while ( length > 0 ) {
int amount = min ( (int)length, (int)sizeof( file_buffer ) );
if ( source_file->Read( &(file_buffer[0]), amount ) != amount ) {
read_error = true;
length = 0;
}
if ( dest_file->Write( &file_buffer[0], amount ) != amount ) {
write_error = true;
length = 0;
}
length -= amount;
}
}
if ( source_file != NULL ) {
mix_factory.Return_File( source_file );
}
if ( dest_file != NULL ) {
_TheFileFactory->Return_File( dest_file );
}
if ( read_error ) {
StringClass message;
message.Format ("Read Error on %s.", source_name );
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
return;
}
if ( write_error ) {
StringClass message;
message.Format ("Write Error on %s.", dest_name );
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
return;
}
// filenames[index];
}
} else {
StringClass message;
message.Format ("Failed to create folder %s.", export_path);
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
}
} else {
StringClass message;
message.Format ("Error reading the filename list from %s.", current_filename);
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
}
} else {
StringClass message;
message.Format ("No Current Mix File.");
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnRemoveAVAssets
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::OnRemoveAVAssets (void)
{
CFileDialog dialog(true, ".mix", NULL, OFN_ALLOWMULTISELECT | OFN_HIDEREADONLY | OFN_EXPLORER, "Mix File (*.dat, *.mix)|*.dat;*.mix||", this);
dialog.m_ofn.lpstrTitle = "Pick Mix Files";
char *file_name_buffer = new char [65536];
*file_name_buffer = 0;
dialog.m_ofn.lpstrFile = file_name_buffer;
dialog.m_ofn.nMaxFile = 65535;
if (dialog.DoModal () == IDOK) {
//
// Process each mix file and put the stripped mix file into a 'temp' subdirectory under the current one.
//
POSITION pos = dialog.GetStartPosition();
while (pos != NULL) {
StringClass file_name = dialog.GetNextPathName(pos);
//
// Get just the path portion.
//
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char path[_MAX_PATH];
char name[_MAX_PATH];
char ext[_MAX_PATH];
_splitpath(file_name, drive, dir, name, ext);
//
// Make sure the temp directory exists.
//
strcat(dir, "temp\\");
_makepath(path, drive, dir, NULL, NULL);
CreateDirectory(path, NULL);
//
// Make the output file name.
//
char output_file[_MAX_PATH];
_makepath(output_file, drive, dir, name, ext);
AVAssetSuckerClass sucker;
sucker.Suck(file_name.Peek_Buffer(), output_file);
}
}
delete [] file_name_buffer;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnMakeMixPatch
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::OnMakeMixPatch(void)
{
//
// Ask for the name of the old source mix file.
//
CFileDialog dialog(true, ".mix", NULL, OFN_HIDEREADONLY | OFN_EXPLORER, "Mix File (*.dat, *.mix)|*.dat;*.mix||", this);
dialog.m_ofn.lpstrTitle = "Pick Old Source Mix File";
char file_name_buffer[1024];
file_name_buffer[0] = 0;
dialog.m_ofn.lpstrFile = file_name_buffer;
dialog.m_ofn.nMaxFile = 1024;
if (dialog.DoModal () == IDOK) {
//
// Pull the name of the old source mix file.
//
POSITION pos = dialog.GetStartPosition();
StringClass old_file_name = dialog.GetNextPathName(pos);
//
// Ask for the name of the new source mix file.
//
CFileDialog dialog2(true, ".mix", NULL, OFN_HIDEREADONLY | OFN_EXPLORER, "Mix File (*.dat, *.mix)|*.dat;*.mix||", this);
dialog2.m_ofn.lpstrTitle = "Pick New Source Mix File";
file_name_buffer[0] = 0;
dialog2.m_ofn.lpstrFile = file_name_buffer;
dialog2.m_ofn.nMaxFile = 1024;
if (dialog2.DoModal () == IDOK) {
//
// Pull the name of the new source mix file.
//
pos = dialog2.GetStartPosition();
StringClass new_file_name = dialog2.GetNextPathName(pos);
//
// Ask for the name of the output mix file.
//
CFileDialog dialog3(true, ".mix", NULL, OFN_HIDEREADONLY | OFN_EXPLORER, "Mix File (*.dat, *.mix)|*.dat;*.mix||", this);
dialog3.m_ofn.lpstrTitle = "Pick Output Patch Mix File";
file_name_buffer[0] = 0;
dialog3.m_ofn.lpstrFile = file_name_buffer;
dialog3.m_ofn.nMaxFile = 1024;
if (dialog3.DoModal () == IDOK) {
//
// Pull the name of the new source mix file.
//
pos = dialog3.GetStartPosition();
StringClass out_file_name = dialog3.GetNextPathName(pos);
//
// Ask for the directory containing the old source art.
//
char path[_MAX_PATH + 256];
BROWSEINFO binfo;
binfo.hwndOwner = NULL;
binfo.pidlRoot = NULL;
binfo.pszDisplayName = path;
binfo.lpszTitle = "Select Old Source Art Directory";
binfo.ulFlags = 0;
binfo.lpfn = NULL;
binfo.lParam = 0;
binfo.iImage = 0;
LPITEMIDLIST itemptr = SHBrowseForFolder(&binfo);
if (itemptr) {
char old_art_dir[_MAX_PATH + 256];
if (SHGetPathFromIDList(itemptr, old_art_dir)) {
//
// Ask for the directory containing the new source art.
//
char path[_MAX_PATH + 256];
BROWSEINFO binfo;
binfo.hwndOwner = NULL;
binfo.pidlRoot = NULL;
binfo.pszDisplayName = path;
binfo.lpszTitle = "Select New Source Art Directory";
binfo.ulFlags = 0;
binfo.lpfn = NULL;
binfo.lParam = 0;
binfo.iImage = 0;
itemptr = SHBrowseForFolder(&binfo);
if (itemptr) {
char new_art_dir[_MAX_PATH + 256];
if (SHGetPathFromIDList(itemptr, new_art_dir)) {
MixPatchMakerClass patcher;
patcher.Make_Patch(old_file_name.Peek_Buffer(), new_file_name.Peek_Buffer(), out_file_name.Peek_Buffer(), old_art_dir, new_art_dir);
}
}
}
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// WindowProc
//
/////////////////////////////////////////////////////////////////////////////
LRESULT
CMainFrame::WindowProc
(
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
return CFrameWnd::WindowProc(message, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDropFiles
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::OnDropFiles (HDROP hDropInfo)
{
SetActiveWindow ();
CWinApp *win_app = AfxGetApp ();
ASSERT (win_app != NULL);
//
// Get the count of files from the drop query
//
int file_count = (int)::DragQueryFile (hDropInfo, (UINT)-1, NULL, 0);
if (file_count > 0) {
CMixViewerDoc *doc = (CMixViewerDoc *)GetActiveDocument ();
if (file_count == 1) {
//
// Get the filename...
//
TCHAR filename[_MAX_PATH];
::DragQueryFile (hDropInfo, 0, filename, _MAX_PATH);
//
// Get the extension from the filename
//
char extension[_MAX_EXT] = { 0 };
::_splitpath (filename, NULL, NULL, NULL, extension);
//
// Is this a mix file, or should we be adding this file to the mix?
//
if ( ::lstrcmpi (extension, ".mix") == 0 ||
::lstrcmpi (extension, ".dat") == 0 ||
::lstrcmpi (extension, ".dbs") == 0)
{
win_app->OpenDocumentFile (filename);
} else {
Add_To_Mix_File (doc->GetPathName (), filename);
doc->Reload_Views ();
}
} else {
DynamicVectorClass<StringClass> file_list;
//
// Loop over each of the dropped files and add them to the current mix file
//
for (int index = 0; index < file_count; index ++) {
//
// Add this file to a list so we can batch add all the files...
//
TCHAR filename[_MAX_PATH];
::DragQueryFile (hDropInfo, index, filename, _MAX_PATH);
file_list.Add (filename);
}
::DragFinish(hDropInfo);
//
// Add the mix files to the list
//
Add_To_Mix_File (doc->GetPathName (), file_list);
doc->Reload_Views ();
}
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Add_To_Mix_File
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::Add_To_Mix_File (const char *mix_filename, const char *filename)
{
DynamicVectorClass<StringClass> file_list;
file_list.Add (filename);
Add_To_Mix_File (mix_filename, file_list);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Add_To_Mix_File
//
/////////////////////////////////////////////////////////////////////////////
void
CMainFrame::Add_To_Mix_File (const char *mix_filename, DynamicVectorClass<StringClass> &new_file_list)
{
//
// Set the current directory...
//
CString path = Strip_Filename_From_Path (mix_filename);
if (path.GetLength () > 0) {
::SetCurrentDirectory (path);
}
//
// Get access to the mix file in qestion
//
MixFileFactoryClass *mix_factory = new MixFileFactoryClass (mix_filename, _TheFileFactory);
if (mix_factory->Is_Valid () && mix_factory->Build_Internal_Filename_List ()) {
//
// Now add the new files into the mix file...
//
for (int index = 0; index < new_file_list.Count (); index ++) {
CString filename = ::Get_Filename_From_Path (new_file_list[index]);
mix_factory->Delete_File (filename);
mix_factory->Add_File (new_file_list[index], filename);
}
//
// Do it!
//
mix_factory->Flush_Changes ();
}
//
// Free the mix factory
//
delete mix_factory;
mix_factory = NULL;
return ;
}

View File

@@ -0,0 +1,96 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MainFrm.h : interface of the CMainFrame class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MAINFRM_H__BA36CCDC_B39E_4972_B9DC_A531CDEF5E4B__INCLUDED_)
#define AFX_MAINFRM_H__BA36CCDC_B39E_4972_B9DC_A531CDEF5E4B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "wwstring.h"
#include "vector.h"
CString Strip_Filename_From_Path (LPCTSTR path);
class CMainFrame : public CFrameWnd
{
protected: // create from serialization only
CMainFrame();
DECLARE_DYNCREATE(CMainFrame)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMainFrame)
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected: // control bar embedded members
CStatusBar m_wndStatusBar;
CToolBar m_wndToolBar;
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnCombineDuplicates();
afx_msg void OnRemoveAVAssets();
afx_msg void OnMakeMixPatch();
afx_msg void OnDropFiles(HDROP hDropInfo);
afx_msg void OnCreateMixFile();
afx_msg void OnExportFiles();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
///////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////
void Add_To_Mix_File (const char *mix_filename, const char *filename);
void Add_To_Mix_File (const char *mix_filename, DynamicVectorClass<StringClass> &new_file_list);
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAINFRM_H__BA36CCDC_B39E_4972_B9DC_A531CDEF5E4B__INCLUDED_)

View File

@@ -0,0 +1,219 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MakeMixFileDialog.cpp : implementation file
//
#include "stdafx.h"
#include "mixviewer.h"
#include "MakeMixFileDialog.h"
#include "wwstring.h"
#include "MainFrm.h"
#include "mixfile.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// MakeMixFileDialogClass dialog
MakeMixFileDialogClass::MakeMixFileDialogClass(CWnd* pParent /*=NULL*/)
: CDialog(MakeMixFileDialogClass::IDD, pParent)
{
//{{AFX_DATA_INIT(MakeMixFileDialogClass)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}
void MakeMixFileDialogClass::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(MakeMixFileDialogClass)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(MakeMixFileDialogClass, CDialog)
//{{AFX_MSG_MAP(MakeMixFileDialogClass)
ON_BN_CLICKED(IDC_BROWSE_FILE, OnBrowseFile)
ON_BN_CLICKED(IDC_BROWSE_DIR, OnBrowseDir)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// MakeMixFileDialogClass message handlers
BOOL MakeMixFileDialogClass::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
/*
**
*/
unsigned MakeMixFileDialogClass::Add_Files (const StringClass &basepath, const StringClass &subpath, MixFileCreator &mixfile)
{
const char wildcardname [] = "*.*";
unsigned filecount;
StringClass findfilepathname;
WIN32_FIND_DATA finddata;
HANDLE handle;
filecount = 0;
if (basepath.Get_Length() > 0) {
findfilepathname = basepath;
findfilepathname += "\\";
}
if (subpath.Get_Length() > 0) {
findfilepathname += subpath;
findfilepathname += "\\";
}
findfilepathname += wildcardname;
handle = FindFirstFile (findfilepathname, &finddata);
if (handle != INVALID_HANDLE_VALUE) {
bool done;
done = false;
while (!done) {
// Filter out system files.
if (finddata.cFileName [0] != '.') {
StringClass subpathname;
if (subpath.Get_Length() > 0) {
subpathname += subpath;
subpathname += "\\";
}
subpathname += finddata.cFileName;
// Is it a subdirectory?
if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
// Recurse on subdirectory.
filecount += Add_Files (basepath, subpathname, mixfile);
} else {
StringClass fullpathname;
if (basepath.Get_Length() > 0) {
fullpathname += basepath;
fullpathname += "\\";
}
if (subpath.Get_Length() > 0) {
fullpathname += subpath;
fullpathname += "\\";
}
fullpathname += finddata.cFileName;
if ( MixFilename != fullpathname ) {
mixfile.Add_File (fullpathname, subpathname);
filecount++;
}
}
}
done = !FindNextFile (handle, &finddata);
}
}
return (filecount);
}
void MakeMixFileDialogClass::OnOK()
{
CString mix_name;
GetDlgItemText( IDC_BROWSE_FILE_NAME, mix_name );
CString dir_name;
GetDlgItemText( IDC_BROWSE_DIR_NAME, dir_name );
if ( mix_name.IsEmpty() ) {
StringClass message;
message.Format ("Invalid Mix File.");
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
} else if ( dir_name.IsEmpty() ) {
StringClass message;
message.Format ("Invalid Source Directory.");
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
} else {
MixFilename = mix_name;
MixFileCreator mixfile (mix_name);
StringClass basepath (dir_name);
StringClass subpath;
StringClass message;
int filecount = Add_Files (basepath, subpath, mixfile);
if (filecount > 0) {
message.Format ("%u files added\n", filecount);
} else {
message.Format ("No files found in source directory\n");
}
MessageBox (message, "Mix File Created", MB_OK);
CDialog::OnOK();
}
}
void MakeMixFileDialogClass::OnBrowseFile()
{
CString old_name;
GetDlgItemText( IDC_BROWSE_FILE_NAME, old_name );
CFileDialog dialog ( TRUE,
".mix",
old_name,
OFN_HIDEREADONLY | OFN_EXPLORER,
"Mix File (*.mix)|*.mix||",
this);
dialog.m_ofn.lpstrTitle = "Pick Mix File to Create";
if (dialog.DoModal () == IDOK) {
SetDlgItemText( IDC_BROWSE_FILE_NAME, dialog.GetPathName () );
}
}
void MakeMixFileDialogClass::OnBrowseDir()
{
CString old_name;
GetDlgItemText( IDC_BROWSE_DIR_NAME, old_name );
CFileDialog dialog ( TRUE,
NULL, //".",
old_name,
OFN_HIDEREADONLY | OFN_EXPLORER,
NULL, //"Mix File (*.mix)|*.mix||",
this);
dialog.m_ofn.lpstrTitle = "Pick A File In the Root Source Directory";
if (dialog.DoModal () == IDOK) {
StringClass filename = dialog.GetPathName ();
StringClass directory = Strip_Filename_From_Path (filename);
SetDlgItemText( IDC_BROWSE_DIR_NAME, directory );
}
}

View File

@@ -0,0 +1,72 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(AFX_MAKEMIXFILEDIALOG_H__8A52B67D_3497_4915_825C_199D6EC5995D__INCLUDED_)
#define AFX_MAKEMIXFILEDIALOG_H__8A52B67D_3497_4915_825C_199D6EC5995D__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MakeMixFileDialog.h : header file
//
#include "mixfile.h"
/////////////////////////////////////////////////////////////////////////////
// MakeMixFileDialogClass dialog
class MakeMixFileDialogClass : public CDialog
{
// Construction
public:
MakeMixFileDialogClass(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(MakeMixFileDialogClass)
enum { IDD = IDD_MAKE_MIX_FILE };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(MakeMixFileDialogClass)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
unsigned Add_Files (const StringClass &basepath, const StringClass &subpath, MixFileCreator &mixfile);
StringClass MixFilename;
// Generated message map functions
//{{AFX_MSG(MakeMixFileDialogClass)
virtual BOOL OnInitDialog();
virtual void OnOK();
afx_msg void OnBrowseFile();
afx_msg void OnBrowseDir();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAKEMIXFILEDIALOG_H__8A52B67D_3497_4915_825C_199D6EC5995D__INCLUDED_)

View File

@@ -0,0 +1,122 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MixCombiningDialog.cpp : implementation file
//
#include "stdafx.h"
#include "MixViewer.h"
#include "MixCombiningDialog.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
//
// MixCombiningDialogClass
//
/////////////////////////////////////////////////////////////////////////////
MixCombiningDialogClass::MixCombiningDialogClass(CWnd* pParent /*=NULL*/)
: CDialog(MixCombiningDialogClass::IDD, pParent)
{
//{{AFX_DATA_INIT(MixCombiningDialogClass)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// DoDataExchange
//
/////////////////////////////////////////////////////////////////////////////
void
MixCombiningDialogClass::DoDataExchange (CDataExchange *pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(MixCombiningDialogClass)
DDX_Control(pDX, IDC_PROGRESS, ProgressCtrl);
//}}AFX_DATA_MAP
return ;
}
BEGIN_MESSAGE_MAP(MixCombiningDialogClass, CDialog)
//{{AFX_MSG_MAP(MixCombiningDialogClass)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//
// OnInitDialog
//
/////////////////////////////////////////////////////////////////////////////
BOOL
MixCombiningDialogClass::OnInitDialog (void)
{
CDialog::OnInitDialog ();
ProgressCtrl.SetPos (0);
ProgressCtrl.SetRange (0, 100);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// Set_Status_Text
//
/////////////////////////////////////////////////////////////////////////////
void
MixCombiningDialogClass::Set_Status_Text (const char *text)
{
while (!::IsWindow(m_hWnd)) {}
SetDlgItemText (IDC_STATUS, text);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Set_Progress_Percent
//
/////////////////////////////////////////////////////////////////////////////
void
MixCombiningDialogClass::Set_Progress_Percent (float percent)
{
while (!::IsWindow(m_hWnd)) {}
ProgressCtrl.SetPos ((int)(percent * 100.0f));
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Set_Title
//
/////////////////////////////////////////////////////////////////////////////
void MixCombiningDialogClass::Set_Title(const char *text)
{
while (!::IsWindow(m_hWnd)) {}
SetWindowText(text);
}

View File

@@ -0,0 +1,75 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(AFX_MIXCOMBININGDIALOG_H__F9BADF1D_9DAA_423E_BB9B_85765370E37E__INCLUDED_)
#define AFX_MIXCOMBININGDIALOG_H__F9BADF1D_9DAA_423E_BB9B_85765370E37E__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// MixCombiningDialog.h : header file
//
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
// MixCombiningDialogClass dialog
class MixCombiningDialogClass : public CDialog
{
// Construction
public:
MixCombiningDialogClass(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(MixCombiningDialogClass)
enum { IDD = IDD_COMBINING_DIALOG };
CProgressCtrl ProgressCtrl;
//}}AFX_DATA
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(MixCombiningDialogClass)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
// Generated message map functions
//{{AFX_MSG(MixCombiningDialogClass)
virtual BOOL OnInitDialog();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
////////////////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////////////////
void Set_Status_Text (const char *text);
void Set_Progress_Percent (float percent);
void Set_Title(const char *text);
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MIXCOMBININGDIALOG_H__F9BADF1D_9DAA_423E_BB9B_85765370E37E__INCLUDED_)

View File

@@ -0,0 +1,451 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "stdafx.h"
#include "mixpatchmaker.h"
#include "ffactory.h"
#include "mixfile.h"
#include "rawfile.h"
#include "bittype.h"
#include "mixcombiningdialog.h"
MixPatchMakerClass::MixPatchMakerClass(void) :
Dialog(NULL)
{
}
void MixPatchMakerClass::Make_Patch(char *old_input_file, char *new_input_file, char *output_file, char *old_art_dir, char *new_art_dir)
{
strcpy(OldInputFile, old_input_file);
strcpy(NewInputFile, new_input_file);
strcpy(OutputFile, output_file);
strcpy(OldArtDir, old_art_dir);
strcpy(NewArtDir, new_art_dir);
//
// Kick off the worker thread...
//
::AfxBeginThread(Do_Stuff, (LPVOID)this);
//
// Show the UI
//
MixCombiningDialogClass dialog;
Dialog = &dialog;
dialog.DoModal();
}
unsigned int MixPatchMakerClass::Do_Stuff(void *param)
{
((MixPatchMakerClass*)param)->Thread_Make();
return(1);
}
void MixPatchMakerClass::Thread_Make(void)
{
char name[_MAX_PATH];
char name_compare[_MAX_PATH];
while (Dialog == NULL) {
Sleep(0);
}
/*
** Get just the file name.
*/
char justname[_MAX_PATH];
char justname_new[_MAX_PATH];
_splitpath(OldInputFile, NULL, NULL, justname, NULL);
_splitpath(NewInputFile, NULL, NULL, justname_new, NULL);
char text[_MAX_PATH + 128];
sprintf(text, "Looking for differences between %s and %s...", justname, justname_new);
Dialog->Set_Title("Building patch mixfile...");
Dialog->Set_Status_Text(text);
Dialog->Set_Progress_Percent (0);
MixFileFactoryClass old_mix(OldInputFile, _TheFileFactory);
MixFileFactoryClass new_mix(NewInputFile, _TheFileFactory);
if (new_mix.Is_Valid() && new_mix.Build_Internal_Filename_List()) {
if (old_mix.Is_Valid() && old_mix.Build_Internal_Filename_List()) {
/*
** Get the list of files in the new source mix file.
*/
DynamicVectorClass<StringClass> new_filename_list;
new_mix.Get_Filename_List(new_filename_list);
/*
** Get the list of files in the old source mix file.
*/
DynamicVectorClass<StringClass> old_filename_list;
old_mix.Get_Filename_List(old_filename_list);
/*
** Create the output mix file.
*/
MixFileCreator mix_out(OutputFile);
/*
** Loop through all the files in the new source mix. If a file doesn't exist in the old one, or it does exist but is
** different, then copy it into the output mix file.
*/
for (int i=0 ; i<new_filename_list.Count() ; i++) {
strcpy(name, new_filename_list[i].Peek_Buffer());
strupr(name);
bool copy = false;
if (stricmp(name, "STRINGS.TDB") == 0) {
continue;
}
/*
** Search for the file in the old mixfile.
*/
bool found = false;
for (int j=0 ; j<old_filename_list.Count() ; j++) {
strcpy(name_compare, old_filename_list[j].Peek_Buffer());
if (stricmp(name, name_compare) == 0) {
found = true;
/*
** There's a file with the same name in the old mix file. See if it's byte for byte identical. If it's not
** then we need to use the newer file in the patch mix.
*/
bool same = Compare_File(&new_mix, &old_mix, new_filename_list[i].Peek_Buffer());
if (!same) {
/*
** If it's a .dds (texture) file, compare the source art for changes. The .dds can change even when the
** source art doesn't.
*/
if (strstr(name, ".DDS")) {
char targa_name[_MAX_PATH];
strcpy(targa_name, name);
char *ext = strstr(targa_name, ".DDS");
if (ext) {
strcpy(ext, ".TGA");
/*
** If the two source art files are the same then break out.
*/
if (Compare_Source_Art_File(targa_name)) {
break;
}
}
}
copy = true;
}
break;
}
}
/*
** If the file doesn't exist at all in the older mixfile then it needs to be in the patch mix.
*/
if (!found) {
copy = true;
}
if (copy) {
Copy_File(&new_mix, &mix_out, new_filename_list[i].Peek_Buffer());
}
Dialog->Set_Progress_Percent((float)i / float(new_filename_list.Count() + 1));
}
}
}
Dialog->PostMessage(WM_COMMAND, MAKELPARAM(IDOK, BN_CLICKED));
}
void MixPatchMakerClass::Copy_File(MixFileFactoryClass *src_mix, MixFileCreator *dest_mix, char *filename)
{
//
// Get the file data from the source mix
//
FileClass *src_file = src_mix->Get_File (filename);
src_file->Open ();
int size = src_file->Size();
//
// Create a temporary destination file for the data
//
char temp_file_name[_MAX_PATH];
char temp_path[_MAX_PATH];
int chars = GetTempPath(_MAX_PATH, temp_path);
if (chars) {
int res = GetTempFileName(temp_path, "MIX", 0, temp_file_name);
if (res == 0) {
WWDEBUG_SAY(("GetTempFileName failed with error code %d\n", GetLastError()));
} else {
RawFileClass temp_file(temp_file_name);
if (temp_file.Open(RawFileClass::WRITE)) {
//
// Save the data in the temp file.
//
void *bigbuf = new char [size + 1024];
src_file->Read(bigbuf, size);
temp_file.Write(bigbuf, size);
delete [] bigbuf;
temp_file.Close();
//
// Add the temp file to the mix file.
//
dest_mix->Add_File(temp_file_name, filename);
//
// Delete the temp file.
//
DeleteFile(temp_file_name);
}
}
}
src_mix->Return_File(src_file);
}
/***********************************************************************************************
* MixPatchMakerClass::Compare_File -- Compare two files in seperate mixfiles. *
* *
* *
* *
* INPUT: First mixfile *
* Second mixfile *
* Name of file to compare *
* *
* OUTPUT: true if files are the same *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/5/2002 9:54PM ST : Created *
*=============================================================================================*/
bool MixPatchMakerClass::Compare_File(MixFileFactoryClass *src_mix, MixFileFactoryClass *dest_mix, char *filename)
{
/*
** Get the file data from the source mix
*/
FileClass *src_file = src_mix->Get_File(filename);
int size = src_file->Size();
/*
** Get the file data from the dest mix
*/
FileClass *dest_file = dest_mix->Get_File(filename);
/*
** If the two files are a different size then we know they aren't the same.
*/
if (size != dest_file->Size()) {
src_mix->Return_File(src_file);
dest_mix->Return_File(dest_file);
return(false);
}
/*
** Read the source file into memory.
*/
src_file->Open();
unsigned char *src_data = new unsigned char [size + 32];
src_file->Read(src_data, size);
src_file->Close();
/*
** Read the dest file into memory.
*/
dest_file->Open();
unsigned char *dest_data = new unsigned char [size + 32];
dest_file->Read(dest_data, size);
dest_file->Close();
/*
** Compare them.
*/
bool same = (memcmp(src_data, dest_data, size) == 0) ? true : false;
/*
** Clean up.
*/
delete [] src_data;
delete [] dest_data;
src_mix->Return_File(src_file);
dest_mix->Return_File(dest_file);
return(same);
}
/***********************************************************************************************
* MixPatchMakerClass::Compare_Source_Art_File -- Compare source art .tga files *
* *
* *
* *
* INPUT: Filename *
* *
* OUTPUT: True if same *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/21/2002 4:31PM ST : Created *
*=============================================================================================*/
bool MixPatchMakerClass::Compare_Source_Art_File(char *filename)
{
/*
** Find the file in the old source art directory.
*/
char path_to_old_file[_MAX_PATH + 256];
bool got = Find_File(filename, OldArtDir, path_to_old_file);
if (got) {
/*
** Find the file in the old source art directory.
*/
char path_to_new_file[_MAX_PATH + 256];
got = Find_File(filename, NewArtDir, path_to_new_file);
if (got) {
/*
** Both files exist. Load them and compare.
*/
RawFileClass file1(path_to_old_file);
RawFileClass file2(path_to_new_file);
if (file1.Size() == file2.Size()) {
int size = file1.Size();
unsigned char * buf1 = new unsigned char [size + 1024];
unsigned char * buf2 = new unsigned char [size + 1024];
file1.Read(buf1, size);
file2.Read(buf2, size);
int diff = memcmp(buf1, buf2, size);
delete [] buf1;
delete [] buf2;
if (diff == 0) {
return(true);
}
}
}
}
return(false);
}
/***********************************************************************************************
* MixPatchMakerClass::Find_File -- Find a file in a directory or sub directory *
* *
* *
* *
* INPUT: Name of file to search for *
* Path to start search *
* Ptr to string to receive path/filename of file if found *
* *
* OUTPUT: True if file was found *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/21/2002 8:45PM ST : Created *
*=============================================================================================*/
bool MixPatchMakerClass::Find_File(char *file_name, char *path, char *found_path)
{
/*
** Look in the current directory.
*/
char path_to_file[_MAX_PATH + 256];
char *pointless_pointer = NULL;
int len = SearchPath(path, file_name, NULL, sizeof(path_to_file), path_to_file, &pointless_pointer);
if (len) {
strcpy(found_path, path_to_file);
return(true);
}
/*
** Look for a subdirectory to search.
*/
WIN32_FIND_DATA find_info = { 0 };
HANDLE find_handle;
char search_path[_MAX_PATH + 128];
strcpy(search_path, path);
strcat(search_path, "\\*.*");
find_handle = FindFirstFile(search_path, &find_info);
while (find_handle != INVALID_HANDLE_VALUE) {
if ((find_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
if (strcmp(find_info.cFileName, ".") != 0) {
if (strcmp(find_info.cFileName, "..") != 0) {
char new_dir_name[_MAX_PATH + 128];
strcpy(new_dir_name, path);
strcat(new_dir_name, "\\");
strcat(new_dir_name, find_info.cFileName);
bool found = Find_File(file_name, new_dir_name, found_path);
if (found) {
FindClose(find_handle);
return(true);
}
}
}
}
if (FindNextFile(find_handle, &find_info) == 0) {
FindClose(find_handle);
break;
}
}
return(false);
}

View File

@@ -0,0 +1,56 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#ifndef _MIXPATCHMAKER_H
#define _MIXPATCHMAKER_H
class MixFileFactoryClass;
class MixFileCreator;
class MixCombiningDialogClass;
class MixPatchMakerClass
{
public:
MixPatchMakerClass(void);
void Make_Patch(char *old_input_file, char *new_input_file, char *output_file, char *old_art_dir, char *new_art_dir);
static unsigned int Do_Stuff(void *param);
void Thread_Make(void);
private:
void Copy_File(MixFileFactoryClass *src_mix, MixFileCreator *dest_mix, char *filename);
bool Compare_File(MixFileFactoryClass *src_mix, MixFileFactoryClass *dest_mix, char *filename);
bool Compare_Source_Art_File(char *filename);
bool Find_File(char *file_name, char *path, char *found_path);
MixCombiningDialogClass *Dialog;
char OldInputFile[1024];
char NewInputFile[1024];
char OutputFile[1024];
char OldArtDir[1024];
char NewArtDir[1024];
};
#endif //_MIXPATCHMAKER_H

View File

@@ -0,0 +1,175 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MixViewer.cpp : Defines the class behaviors for the application.
//
#include "stdafx.h"
#include "MixViewer.h"
#include "MainFrm.h"
#include "MixViewerDoc.h"
#include "MixViewerView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMixViewerApp
BEGIN_MESSAGE_MAP(CMixViewerApp, CWinApp)
//{{AFX_MSG_MAP(CMixViewerApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMixViewerApp construction
CMixViewerApp::CMixViewerApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CMixViewerApp object
CMixViewerApp theApp;
/////////////////////////////////////////////////////////////////////////////
// CMixViewerApp initialization
BOOL CMixViewerApp::InitInstance()
{
AfxEnableControlContainer();
// Standard initialization
// If you are not using these features and wish to reduce the size
// of your final executable, you should remove from the following
// the specific initialization routines you do not need.
#ifdef _AFXDLL
Enable3dControls(); // Call this when using MFC in a shared DLL
#else
Enable3dControlsStatic(); // Call this when linking to MFC statically
#endif
// Change the registry key under which our settings are stored.
// TODO: You should modify this string to be something appropriate
// such as the name of your company or organization.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(8); // Load standard INI file options (including MRU)
// Register the application's document templates. Document templates
// serve as the connection between documents, frame windows and views.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMixViewerDoc),
RUNTIME_CLASS(CMainFrame), // main SDI frame window
RUNTIME_CLASS(CMixViewerView));
AddDocTemplate(pDocTemplate);
// Enable DDE Execute open
EnableShellOpen();
RegisterShellFileTypes(TRUE);
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Dispatch commands specified on the command line
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// The one and only window has been initialized, so show and update it.
m_pMainWnd->DragAcceptFiles (TRUE);
m_pMainWnd->ShowWindow (SW_SHOW);
m_pMainWnd->UpdateWindow ();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
// No message handlers
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// App command to run the dialog
void CMixViewerApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
/////////////////////////////////////////////////////////////////////////////
// CMixViewerApp message handlers

View File

@@ -0,0 +1,215 @@
# Microsoft Developer Studio Project File - Name="MixViewer" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=MixViewer - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "MixViewer.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "MixViewer.mak" CFG="MixViewer - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "MixViewer - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "MixViewer - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/Commando/Code/Tools/MixViewer", QSDEAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "MixViewer - Win32 Release"
# PROP BASE Use_MFC 6
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 5
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_AFXDLL" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\..\wwlib" /I "..\..\wwdebug" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /machine:I386
# ADD LINK32 wwlib.lib wwdebug.lib winmm.lib /nologo /subsystem:windows /machine:I386 /libpath:"..\..\libs\profile"
!ELSEIF "$(CFG)" == "MixViewer - Win32 Debug"
# PROP BASE Use_MFC 6
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 5
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_AFXDLL" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\..\wwlib" /I "..\..\wwdebug" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /GZ /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 /nologo /subsystem:windows /debug /machine:I386
# ADD LINK32 wwlib.lib wwdebug.lib winmm.lib /nologo /subsystem:windows /map:"..\..\..\Run\MixViewerD.map" /debug /machine:I386 /out:"..\..\..\Run\MixViewerD.exe" /libpath:"..\..\libs\debug"
!ENDIF
# Begin Target
# Name "MixViewer - Win32 Release"
# Name "MixViewer - Win32 Debug"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\AVAssetSuck.cpp
# End Source File
# Begin Source File
SOURCE=.\duplicatecombiner.cpp
# End Source File
# Begin Source File
SOURCE=.\MainFrm.cpp
# End Source File
# Begin Source File
SOURCE=.\MakeMixFileDialog.cpp
# End Source File
# Begin Source File
SOURCE=.\MixCombiningDialog.cpp
# End Source File
# Begin Source File
SOURCE=.\MixPatchMaker.cpp
# End Source File
# Begin Source File
SOURCE=.\MixViewer.cpp
# End Source File
# Begin Source File
SOURCE=.\MixViewer.rc
# End Source File
# Begin Source File
SOURCE=.\MixViewerDoc.cpp
# End Source File
# Begin Source File
SOURCE=.\MixViewerView.cpp
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\AVAssetSuck.h
# End Source File
# Begin Source File
SOURCE=.\duplicatecombiner.h
# End Source File
# Begin Source File
SOURCE=.\MainFrm.h
# End Source File
# Begin Source File
SOURCE=.\MakeMixFileDialog.h
# End Source File
# Begin Source File
SOURCE=.\MixCombiningDialog.h
# End Source File
# Begin Source File
SOURCE=.\MixPatchMaker.h
# End Source File
# Begin Source File
SOURCE=.\MixViewer.h
# End Source File
# Begin Source File
SOURCE=.\MixViewerDoc.h
# End Source File
# Begin Source File
SOURCE=.\MixViewerView.h
# End Source File
# Begin Source File
SOURCE=.\Resource.h
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\res\icon1.ico
# End Source File
# Begin Source File
SOURCE=.\res\MixViewer.ico
# End Source File
# Begin Source File
SOURCE=.\res\MixViewer.rc2
# End Source File
# Begin Source File
SOURCE=.\res\MixViewerDoc.ico
# End Source File
# Begin Source File
SOURCE=.\res\Toolbar.bmp
# End Source File
# End Group
# Begin Source File
SOURCE=.\ReadMe.txt
# End Source File
# End Target
# End Project

View File

@@ -0,0 +1,67 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MixViewer.h : main header file for the MIXVIEWER application
//
#if !defined(AFX_MIXVIEWER_H__E184F3F7_FBE5_497F_8D2F_730CD788C579__INCLUDED_)
#define AFX_MIXVIEWER_H__E184F3F7_FBE5_497F_8D2F_730CD788C579__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CMixViewerApp:
// See MixViewer.cpp for the implementation of this class
//
class CMixViewerApp : public CWinApp
{
public:
CMixViewerApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMixViewerApp)
public:
virtual BOOL InitInstance();
//}}AFX_VIRTUAL
// Implementation
//{{AFX_MSG(CMixViewerApp)
afx_msg void OnAppAbout();
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MIXVIEWER_H__E184F3F7_FBE5_497F_8D2F_730CD788C579__INCLUDED_)

View File

@@ -0,0 +1,432 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// 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
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
"#define _AFX_NO_OLE_RESOURCES\r\n"
"#define _AFX_NO_TRACKER_RESOURCES\r\n"
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
"\r\n"
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
"#ifdef _WIN32\r\n"
"LANGUAGE 9, 1\r\n"
"#pragma code_page(1252)\r\n"
"#endif //_WIN32\r\n"
"#include ""res\\MixViewer.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
"#include ""afxres.rc"" // Standard components\r\n"
"#endif\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDR_MAINFRAME ICON DISCARDABLE "res\\MixViewer.ico"
IDR_MIXVIETYPE ICON DISCARDABLE "res\\MixViewerDoc.ico"
IDI_ICON1 ICON DISCARDABLE "res\\icon1.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDR_MAINFRAME BITMAP MOVEABLE PURE "res\\Toolbar.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// Toolbar
//
IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15
BEGIN
BUTTON ID_FILE_NEW
BUTTON ID_FILE_OPEN
BUTTON ID_FILE_SAVE
SEPARATOR
BUTTON IDM_COMBINE_DUPLICATES
BUTTON IDM_REMOVE_AV_ASSETS
BUTTON IDM_MAKE_MIX_PATCH
BUTTON ID_APP_ABOUT
END
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_MAINFRAME MENU PRELOAD DISCARDABLE
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&New\tCtrl+N", ID_FILE_NEW
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE
MENUITEM "Save &As...", ID_FILE_SAVE_AS
MENUITEM SEPARATOR
MENUITEM "Combine &Duplicates...", IDM_COMBINE_DUPLICATES
MENUITEM "&Remove Audio and Visual Assets", IDM_REMOVE_AV_ASSETS
MENUITEM "&Build Patch Mixfile", IDM_MAKE_MIX_PATCH
MENUITEM SEPARATOR
MENUITEM "&Create Mix File...", IDM_CREATE_MIX_FILE
MENUITEM "&Export Files...", IDM_EXPORT_FILES
MENUITEM SEPARATOR
MENUITEM "Recent File", ID_FILE_MRU_FILE1, GRAYED
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_APP_EXIT
END
POPUP "&Edit"
BEGIN
MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO
MENUITEM SEPARATOR
MENUITEM "Cu&t\tCtrl+X", ID_EDIT_CUT
MENUITEM "&Copy\tCtrl+C", ID_EDIT_COPY
MENUITEM "&Paste\tCtrl+V", ID_EDIT_PASTE
END
POPUP "&View"
BEGIN
MENUITEM "&Toolbar", ID_VIEW_TOOLBAR
MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR
END
POPUP "&Help"
BEGIN
MENUITEM "&About MixViewer...", ID_APP_ABOUT
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//
IDR_MAINFRAME ACCELERATORS PRELOAD MOVEABLE PURE
BEGIN
"N", ID_FILE_NEW, VIRTKEY, CONTROL
"O", ID_FILE_OPEN, VIRTKEY, CONTROL
"S", ID_FILE_SAVE, VIRTKEY, CONTROL
"Z", ID_EDIT_UNDO, VIRTKEY, CONTROL
"X", ID_EDIT_CUT, VIRTKEY, CONTROL
"C", ID_EDIT_COPY, VIRTKEY, CONTROL
"V", ID_EDIT_PASTE, VIRTKEY, CONTROL
VK_BACK, ID_EDIT_UNDO, VIRTKEY, ALT
VK_DELETE, ID_EDIT_CUT, VIRTKEY, SHIFT
VK_INSERT, ID_EDIT_COPY, VIRTKEY, CONTROL
VK_INSERT, ID_EDIT_PASTE, VIRTKEY, SHIFT
VK_F6, ID_NEXT_PANE, VIRTKEY
VK_F6, ID_PREV_PANE, VIRTKEY, SHIFT
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 235, 55
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About MixViewer"
FONT 8, "MS Sans Serif"
BEGIN
ICON IDR_MAINFRAME,IDC_STATIC,11,17,20,20
LTEXT "MixViewer Version 1.0",IDC_STATIC,40,10,119,8,
SS_NOPREFIX
LTEXT "Copyright (C) 2001",IDC_STATIC,40,25,119,8
DEFPUSHBUTTON "OK",IDOK,178,7,50,14,WS_GROUP
END
IDD_COMBINING_DIALOG DIALOG DISCARDABLE 0, 0, 186, 58
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
CAPTION "Mix Combiner"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "Building File Lists...",IDC_STATUS,7,7,172,22
CONTROL "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,
40,172,11
END
IDD_MAKE_MIX_FILE DIALOG DISCARDABLE 0, 0, 386, 74
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Create Mix File"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "Generate MIX file",IDOK,96,53,86,14
PUSHBUTTON "Cancel",IDCANCEL,204,53,86,14
EDITTEXT IDC_BROWSE_DIR_NAME,65,33,256,14,ES_AUTOHSCROLL
EDITTEXT IDC_BROWSE_FILE_NAME,66,7,256,14,ES_AUTOHSCROLL
PUSHBUTTON "Browse...",IDC_BROWSE_FILE,329,7,50,14
PUSHBUTTON "Browse...",IDC_BROWSE_DIR,329,33,50,14
RTEXT "MIX Filename:",IDC_STATIC,7,7,57,14,SS_CENTERIMAGE
RTEXT "Source Directory:",IDC_STATIC,7,33,57,14,SS_CENTERIMAGE
END
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "MixViewer MFC Application\0"
VALUE "FileVersion", "1, 0, 0, 1\0"
VALUE "InternalName", "MixViewer\0"
VALUE "LegalCopyright", "Copyright (C) 2001\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "MixViewer.EXE\0"
VALUE "ProductName", "MixViewer Application\0"
VALUE "ProductVersion", "1, 0, 0, 1\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_ABOUTBOX, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 228
TOPMARGIN, 7
BOTTOMMARGIN, 48
END
IDD_COMBINING_DIALOG, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 51
END
IDD_MAKE_MIX_FILE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 379
TOPMARGIN, 7
BOTTOMMARGIN, 67
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
IDR_MAINFRAME "MixViewer\n\nMixVie\nMix Files (*.mix)\n.mix\nMixViewer.Document\nMixVie Document"
END
STRINGTABLE PRELOAD DISCARDABLE
BEGIN
AFX_IDS_APP_TITLE "MixViewer"
AFX_IDS_IDLEMESSAGE "Ready"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_INDICATOR_EXT "EXT"
ID_INDICATOR_CAPS "CAP"
ID_INDICATOR_NUM "NUM"
ID_INDICATOR_SCRL "SCRL"
ID_INDICATOR_OVR "OVR"
ID_INDICATOR_REC "REC"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_NEW "Create a new document\nNew"
ID_FILE_OPEN "Open an existing document\nOpen"
ID_FILE_CLOSE "Close the active document\nClose"
ID_FILE_SAVE "Save the active document\nSave"
ID_FILE_SAVE_AS "Save the active document with a new name\nSave As"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_APP_ABOUT "Display program information, version number and copyright\nAbout"
ID_APP_EXIT "Quit the application; prompts to save documents\nExit"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_FILE_MRU_FILE1 "Open this document"
ID_FILE_MRU_FILE2 "Open this document"
ID_FILE_MRU_FILE3 "Open this document"
ID_FILE_MRU_FILE4 "Open this document"
ID_FILE_MRU_FILE5 "Open this document"
ID_FILE_MRU_FILE6 "Open this document"
ID_FILE_MRU_FILE7 "Open this document"
ID_FILE_MRU_FILE8 "Open this document"
ID_FILE_MRU_FILE9 "Open this document"
ID_FILE_MRU_FILE10 "Open this document"
ID_FILE_MRU_FILE11 "Open this document"
ID_FILE_MRU_FILE12 "Open this document"
ID_FILE_MRU_FILE13 "Open this document"
ID_FILE_MRU_FILE14 "Open this document"
ID_FILE_MRU_FILE15 "Open this document"
ID_FILE_MRU_FILE16 "Open this document"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_NEXT_PANE "Switch to the next window pane\nNext Pane"
ID_PREV_PANE "Switch back to the previous window pane\nPrevious Pane"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_WINDOW_SPLIT "Split the active window into panes\nSplit"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_EDIT_CLEAR "Erase the selection\nErase"
ID_EDIT_CLEAR_ALL "Erase everything\nErase All"
ID_EDIT_COPY "Copy the selection and put it on the Clipboard\nCopy"
ID_EDIT_CUT "Cut the selection and put it on the Clipboard\nCut"
ID_EDIT_FIND "Find the specified text\nFind"
ID_EDIT_PASTE "Insert Clipboard contents\nPaste"
ID_EDIT_REPEAT "Repeat the last action\nRepeat"
ID_EDIT_REPLACE "Replace specific text with different text\nReplace"
ID_EDIT_SELECT_ALL "Select the entire document\nSelect All"
ID_EDIT_UNDO "Undo the last action\nUndo"
ID_EDIT_REDO "Redo the previously undone action\nRedo"
END
STRINGTABLE DISCARDABLE
BEGIN
ID_VIEW_TOOLBAR "Show or hide the toolbar\nToggle ToolBar"
ID_VIEW_STATUS_BAR "Show or hide the status bar\nToggle StatusBar"
END
STRINGTABLE DISCARDABLE
BEGIN
AFX_IDS_SCSIZE "Change the window size"
AFX_IDS_SCMOVE "Change the window position"
AFX_IDS_SCMINIMIZE "Reduce the window to an icon"
AFX_IDS_SCMAXIMIZE "Enlarge the window to full size"
AFX_IDS_SCNEXTWINDOW "Switch to the next document window"
AFX_IDS_SCPREVWINDOW "Switch to the previous document window"
AFX_IDS_SCCLOSE "Close the active window and prompts to save the documents"
END
STRINGTABLE DISCARDABLE
BEGIN
AFX_IDS_SCRESTORE "Restore the window to normal size"
AFX_IDS_SCTASKLIST "Activate Task List"
END
STRINGTABLE DISCARDABLE
BEGIN
IDM_COMBINE_DUPLICATES "Combine duplicates from a file set into a shared mix file.\nCombine Duplicates"
IDM_REMOVE_AV_ASSETS "Strip out audio and visual assets from a mixfile.\nRemove Audio and Visual Assets"
IDM_CREATE_MIX_FILE "Creates a MIX file.\nCreate a MIX file"
IDM_EXPORT_FILES "Export all files into a directory.\nExport Files"
IDM_MAKE_MIX_PATCH "Build a patch mixfile from two source mix files.\nBuild Patch Mixfile"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_PROPERTY_RESOURCES
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif //_WIN32
#include "res\MixViewer.rc2" // non-Microsoft Visual C++ edited resources
#include "afxres.rc" // Standard components
#endif
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,171 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MixViewerDoc.cpp : implementation of the CMixViewerDoc class
//
#include "stdafx.h"
#include "mixviewer.h"
#include "mixviewerdoc.h"
#include "mixviewerview.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CMixViewerDoc
IMPLEMENT_DYNCREATE(CMixViewerDoc, CDocument)
BEGIN_MESSAGE_MAP(CMixViewerDoc, CDocument)
//{{AFX_MSG_MAP(CMixViewerDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMixViewerDoc construction/destruction
CMixViewerDoc::CMixViewerDoc()
{
// TODO: add one-time construction code here
}
CMixViewerDoc::~CMixViewerDoc()
{
}
/////////////////////////////////////////////////////////////////////////////
// CMixViewerDoc serialization
void CMixViewerDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
// CMixViewerDoc diagnostics
#ifdef _DEBUG
void CMixViewerDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CMixViewerDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
//
// OnNewDocument
//
/////////////////////////////////////////////////////////////////////////////
BOOL
CMixViewerDoc::OnNewDocument (void)
{
if (!CDocument::OnNewDocument ()) {
return FALSE;
}
//
// Update each view
//
POSITION pos = GetFirstViewPosition ();
while (pos != NULL)
{
CMixViewerView *view = (CMixViewerView *)GetNextView (pos);
view->Reset ();
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnOpenDocument
//
/////////////////////////////////////////////////////////////////////////////
BOOL
CMixViewerDoc::OnOpenDocument (LPCTSTR path)
{
if (!CDocument::OnOpenDocument (path)) {
return FALSE;
}
//
// Start fresh
//
OnNewDocument ();
//
// Update each view
//
POSITION pos = GetFirstViewPosition ();
while (pos != NULL)
{
CMixViewerView *view = (CMixViewerView *)GetNextView (pos);
view->Reload (path);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
//
// Reload_Views
//
/////////////////////////////////////////////////////////////////////////////
void
CMixViewerDoc::Reload_Views (void)
{
//
// Update each view
//
POSITION pos = GetFirstViewPosition ();
while (pos != NULL)
{
CMixViewerView *view = (CMixViewerView *)GetNextView (pos);
view->Reload (GetPathName ());
}
return ;
}

View File

@@ -0,0 +1,79 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MixViewerDoc.h : interface of the CMixViewerDoc class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MIXVIEWERDOC_H__3E44CD42_6816_4308_AD7B_241F70244FF1__INCLUDED_)
#define AFX_MIXVIEWERDOC_H__3E44CD42_6816_4308_AD7B_241F70244FF1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CMixViewerDoc : public CDocument
{
protected: // create from serialization only
CMixViewerDoc();
DECLARE_DYNCREATE(CMixViewerDoc)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMixViewerDoc)
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMixViewerDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CMixViewerDoc)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
void Reload_Views (void);
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MIXVIEWERDOC_H__3E44CD42_6816_4308_AD7B_241F70244FF1__INCLUDED_)

View File

@@ -0,0 +1,340 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MixViewerView.cpp : implementation of the CMixViewerView class
//
#include "stdafx.h"
#include "MixViewer.h"
#include "mixviewerdoc.h"
#include "mixviewerview.h"
#include "ffactory.h"
#include "mixfile.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// Local prototypes
/////////////////////////////////////////////////////////////////////////////
static int CALLBACK MixFilenamesListSortCallback (LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
/////////////////////////////////////////////////////////////////////////////
// CMixViewerView
IMPLEMENT_DYNCREATE(CMixViewerView, CListView)
BEGIN_MESSAGE_MAP(CMixViewerView, CListView)
//{{AFX_MSG_MAP(CMixViewerView)
ON_WM_CREATE()
ON_NOTIFY_REFLECT(LVN_DELETEITEM, OnDeleteitem)
ON_WM_WINDOWPOSCHANGING()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//
// CMixViewerView
//
/////////////////////////////////////////////////////////////////////////////
CMixViewerView::CMixViewerView (void)
{
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// ~CMixViewerView
//
/////////////////////////////////////////////////////////////////////////////
CMixViewerView::~CMixViewerView (void)
{
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// PreCreateWindow
//
/////////////////////////////////////////////////////////////////////////////
BOOL
CMixViewerView::PreCreateWindow (CREATESTRUCT &cs)
{
cs.style |= LVS_REPORT;
return CListView::PreCreateWindow (cs);
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDraw
//
/////////////////////////////////////////////////////////////////////////////
void
CMixViewerView::OnDraw (CDC *pDC)
{
CMixViewerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnInitialUpdate
//
/////////////////////////////////////////////////////////////////////////////
void
CMixViewerView::OnInitialUpdate (void)
{
CListView::OnInitialUpdate ();
//
// Size the column
//
CRect rect;
GetListCtrl ().GetClientRect (&rect);
rect.right -= ::GetSystemMetrics (SM_CXVSCROLL) + 2;
GetListCtrl ().SetColumnWidth (0, rect.Width ());
return ;
}
/////////////////////////////////////////////////////////////////////////////
// CMixViewerView diagnostics
#ifdef _DEBUG
void CMixViewerView::AssertValid() const
{
CListView::AssertValid();
}
void CMixViewerView::Dump(CDumpContext& dc) const
{
CListView::Dump(dc);
}
CMixViewerDoc* CMixViewerView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMixViewerDoc)));
return (CMixViewerDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
//
// Reload
//
/////////////////////////////////////////////////////////////////////////////
void
CMixViewerView::Reload (const char *filename)
{
CurrentFilename = filename;
CMixViewerDoc *document = GetDocument ();
if (document == NULL) {
return ;
}
//
// Start fresh
//
GetListCtrl ().DeleteAllItems ();
//
// Get the filename list from the mix file
//
MixFileFactoryClass mix_factory (filename, _TheFileFactory);
if (mix_factory.Build_Filename_List (FilenameList)) {
//
// Add each filename to the list
//
for (int index = 0; index < FilenameList.Count (); index ++) {
int item_index = GetListCtrl ().InsertItem (index, FilenameList[index]);
if (item_index != -1) {
GetListCtrl ().SetItemData (item_index, (DWORD)new StringClass (FilenameList[index]));
}
}
//
// Sort the data
//
GetListCtrl ().SortItems (MixFilenamesListSortCallback, 0);
} else {
//
// Notify the user
//
StringClass message;
message.Format ("Error reading the filename list from %s.", filename);
MessageBox (message, "Mix File Error", MB_ICONERROR | MB_OK);
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// Reset
//
/////////////////////////////////////////////////////////////////////////////
void
CMixViewerView::Reset (void)
{
GetListCtrl ().DeleteAllItems ();
FilenameList.Delete_All ();
CurrentFilename = "";
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnCreate
//
/////////////////////////////////////////////////////////////////////////////
int
CMixViewerView::OnCreate (LPCREATESTRUCT lpCreateStruct)
{
if (CListView::OnCreate (lpCreateStruct) == -1) {
return -1;
}
//
// Configure the list control
//
GetListCtrl ().SetExtendedStyle (GetListCtrl ().GetExtendedStyle () | LVS_EX_FULLROWSELECT);
GetListCtrl ().InsertColumn (0, "Filename");
return 0;
}
////////////////////////////////////////////////////////////////////////////
//
// MixFilenamesListSortCallback
//
////////////////////////////////////////////////////////////////////////////
int CALLBACK
MixFilenamesListSortCallback
(
LPARAM lParam1,
LPARAM lParam2,
LPARAM lParamSort
)
{
int retval = 0;
//
// Get the data from list control
//
StringClass *item_data1 = (StringClass *)lParam1;
StringClass *item_data2 = (StringClass *)lParam2;
if (item_data1 != NULL && item_data2 != NULL) {
bool is_1_dir = (::strrchr (*item_data1, '\\') != NULL);
bool is_2_dir = (::strrchr (*item_data2, '\\') != NULL);
if (is_1_dir && is_2_dir == false) {
retval = -1;
} else if (is_1_dir == false && is_2_dir) {
retval = 1;
} else {
//
// Do a simple string compare
//
retval = item_data1->Compare_No_Case (*item_data2);
}
}
return retval;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnDeleteitem
//
/////////////////////////////////////////////////////////////////////////////
void
CMixViewerView::OnDeleteitem (NMHDR *pNMHDR, LRESULT *pResult)
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW *)pNMHDR;
*pResult = 0;
//
// Get the string associated with this entry
//
StringClass *string = (StringClass *)GetListCtrl ().GetItemData (pNMListView->iItem);
GetListCtrl ().SetItemData (pNMListView->iItem, 0);
//
// Free the string
//
if (string != NULL) {
delete string;
string = NULL;
}
return ;
}
/////////////////////////////////////////////////////////////////////////////
//
// OnWindowPosChanging
//
/////////////////////////////////////////////////////////////////////////////
void
CMixViewerView::OnWindowPosChanging (WINDOWPOS FAR *lpwndpos)
{
if ((lpwndpos->flags & SWP_NOSIZE) == 0) {
//
// Get the current percent of the column width
//
CRect rect;
GetListCtrl ().GetWindowRect (&rect);
int curr_width = GetListCtrl ().GetColumnWidth (0);
float percent = (float)curr_width / (float)rect.Width ();
//
// Size the column
//
int new_width = int(lpwndpos->cx * percent);
GetListCtrl ().SetColumnWidth (0, new_width);
}
CListView::OnWindowPosChanging (lpwndpos);
return ;
}

View File

@@ -0,0 +1,112 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MixViewerView.h : interface of the CMixViewerView class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_MIXVIEWERVIEW_H__562AE398_6B91_4DA8_B325_73D4EC73EB36__INCLUDED_)
#define AFX_MIXVIEWERVIEW_H__562AE398_6B91_4DA8_B325_73D4EC73EB36__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "resource.h"
#include "vector.h"
#include "wwstring.h"
//////////////////////////////////////////////////////////////////////////////////
//
// CMixViewerView
//
//////////////////////////////////////////////////////////////////////////////////
class CMixViewerView : public CListView
{
protected: // create from serialization only
CMixViewerView();
DECLARE_DYNCREATE(CMixViewerView)
// Attributes
public:
CMixViewerDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMixViewerView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void OnInitialUpdate(); // called first time after construct
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CMixViewerView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CMixViewerView)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDeleteitem(NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnWindowPosChanging(WINDOWPOS FAR* lpwndpos);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
public:
///////////////////////////////////////////////////////////////////////
// Public methods
///////////////////////////////////////////////////////////////////////
void Reload (const char *filename);
void Reset (void);
private:
///////////////////////////////////////////////////////////////////////
// Private member data
///////////////////////////////////////////////////////////////////////
DynamicVectorClass<StringClass> FilenameList;
StringClass CurrentFilename;
};
#ifndef _DEBUG // debug version in MixViewerView.cpp
inline CMixViewerDoc* CMixViewerView::GetDocument()
{ return (CMixViewerDoc*)m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MIXVIEWERVIEW_H__562AE398_6B91_4DA8_B325_73D4EC73EB36__INCLUDED_)

View File

@@ -0,0 +1,33 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by MixViewer.rc
//
#define IDD_ABOUTBOX 100
#define IDR_MAINFRAME 128
#define IDR_MIXVIETYPE 129
#define IDD_COMBINING_DIALOG 130
#define IDI_ICON1 131
#define IDD_MAKE_MIX_FILE 132
#define IDC_STATUS 1000
#define IDC_PROGRESS 1001
#define IDC_BROWSE_DIR_NAME 1002
#define IDC_BROWSE_FILE_NAME 1003
#define IDC_BROWSE_FILE 1004
#define IDC_BROWSE_DIR 1005
#define IDM_COMBINE_DUPLICATES 32771
#define IDM_REMOVE_AV_ASSETS 32773
#define IDM_CREATE_MIX_FILE 32775
#define IDM_EXPORT_FILES 32776
#define IDM_MAKE_MIX_PATCH 32777
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_3D_CONTROLS 1
#define _APS_NEXT_RESOURCE_VALUE 133
#define _APS_NEXT_COMMAND_VALUE 32778
#define _APS_NEXT_CONTROL_VALUE 1006
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -0,0 +1,26 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// stdafx.cpp : source file that includes just the standard includes
// MixViewer.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"

View File

@@ -0,0 +1,46 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#if !defined(AFX_STDAFX_H__FDF881A5_EA5E_4820_A638_5E0BBA8E14D5__INCLUDED_)
#define AFX_STDAFX_H__FDF881A5_EA5E_4820_A638_5E0BBA8E14D5__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxcview.h>
#include <afxdisp.h> // MFC Automation classes
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__FDF881A5_EA5E_4820_A638_5E0BBA8E14D5__INCLUDED_)

View File

@@ -0,0 +1,592 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWAudio *
* *
* $Archive:: /Commando/Code/Tools/MixViewer/duplicatecombiner.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 2/21/02 5:25p $*
* *
* $Revision:: 3 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "stdafx.h"
#include "duplicatecombiner.h"
#include "ffactory.h"
#include "mixfile.h"
#include "rawfile.h"
#include "bittype.h"
#include "mixcombiningdialog.h"
//////////////////////////////////////////////////////////////
//
// DuplicateRemoverClass
//
//////////////////////////////////////////////////////////////
DuplicateRemoverClass::DuplicateRemoverClass (void) :
TempFilenameStart (0),
Dialog (NULL)
{
return ;
}
//////////////////////////////////////////////////////////////
//
// ~DuplicateRemoverClass
//
//////////////////////////////////////////////////////////////
DuplicateRemoverClass::~DuplicateRemoverClass (void)
{
return ;
}
//////////////////////////////////////////////////////////////
//
// Process
//
//////////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Process (void)
{
//
// Kick off the worker thread...
//
::AfxBeginThread (fnThreadProc, (LPVOID)this);
//
// Show the UI
//
MixCombiningDialogClass dialog;
Dialog = &dialog;
dialog.DoModal ();
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// fnThreadProc
//
////////////////////////////////////////////////////////////////////////////
UINT
DuplicateRemoverClass::fnThreadProc (LPVOID pParam)
{
//
// Simply ask the combiner to start processing
//
DuplicateRemoverClass *remover = (DuplicateRemoverClass *)pParam;
if (remover != NULL) {
remover->Internal_Process ();
}
return 1;
}
//////////////////////////////////////////////////////////////
//
// Internal_Process
//
//////////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Internal_Process (void)
{
Make_Temp_Directory ();
//
// Open the source mix files
//
DynamicVectorClass<MixFileFactoryClass *> mix_file_list;
Open_Mix_Files (mix_file_list);
//
// Open the destination mix factory
//
MixFileFactoryClass dest_factory (DestinationMixFilename, _TheFileFactory);
if (dest_factory.Is_Valid () && dest_factory.Build_Internal_Filename_List ()) {
Dialog->Set_Status_Text ("Building temporary files...");
Dialog->Set_Progress_Percent (0);
//
// Loop over each mix file...
//
for (int mix_index = 0; mix_index < mix_file_list.Count (); mix_index ++) {
//
// Get the list of filenames inside this mix file
//
DynamicVectorClass<StringClass> filename_list;
mix_file_list[mix_index]->Get_Filename_List (filename_list);
for (int file_index = 0; file_index < filename_list.Count (); file_index ++) {
StringClass filename = ::strlwr (filename_list[file_index].Peek_Buffer ());
DynamicVectorClass<int> dup_indices;
dup_indices.Add (mix_index);
//
// Try to find this file in any of the other mix files
//
for (int test_mix_index = 0; test_mix_index < mix_file_list.Count (); test_mix_index ++) {
if (test_mix_index != mix_index && Is_File_In_Factory (filename, mix_file_list[test_mix_index])) {
dup_indices.Add (test_mix_index);
}
}
//
// Check to see if this file is already in the "destination" file
//
bool is_in_dest = Is_File_In_Factory (filename, &dest_factory);
//
// Were there any duplicates?
//
if (dup_indices.Count () > 1 || is_in_dest) {
//
// Copy the file from the source to the destination factory
//
if (is_in_dest == false) {
Copy_File (mix_file_list[mix_index], &dest_factory, filename);
}
//
// Remove all the duplicates from the mix files
//
for (int dup_index = 0; dup_index < dup_indices.Count (); dup_index ++) {
mix_file_list[dup_indices[dup_index]]->Delete_File (filename);
}
}
}
//
// Update the UI
//
Dialog->Set_Progress_Percent ((float)mix_index / float(mix_file_list.Count () + 1));
}
//
// Save the changes
//
Dialog->Set_Status_Text ("Reconstructing mix files...");
Dialog->Set_Progress_Percent (0);
dest_factory.Flush_Changes ();
Dialog->Set_Progress_Percent (1.0F / float(mix_file_list.Count () + 1));
for (int index = 0; index < mix_file_list.Count (); index ++) {
mix_file_list[index]->Flush_Changes ();
Dialog->Set_Progress_Percent ((float)index / float(mix_file_list.Count () + 1));
}
Dialog->Set_Progress_Percent (1.0F);
}
//
// Free each of the mix file factories
//
Close_Mix_Files (mix_file_list);
//
// Remove the temporary directory we created
//
Delete_Temp_Directory ();
//
// Close the dialog
//
Dialog->PostMessage (WM_COMMAND, MAKELPARAM (IDOK, BN_CLICKED));
return ;
}
//////////////////////////////////////////////////////////////
//
// Copy_File
//
//////////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Copy_File
(
MixFileFactoryClass * src_mix,
MixFileFactoryClass * dest_mix,
const char * filename
)
{
//
// Get the file data from the source mix
//
FileClass *src_file = src_mix->Get_File (filename);
src_file->Open ();
//
// Create a destination file for the data
//
StringClass full_path;
Get_Temp_Filename (full_path);
RawFileClass dest_file;
dest_file.Set_Name (full_path);
if (dest_file.Open (RawFileClass::WRITE)) {
//
// Copy the data from the source mix file to the destination file
//
int file_size = src_file->Size ();
uint8 buffer[4096];
while (file_size > 0) {
//
// Read the data from the source file
//
int bytes = min (file_size, (int)sizeof (buffer));
int copied_size = src_file->Read (buffer, bytes);
file_size -= copied_size;
if (copied_size <= 0) {
break;
}
//
// Copy the data to the dest file
//
dest_file.Write (buffer, copied_size);
}
//
// Add the file to the destination mix file
//
dest_mix->Add_File (full_path, filename);
//
// Close the temporary data file
//
dest_file.Close ();
}
//
// Return the file
//
src_mix->Return_File (src_file);
return ;
}
//////////////////////////////////////////////////////////////
//
// Open_Mix_Files
//
//////////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Open_Mix_Files (DynamicVectorClass<MixFileFactoryClass *> &list)
{
//
// Loop over all the mix filenames in our list
//
for (int index = 0; index < MixFileList.Count (); index ++) {
//
// Create this mix file factory and add it to our list
//
MixFileFactoryClass *mix_factory = new MixFileFactoryClass (MixFileList[index], _TheFileFactory);
if (mix_factory->Is_Valid () && mix_factory->Build_Internal_Filename_List ()) {
list.Add (mix_factory);
} else {
delete mix_factory;
mix_factory = NULL;
}
//
// Update the UI
//
Dialog->Set_Progress_Percent ((float)index / float(MixFileList.Count () + 1));
}
return ;
}
//////////////////////////////////////////////////////////////
//
// Close_Mix_Files
//
//////////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Close_Mix_Files (DynamicVectorClass<MixFileFactoryClass *> &list)
{
//
// Simply free each entry in the list
//
for (int index = 0; index < list.Count (); index ++) {
delete list[index];
}
list.Delete_All ();
return ;
}
/////////////////////////////////////////////////////////
//
// Make_Temp_Directory
//
/////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Make_Temp_Directory (void)
{
//
// Get the path of the temp directory
//
char temp_dir[MAX_PATH] = { 0 };
::GetTempPath (sizeof (temp_dir), temp_dir);
CString temp_path = Make_Path (temp_dir, "mixcombiner");
//
// Try to find a unique temp directory to store our data
//
int index = 0;
do {
TempDirectory.Format ("%s%.2d.DIR", (const char *)temp_path, index++);
} while (GetFileAttributes (TempDirectory) != 0xFFFFFFFF);
//
// Create the directory
//
::CreateDirectory (TempDirectory, NULL);
::SetCurrentDirectory (TempDirectory);
return ;
}
/////////////////////////////////////////////////////////
//
// Delete_Temp_Directory
//
/////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Delete_Temp_Directory (void)
{
//
// Change the current directory so we can remove the temporary one
//
::SetCurrentDirectory ("c:\\");
//
// Remove the temporary directory
//
Clean_Directory (TempDirectory);
::RemoveDirectory (TempDirectory);
return ;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Clean_Directory
//
//////////////////////////////////////////////////////////////////////////////////
bool
DuplicateRemoverClass::Clean_Directory (LPCTSTR local_dir)
{
bool retval = true;
//
// Build a search mask from the directory
//
StringClass search_mask = StringClass (local_dir) + "\\*.*";
//
// Loop through all the files in this directory and add them
// to our list
//
DynamicVectorClass<StringClass> file_list;
BOOL keep_going = TRUE;
WIN32_FIND_DATA find_info = { 0 };
for (HANDLE hfind = ::FindFirstFile (search_mask, &find_info);
(hfind != INVALID_HANDLE_VALUE) && keep_going;
keep_going = ::FindNextFile (hfind, &find_info))
{
//
// If this file isn't a directory, add it to the list
//
if (!(find_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
StringClass filename = find_info.cFileName;
file_list.Add (filename);
} else if (find_info.cFileName[0] != '.') {
//
// Recurse into this subdirectory
//
StringClass full_path = Make_Path (local_dir, find_info.cFileName);
Clean_Directory (full_path);
//
// Add this directory to the list so it will get
// deleted with the files...
//
StringClass filename = find_info.cFileName;
file_list.Add (filename);
}
}
//
// Close the search handle
//
if (hfind != NULL) {
::FindClose (hfind);
}
//
// Now loop through all the files and delete them
//
for (int index = 0; index < file_list.Count (); index ++) {
StringClass &filename = file_list[index];
StringClass full_path = Make_Path (local_dir, filename);
Delete_File (full_path);
}
return retval;
}
//////////////////////////////////////////////////////////////////////////////////
//
// Make_Path
//
//////////////////////////////////////////////////////////////////////////////////
StringClass
DuplicateRemoverClass::Make_Path (LPCTSTR path, LPCTSTR filename)
{
StringClass full_path = path;
//
// Delimit the path if necessary
//
if (full_path[full_path.Get_Length () - 1] != '\\') {
full_path += "\\";
}
//
// Concatenate the filename onto the path
//
full_path += filename;
return full_path;
}
/////////////////////////////////////////////////////////
//
// Get_Temp_Filename
//
/////////////////////////////////////////////////////////
void
DuplicateRemoverClass::Get_Temp_Filename (StringClass &full_path)
{
CString temp_path = Make_Path (TempDirectory, "tempfile");
//
// Try to find a unique temp filename
//
do {
full_path.Format ("%s%.5d.dat", (const char *)temp_path, TempFilenameStart++);
} while (GetFileAttributes (full_path) != 0xFFFFFFFF);
return ;
}
////////////////////////////////////////////////////////////////////////////
//
// Delete_File
//
////////////////////////////////////////////////////////////////////////////
bool
DuplicateRemoverClass::Delete_File (LPCTSTR filename)
{
bool retval = false;
ASSERT (filename != NULL);
if (filename != NULL) {
//
// Strip the readonly bit off if necessary
//
DWORD attributes = ::GetFileAttributes (filename);
if ((attributes != 0xFFFFFFFF) &&
((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY))
{
::SetFileAttributes (filename, attributes & (~FILE_ATTRIBUTE_READONLY));
}
//
// Perform the delete operation!
//
if ((attributes != 0xFFFFFFFF) &&
((attributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY))
{
retval = (::RemoveDirectory (filename) == TRUE);
} else {
retval = (::DeleteFile (filename) == TRUE);
}
}
return retval;
}
////////////////////////////////////////////////////////////////////////////
//
// Is_File_In_Factory
//
////////////////////////////////////////////////////////////////////////////
bool
DuplicateRemoverClass::Is_File_In_Factory (const StringClass &filename, MixFileFactoryClass *factory)
{
bool retval = false;
//
// Get the list of filenames inside this mix file
//
DynamicVectorClass<StringClass> *test_filename_list = NULL;
factory->Get_Filename_List (&test_filename_list);
//
// Try to find the file inside this mix file
//
for (int index = 0; index < test_filename_list->Count (); index ++) {
if (filename.Compare_No_Case ((*test_filename_list)[index]) == 0) {
retval = true;
break;
}
}
return retval;
}

View File

@@ -0,0 +1,123 @@
/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : WWAudio *
* *
* $Archive:: /Commando/Code/Tools/MixViewer/duplicatecombiner.h $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 9/12/01 7:17p $*
* *
* $Revision:: 2 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if defined(_MSC_VER)
#pragma once
#endif
#ifndef __DUPLICATE_REMOVER_H
#define __DUPLICATE_REMOVER_H
#include "wwstring.h"
#include "vector.h"
//////////////////////////////////////////////////////////////////////////////////
// Forward declarations
//////////////////////////////////////////////////////////////////////////////////
class MixFileFactoryClass;
class MixCombiningDialogClass;
//////////////////////////////////////////////////////////////////////////////////
//
// DuplicateRemoverClass
//
//////////////////////////////////////////////////////////////////////////////////
class DuplicateRemoverClass
{
public:
//////////////////////////////////////////////////////////////////
// Public constructors/destructor
//////////////////////////////////////////////////////////////////
DuplicateRemoverClass (void);
~DuplicateRemoverClass (void);
//////////////////////////////////////////////////////////////////
// Public methods
//////////////////////////////////////////////////////////////////
//
// Configuration
//
void Add_Mix_File (const char *filename) { MixFileList.Add (filename); }
void Set_Destination_File (const char *filename) { DestinationMixFilename = filename; }
//
// Processing
//
void Process (void);
private:
//////////////////////////////////////////////////////////////////
// Private methods
//////////////////////////////////////////////////////////////////
void Open_Mix_Files (DynamicVectorClass<MixFileFactoryClass *> &list);
void Close_Mix_Files (DynamicVectorClass<MixFileFactoryClass *> &list);
void Internal_Process (void);
static UINT fnThreadProc (LPVOID pParam);
//
// Utilities
//
void Copy_File (MixFileFactoryClass *src_mix, MixFileFactoryClass *dest_mix, const char *filename);
bool Clean_Directory (LPCTSTR local_dir);
void Get_Temp_Filename (StringClass &full_path);
void Make_Temp_Directory (void);
void Delete_Temp_Directory (void);
bool Delete_File (LPCTSTR filename);
StringClass Make_Path (LPCTSTR path, LPCTSTR filename);
bool Is_File_In_Factory (const StringClass &filename, MixFileFactoryClass *factory);
//////////////////////////////////////////////////////////////////
// Private member data
//////////////////////////////////////////////////////////////////
DynamicVectorClass<StringClass> MixFileList;
StringClass DestinationMixFilename;
StringClass TempDirectory;
int TempFilenameStart;
MixCombiningDialogClass * Dialog;
};
#endif //__DUPLICATE_REMOVER_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,13 @@
//
// MIXVIEWER.RC2 - resources Microsoft Visual C++ does not edit directly
//
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
/////////////////////////////////////////////////////////////////////////////

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B