/* * Descent 3 * Copyright (C) 2024 Parallax Software * * 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 . */ /* * $Logfile: /DescentIII/Main/hogedit/HogEditDoc.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:56 $ * $Author: kevinb $ * * * * $Log: not supported by cvs2svn $ * * 10 5/05/99 12:53p Nate * Added support for multiple file extraction * * 9 10/30/98 11:15a Nate * Added support for modification of hog files. * * 8 10/09/98 4:50p Nate * * 7 9/17/98 4:29p Nate * Added Import Directory option. * * 6 8/14/98 4:38p Nate * Fixed a few minor bugs and added better error reporting * * 5 8/14/98 1:01p Nate * Added better error reporting for the HogEditor * * 4 7/22/98 2:38p Nate * Added Modified File prompt when exiting * * 3 7/20/98 3:35p Nate * Added more Editing functionality * * 2 7/15/98 12:31p Nate * Initial version * * $NoKeywords: $ */ // HogEditDoc.cpp : implementation of the CHogEditDoc class // #include "stdafx.h" #include #include #include "HogEdit.h" #include "hogfile.h" #include "HogEditDoc.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif bool DocModified; // is document modified. ///////////////////////////////////////////////////////////////////////////// // CHogEditDoc IMPLEMENT_DYNCREATE(CHogEditDoc, CDocument) BEGIN_MESSAGE_MAP(CHogEditDoc, CDocument) //{{AFX_MSG_MAP(CHogEditDoc) ON_UPDATE_COMMAND_UI(ID_ACTION_INSERT, OnUpdateActionInsert) ON_UPDATE_COMMAND_UI(ID_ACTION_CREATE, OnUpdateActionCreate) ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave) ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs) ON_UPDATE_COMMAND_UI(ID_ACTION_UPDATE, OnUpdateActionUpdate) ON_UPDATE_COMMAND_UI(ID_ACTION_IMPORT, OnUpdateActionImport) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CHogEditDoc construction/destruction CHogEditDoc::CHogEditDoc() { // TODO: add one-time construction code here } CHogEditDoc::~CHogEditDoc() { } BOOL CHogEditDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; // TODO: add reinitialization code here // (SDI documents will reuse this document) NewDocument(); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CHogEditDoc serialization void CHogEditDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here } else { // TODO: add loading code here } } ///////////////////////////////////////////////////////////////////////////// // CHogEditDoc diagnostics #ifdef _DEBUG void CHogEditDoc::AssertValid() const { CDocument::AssertValid(); } void CHogEditDoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CHogEditDoc commands ////////////////////////////////////////////////////////////////////////////// // These functions perform most of the meaty tasks of this interface. // creates a new (and empty) hog library. void CHogEditDoc::NewDocument() { // Initialize the hog library structure Library.filename[0]='\0'; Library.flags=0; Library.num_entries=0; // clear out all lists Library.filelist.RemoveAll(); // mark as not modified. DocModified = FALSE; m_StaticHog = FALSE; m_DocumentName = "Untitled.rib"; m_NoNameChosen = TRUE; } // loads a RIB file or HOG file. int CHogEditDoc::LoadDocument(CString& name) { char *ascii_name; char ext[_MAX_EXT]; int res; // Get ascii string from name ascii_name=name.GetBuffer(0); // extract file extension from name _splitpath(ascii_name, NULL, NULL, NULL, ext); // load either .rib or .hog file if (strcmpi(ext, ".rib") == 0) { res=LoadRib(ascii_name); if(res) m_StaticHog = false; } else { res=LoadHog(ascii_name); if(res) m_StaticHog = true; } // Set the new document name if(res) m_DocumentName = name; return(res); } // saves a RIB file int CHogEditDoc::SaveDocument(CString& name) { char *ascii_name; char ext[_MAX_EXT]; int res; ascii_name=name.GetBuffer(0); // name dialog _splitpath(ascii_name, NULL, NULL, NULL, ext); // load either .rib or .hog file if (strcmpi(ext, ".rib") == 0) { res=SaveRib(ascii_name); if(res) m_StaticHog = false; } else { res=SaveHog(ascii_name); if(res) m_StaticHog = true; } return(res); } // loads a RIB file int CHogEditDoc::LoadRib(const char *pathname) { hog_library_entry entry; FILE *rib_fp; char tag[10]; int j; // open the file rib_fp = fopen( pathname, "rb" ); if ( rib_fp == NULL ) { OutputDebugString("Could not open file.\n"); return false; } // write the tag if (!fread(tag, strlen(RIB_TAG_STR), 1, rib_fp )) { fclose(rib_fp); return false; } // Make tag string null terminated tag[strlen(RIB_TAG_STR)]='\0'; // Check if string has a valid tag if(strcmp(tag,RIB_TAG_STR)!=0) { OutputDebugString("File is not a RIB file!\n"); fclose(rib_fp); return false; } // Read in the hog filename if(!fread(Library.filename,sizeof(char),PSPATHNAME_LEN,rib_fp)) { fclose(rib_fp); return false; } // Read in the hog file flags if(!fread(&Library.flags,sizeof(Library.flags),1,rib_fp)) { fclose(rib_fp); return false; } // Read the number of file entries if (!fread(&Library.num_entries, sizeof(Library.num_entries), 1, rib_fp )) { fclose(rib_fp); return false; } // read the hogfile entries for(j=0;j PSFILENAME_LEN ) return ADDFILE_LONG_FNAME_ERROR; sprintf(filename, "%s%s", temp_filename, ext); length=filestat.st_size; timestamp=filestat.st_mtime; _splitpath(pathname, drive, path, NULL, NULL); sprintf(newpath, "%s%s", drive, path); strcpy(path, filename); // See if this entry is already in the library pos = Library.filelist.GetHeadPosition(); while (pos) { temp_entry = Library.filelist.GetNext(pos); if (!strcmpi(temp_entry.name, filename) /*&& !strcmpi(temp_entry.path, newpath)*/) return ADDFILE_DUP_FILE_ERROR; } // this is a new entry, so set it up and add it to the list! strcpy(entry->path, newpath); strcpy(entry->name, filename); entry->length = length; entry->timestamp = timestamp; entry->offset = -1; // Entry was not read in from a hogfile Library.filelist.AddTail(*entry); DocModified=true; return ADDFILE_OK; } // Checks to see if file has been modified, and updates entry accordingly int CHogEditDoc::UpdatedFileCheck(hog_library_entry *entry) { struct _stat filestat; char full_name[PSPATHNAME_LEN]; sprintf(full_name,"%s%s",entry->path,entry->name); // Get file info if (_stat(full_name, &filestat) != 0) return FILE_IS_GONE; // has file changed? if(entry->timestamp == filestat.st_mtime) return FILE_IS_SAME; // update entries entry->length=filestat.st_size; entry->timestamp=filestat.st_mtime; return FILE_HAS_CHANGED; } // Loads a Hog library entry structure bool CHogEditDoc::ReadHogLibEntry(FILE *fp, hog_library_entry *entry) { int res=0; res = fread(entry->path, sizeof(char), PSPATHNAME_LEN, fp); res = fread(entry->name, sizeof(char), PSFILENAME_LEN+1, fp); res = fread(&entry->flags, sizeof(entry->flags), 1, fp); res = fread(&entry->length, sizeof(entry->length), 1, fp); res = fread(&entry->timestamp, sizeof(entry->timestamp), 1, fp); entry->offset = -1; // Entry was not read in from a hogfile if (res) return TRUE; else return FALSE; } // Saves a Hog library entry structure bool CHogEditDoc::WriteHogLibEntry(FILE *fp, hog_library_entry *entry) { int res=0; res = fwrite(entry->path, sizeof(char), PSPATHNAME_LEN, fp); res = fwrite(entry->name, sizeof(char), PSFILENAME_LEN+1, fp); res = fwrite(&entry->flags, sizeof(entry->flags), 1, fp); res = fwrite(&entry->length, sizeof(entry->length), 1, fp); res = fwrite(&entry->timestamp, sizeof(entry->timestamp), 1, fp); if (res) return TRUE; else return FALSE; } // Allocates and fills the hog library filenames list bool CHogEditDoc::CreateFilenameList(char ***filenames) { char full_name[PSPATHNAME_LEN]; POSITION pos; hog_library_entry temp_entry; int j; // Get the number of filenames Library.num_entries=Library.filelist.GetCount(); // Allocate the list of filename pointers *filenames=new (char (*[Library.num_entries])); if(*filenames==NULL) return FALSE; // Allocate and store each filename in the Library j=0; pos=Library.filelist.GetHeadPosition(); while (pos!=NULL) { temp_entry = Library.filelist.GetNext(pos); // Only include the path if it's added from a rib file if(temp_entry.offset==-1) sprintf(full_name,"%s%s",temp_entry.path,temp_entry.name); else sprintf(full_name,"%s",temp_entry.name); (*filenames)[j]=new char[strlen(full_name)+1]; if((*filenames)[j]==NULL) {OutputDebugString("Outta memory!\n");return FALSE;} strcpy((*filenames)[j],full_name); /* sprintf(full_name,"%d - %s\n",j,(*filenames)[j]); OutputDebugString(full_name); */ j++; } return TRUE; } // Comparison function for qsort int compare( const void *arg1, const void *arg2 ) { char filename1[PSPATHNAME_LEN]; char filename2[PSPATHNAME_LEN]; char ext1[_MAX_EXT]; char ext2[_MAX_EXT]; // Isolate just the filenames (w/extensions) for the compare _splitpath(* (char **)arg1, NULL, NULL, filename1, ext1); _splitpath(* (char **)arg2, NULL, NULL, filename2, ext2); strcat(filename1,ext1); strcat(filename2,ext2); // Do a case-insensitive, asending order comparison return _stricmp(filename1, filename2); } // Quicksort the list of filenames void CHogEditDoc::SortFilenameList(char **filenames) { int count; count=Library.num_entries; qsort((void *)filenames,(size_t)count,sizeof(char *),compare); } // Deallocates the hog library filenames list (Library.num_entries must be valid!) bool CHogEditDoc::DeleteFilenameList(char **filenames) { int j; // Delete each filename for(j=0;jname)) { found_in_hog=TRUE; break; } } // If the filename wasn't in the list, get outta here if(!found_in_hog) return(NULL); // If the found file is actually an "external" file, get outta here if(entry.offset == -1) return(NULL); // fill in the entry data for this file table_entry->flags = entry.flags; table_entry->len = entry.length; table_entry->timestamp = entry.timestamp; // open the source hog file hog_fp = fopen( hog_fname, "rb" ); if ( hog_fp == NULL ) { return(NULL); } // Seek to correct place in hog file if(fseek(hog_fp,entry.offset,SEEK_SET)!=0) { fclose(hog_fp); return(NULL); } // Return pointer to file's position within the hog return(hog_fp); } // This is a function to specifically handle the creation of a new hog // file from the currently loaded (and presumedly altered) hog file. // This one also takes a pointer to a function that will perform // progress updates (for the user) #define TEMP_HOG_FILENAME "TempHogFile.thf" int CHogEditDoc::CreateNewHogFromCurrentHog(char *src_hog_fname, char *target_hog_fname, int nfiles, const char **filenames, void(* UpdateFunction)(char *)) { unsigned i; int table_pos; FILE *hog_fp; tHogHeader header; tHogFileEntry *table; char ext[_MAX_EXT]; char dest_hog_fname[PSPATHNAME_LEN+1]; // If the source and target hog filenames are the same, // then make the destination a temporary file if(!stricmp(src_hog_fname,target_hog_fname)) strcpy(dest_hog_fname,TEMP_HOG_FILENAME); else strcpy(dest_hog_fname,target_hog_fname); hogerr_filename[0]='\0'; // allocate file table if (nfiles <= 0) return HOGMAKER_ERROR; table = new tHogFileEntry[nfiles]; if (!table) return HOGMAKER_MEMORY; // create new file hog_fp = fopen( dest_hog_fname, "wb" ); if ( hog_fp == NULL ) { delete[] table; strcpy(hogerr_filename,dest_hog_fname); return HOGMAKER_OPENOUTFILE; } //write the tag if (!fwrite(HOG_TAG_STR, strlen(HOG_TAG_STR), 1, hog_fp )) { delete[] table; fclose(hog_fp); strcpy(hogerr_filename,dest_hog_fname); return HOGMAKER_OUTFILE; } //write number of files ubyte filler = 0xff; header.nfiles = (unsigned)nfiles; header.file_data_offset = strlen(HOG_TAG_STR) + HOG_HDR_SIZE + (sizeof(tHogFileEntry) * header.nfiles); if (!fwrite(&header.nfiles,sizeof(header.nfiles),1,hog_fp)) { delete[] table; fclose(hog_fp); strcpy(hogerr_filename,dest_hog_fname); return HOGMAKER_OUTFILE; } if (!fwrite(&header.file_data_offset,sizeof(header.file_data_offset),1,hog_fp)) { delete[] table; fclose(hog_fp); strcpy(hogerr_filename,dest_hog_fname); return HOGMAKER_OUTFILE; } // write out filler for(i=0; i < HOG_HDR_SIZE-sizeof(tHogHeader); i++) if (!fwrite(&filler,sizeof(ubyte),1,hog_fp)) { delete[] table; fclose(hog_fp); strcpy(hogerr_filename,dest_hog_fname); return HOGMAKER_OUTFILE; } // save file position of index table and write out dummy table table_pos = strlen(HOG_TAG_STR) + HOG_HDR_SIZE; memset(&table[0], 0, sizeof(table[0])); for (i = 0; i < header.nfiles; i++) { if (!WRITE_FILE_ENTRY(hog_fp, &table[0])) { delete[] table; fclose(hog_fp); strcpy(hogerr_filename,dest_hog_fname); return HOGMAKER_OUTFILE; } } // write files (& build index) for (i=0;iEnable(!m_StaticHog);*/ } void CHogEditDoc::OnUpdateActionCreate(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(!m_StaticHog && Library.filelist.GetCount()>0); } void CHogEditDoc::OnUpdateFileSave(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(/*!m_StaticHog &&*/ DocModified); } void CHogEditDoc::OnUpdateFileSaveAs(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here /*pCmdUI->Enable(!m_StaticHog);*/ } void CHogEditDoc::OnUpdateActionUpdate(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->Enable(!m_StaticHog && Library.filelist.GetCount()>0); } void CHogEditDoc::OnUpdateActionImport(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here //pCmdUI->Enable(!m_StaticHog); }