home *** CD-ROM | disk | FTP | other *** search
- // ------------------------------- //
- // -------- Start of File -------- //
- // ------------------------------- //
- // ----------------------------------------------------------- //
- // C++ Source Code File Name: vb_debug.cpp
- // Compiler Used: MSVC40, DJGPP 2.7.2.1, GCC 2.7.2.1, HP CPP 10.24
- // Produced By: Doug Gaer
- // File Creation Date: 02/04/1997
- // Date Last Modified: 03/17/1999
- // Copyright (c) 1997 Douglas M. Gaer
- // ----------------------------------------------------------- //
- // ------------- Program Description and Details ------------- //
- // ----------------------------------------------------------- //
- /*
- The VBD C++ classes are copyright (c) 1997, by Douglas M. Gaer.
- All those who put this code or its derivatives in a commercial
- product MUST mention this copyright in their documentation for
- users of the products in which this code or its derivative
- classes are used. Otherwise, you have the freedom to redistribute
- verbatim copies of this source code, adapt it to your specific
- needs, or improve the code and release your improvements to the
- public provided that the modified files carry prominent notices
- stating that you changed the files and the date of any change.
-
- THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
- THE ENTIRE RISK OF THE QUALITY AND PERFORMANCE OF THIS SOFTWARE
- IS WITH YOU. SHOULD ANY ELEMENT OF THIS SOFTWARE PROVE DEFECTIVE,
- YOU WILL ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR
- CORRECTION.
-
- This program is used to display a detailed analysis of every
- variable data block allocated in a VBD file.
-
- Changes:
- ================================================================
- 01/20/1998 - Rebuilds the VBD file static area data if the VBD
- header is still intact.
- Changed by: Doug Gaer
-
- 03/09/1998 - Corrected "Checking the FreeSpace value" routine in
- AnalyzeHeader() function. In previous version the error value was
- incremented outside of the if(vb.CkWord != CheckWord) statement.
- Changed by: Doug Gaer
-
- 06/10/1998 - Changed the Rebuild() function to write only normal
- variable blocks to the new file: if(vb.Status == NormalVB)
- Changed by: Doug Gaer
- ================================================================
- */
- // ----------------------------------------------------------- //
- #include <iostream.h>
- #include <iomanip.h>
- #include <string.h>
- #include "vbdfile.h"
- #include "vbdstats.h"
-
- // Program name and version number
- const char *VersionNumber = "1031.101";
- const char *ProgramName = "vb_debug";
-
- // Function prototypes for display menu
- void SkipToEol(istream &s);
- int Quit();
- void Menu(const VBDFilePtr &f);
- void pause();
- void Version();
-
- // Function prototypes for VBD utilities
- void FindVB(const VBDFilePtr &f, int verbose = 0, int walk = 0);
- void AnalyzeHeader(const VBDFilePtr &f);
- void DisplayStats(const VBDFilePtr &f);
- void Rebuild(const VBDFilePtr &f);
-
- void DisplayStats(const VBDFilePtr &f)
- {
- const char *FName = f->VBDFileName();
- FileHeader fh;
-
- f->Read(&fh, sizeof(FileHeader), 0);
- if(memcmp(fh.Signature, VBDFile::VBDSignature, 7)) { // Test file type
- cout << endl;
- cout << "VBD File Header is damaged or does not exist" << endl;
- cout << endl;
- return;
- }
-
- cout << endl;
- __SBYTE__ FileStatus = f->GetFileStatus(); // Get the current file status
- cout << "----- VBD file statistics -----" << endl;
- cout << endl;
- VBDStats(f);
- }
-
- void AnalyzeHeader(const VBDFilePtr &f)
- {
- FileHeader fh;
- VBHeader vb;
- int errors = 0;
-
- f->Read(&fh, sizeof(FileHeader), 0);
- cout << endl;
- cout << "Analyzing VBD file header..." << endl;
- cout << endl;
-
- cout << "Checking VBD signature..." << endl;
- if (memcmp(fh.Signature, VBDFile::VBDSignature, 7)) { // Test file type
- cout << endl;
- cout << "VBD File Header is damaged or does not exist" <<endl;
- cout << endl;
- FindVB(f, 0);
- return;
- }
- else if (memcmp(fh.Signature, VBDFile::VBDSignature, 8)) {
- // Check revision letters
- char revision[8];
- revision[8] = 0; // Ensure null termination
- char rev_letter;
- cout << endl;
- cout << "NOTE: The VBD file revision letters do not match." << endl;
- memmove(revision, VBDFile::VBDSignature, 8);
- rev_letter = revision[7];
- if(rev_letter == 0)
- cout << "Current VBD File Revision = NONE" << endl;
- else
- cout << "Current VBD File Revision = " << rev_letter << endl;
- memmove(revision, fh.Signature, 8);
- rev_letter = revision[7];
- if(rev_letter == 0)
- cout << "Current VBD File Revision = NONE" << endl;
- else
- cout << "The file reads: " << rev_letter << endl;
- cout << "Backward compatibility rules will be enforced." << endl;
- cout << endl;
- }
-
- cout << "Checking for End of File errors..." << endl;
- FAU StaticEOF = f->FileSize(f->VBDFileName());
- if(StaticEOF > fh.EndOfFile) {
- cout << endl;
- cout << "End of file error in file: " << f->VBDFileName() << endl;
- cout << "The actual length is longer then the allocated length!" << endl;
- cout << endl;
- errors++;
- }
-
- cout << "Checking the HeapStart value..." << endl;
- f->Read(&vb, sizeof(VBHeader), fh.HeapStart);
- if (vb.CkWord != CheckWord) {
- cout << endl;
- cout << "Bad HeapStart value in file: " << f->VBDFileName() << endl;
- cout << "No variable block found at file address: "
- << fh.HeapStart << endl;
- cout << endl;
- errors++;
- }
-
- cout << "Checking the FreeSpace value..." << endl;
- if(fh.FreeSpace != 0) {
- f->Read(&vb, sizeof(VBHeader), fh.FreeSpace);
- if(vb.CkWord != CheckWord) {
- cout << endl;
- cout << "Bad FreeSpace value in file: " << f->VBDFileName() << endl;
- cout << "No variable block found at file address: "
- << fh.FreeSpace << endl;
- cout << endl;
- errors++;
- }
- }
-
- cout << "Checking the HighestVB value..." << endl;
- f->Read(&vb, sizeof(VBHeader), fh.HighestVB);
- if (vb.CkWord != CheckWord) {
- cout << endl;
- cout << "Bad HeapStart value in file: " << f->VBDFileName() << endl;
- cout << "No variable block found at file address: "
- << fh.HighestVB << endl;
- cout << endl;
- errors++;
- }
-
- cout << "Checking the VBD version number..." << endl;
- if(fh.Version != VBDFile::VBDVersion) {
- cout << endl;
- cout << "NOTE: The version numbers do not match." << endl;
- cout << "Current VBD File Version = " << VBDFile::VBDVersion << endl;
- cout << "The file reads: " << fh.Version << endl;
- cout << "Backward compatibility rules will be enforced." << endl;
- cout << endl;
- }
-
- if(errors) {
- cout << endl;
- cout << "VBD file header has errors!" << endl;
- }
- else {
- cout << endl;
- cout << "VBD file header checks good." << endl;
- }
- cout << endl;
- }
-
- void FindVB(const VBDFilePtr &f, int verbose, int walk)
- // Serach the file for all variable block.
- {
- VBHeader vb;
- int count = 0;
- int badvb = 0;
-
- cout << endl;
- cout << "Searching file for all variable blocks..." << endl;
-
- FAU StaticEOF = f->FileSize(f->VBDFileName());
- FAU addr = f->VBSearch(0); // Search the entire file
-
- if(addr == 0) {
- cout << endl;
- cout << "No variable blocks found in file: "
- << f->VBDFileName() << endl;
- cout << endl;
- return;
- }
-
- while(1) {
- if(addr >= StaticEOF) break;
- f->Read(&vb, sizeof(VBHeader), addr);
-
- if (vb.CkWord == CheckWord) {
- count++; // Increment the variable block count
- if(verbose) {
- VBStats(f, (addr+sizeof(VBHeader)));
- if(walk) {
- char c;
- cout << endl;
- cout << "Press enter to continue or enter 'X' to exit >";
- cin.clear();
- cin.get(c);
- switch(c) {
- case 'x' : case 'X' :
- cout << endl;
- return;
- default:
- break;
- }
- }
- }
- addr = addr + vb.Length; // Goto the next variable block
- }
- else {
- badvb++;
- cout << endl;
- cout << "Found bad variable block at address " << addr << endl;
- cout << "Searching for next good variable block..." << endl;
- addr = f->VBSearch(addr); // Search for the next good block
- if(!addr) {
- cout << "None found!" << endl;
- cout << endl;
- return;
- }
- }
- }
- cout << endl;
- cout << "Found " << count << " good varible blocks." << endl;
- if(badvb) cout << "Found " << badvb << " bad variable blocks." << endl;
- cout << endl;
- }
-
- void Rebuild(const VBDFilePtr &f)
- {
- cout << endl;
- cout << "Rebuilding damaged VBD file..." << endl;
- cout << endl;
-
- char buf[255];
- int retry = 3;
-
- while(1) { // Loop until a good file name is found
- cout << "Enter new name of file to build >";
- cin.getline(buf, sizeof(buf));
- cout << endl;
- if(!*buf) { // Return if nothing is entered
- Menu(f);
- return;
- }
- if(VBDFile::Exists(buf)) {
- cout << "File already exists!" << endl << endl;
- retry--;
- if(!retry) {
- Menu(f);
- return;
- }
- }
- else
- break;
- }
-
- FileHeader fh;
- VBHeader vb;
- int errors = 0;
-
- // Analyze the VBD file header to determine if the file has
- // a pre-allocated static area
- __LWORD__ static_area;
- f->Read(&fh, sizeof(FileHeader), 0);
-
- // Check the VBD FileHeader's signature
- if (memcmp(fh.Signature, VBDFile::VBDSignature, 8))
- errors++; // Header is damaged and cannot be read
-
- if(!errors) { // Check the HeapStart value
- f->Read(&vb, sizeof(VBHeader), fh.HeapStart);
- if (vb.CkWord != CheckWord)
- errors++;
- }
-
- // If no errors, calculate the the size of the static area
- if(!errors) static_area = fh.HeapStart - sizeof(FileHeader);
-
- FAU StaticEOF = f->FileSize(f->VBDFileName());
- FAU addr = f->VBSearch(0); // Search the entire file
-
- if(addr == 0) {
- cout << endl;
- cout << "No variable blocks found in file: "
- << f->VBDFileName() << endl;
- pause();
- return;
- }
-
- // Create the new file
- VBDFilePtr NewFile(new VBDFile);
- NewFile->Create(buf, static_area);
-
- int count = 0;
- int badvb = 0;
-
- char *v;
-
- if(static_area) { // Write the static area data
- v = new char[static_area];
- f->Read(v, static_area, sizeof(FileHeader));
- NewFile->Write(v, static_area, sizeof(FileHeader));
- delete v;
- }
-
- FAU ObjectLength;
- UINT32 checksum;
- char rev_letter = f->GetRevLetter();
-
- while(1) {
- if(addr >= StaticEOF) break;
-
- f->Read(&vb, sizeof(VBHeader), addr);
- if(vb.CkWord == CheckWord) {
- ObjectLength = f->ObjectLength(addr + sizeof(VBHeader));
- v = new char[ObjectLength];
- f->Read(v, ObjectLength);
- if((__SBYTE__)vb.Status == NormalVB) {
- count++; // Increment the variable block count
- NewFile->Alloc(ObjectLength);
- NewFile->Write(v, ObjectLength);
- switch(rev_letter) {
- case 'A':
- checksum = calcCRC32(v, ObjectLength);
- NewFile->Write(&checksum, sizeof(checksum));
- break;
-
- default: // Default to versions prior to 1027 rev A
- break;
- }
- }
- delete v;
- addr = addr + vb.Length; // Goto the next variable block
- }
- else {
- badvb++;
- addr = f->VBSearch(addr); // Search for the next good block
- if(!addr) break;
- }
- }
- cout << endl;
-
- cout << "Wrote " << count << " good variable blocks to file: "
- << NewFile->VBDFileName() << endl;
-
- if(static_area)
- cout << "Wrote " << static_area << " bytes of Static area data."
- << endl;
-
- if(badvb)
- cout << "Did not write " << badvb << " bad variables found in file: "
- << f->VBDFileName() << endl;
-
- if(errors) {
- cout << f->VBDFileName() << " file header is damaged!" << endl;
- cout << "No header information was copied to "
- << NewFile->VBDFileName() << endl;
- }
-
- NewFile->Close();
- cout << endl;
- }
-
- void Menu(const VBDFilePtr &f)
- {
- cout << endl;
- cout << "Analyzing file: " << f->VBDFileName() << endl;
- cout << "Enter the letter of your selection at the prompt." << endl;
- cout << endl;
- cout << "(A) - Analyze the VBD file header" << endl;
- cout << "(D) - Dump every variable block" << endl;
- cout << "(F) - Find every variable block in the file" << endl;
- cout << "(H) - Displays this menu" << endl;
- cout << "(Q) - Quit this program" << endl;
- cout << "(R) - Rebuild a damaged VBD file" << endl;
- cout << "(S) - Display VBD file statistics" << endl;
- cout << "(W) - Walk through every variable block" << endl;
- cout << endl;
- }
-
- void SkipToEol(istream &s)
- // Used to clear istream
- {
- char c;
- s.clear();
- while(s.get(c) && c != '\n') { ; }
- }
-
- void pause()
- {
- cout << endl;
- cout << "Press enter to continue..." << endl;
- cin.get();
- }
-
- int Quit()
- {
- cout << "Exiting..." << endl;
- return 0;
- }
-
- void Version()
- {
- cout << endl;
- cout << ProgramName << " version number: " << VersionNumber << endl;
- cout << endl;
- }
-
- int main(int argc, char **argv)
- {
- // Display the program version information and exit the program
- if(argc >= 2) {
- if(strcmp(argv[1], "version") == 0) {
- Version();
- return 0;
- }
- }
-
- if(argc < 2) {
- cerr << endl;
- cerr << "VBD file debug utility version " << VersionNumber << endl;
- cerr << "Usage: " << ProgramName << " infile.vbd" << endl;
- cerr << "Usage: " << ProgramName << " infile.vbd (command)" << endl;
- cerr << endl;
- return 1;
- }
-
- VBDFilePtr f(new VBDFile);
- const char *FName = argv[1];
- if(!VBDFile::Exists(FName))
- Error->SignalException(EHandler::NoFileExists);
- else
- f->BlindOpen(FName, VBDFile::READONLY);
-
- char key;
- if(argc <= 2) Menu(f); // Not processing a command
- int rv = 1;
-
- while(rv) {
- if(argc > 2) { // Process a single command and exit the loop
- key = *(argv[2]);
- rv = 0;
- }
- else {
- if (!cin) { // Input is in fail state
- SkipToEol(cin); // Go to end of line
- if (!cin) { // Can't fix
- cout << "Input stream is broken" << endl;
- return 0;
- }
- }
- cout << '>';
- cin >> key;
- if (!cin) continue; // Fix at top of loop
- }
- switch(key) {
- case 'a' : case 'A' :
- if(argc <= 2) SkipToEol(cin);
- AnalyzeHeader(f);
- break;
- case 'f' : case 'F' :
- if(argc <= 2) SkipToEol(cin);
- FindVB(f);
- break;
- case 'd' : case 'D' :
- if(argc <= 2) SkipToEol(cin);
- FindVB(f, 1);
- break;
- case 'h' : case 'H' :
- Menu(f);
- break;
- case '?' :
- Menu(f);
- break;
- case 'q' : case 'Q' :
- rv = Quit();
- break;
- case 'r' : case 'R' :
- if(argc <= 2) SkipToEol(cin);
- Rebuild(f);
- break;
- case 's' : case 'S' :
- if(argc <= 2) SkipToEol(cin);
- DisplayStats(f);
- break;
- case 'w' : case 'W' :
- if(argc <= 2) SkipToEol(cin);
- FindVB(f, 1, 1);
- break;
- default:
- cout << "Unrecognized command" << endl;
- }
- }
-
- return 0;
- }
- // ----------------------------------------------------------- //
- // ------------------------------- //
- // --------- End of File --------- //
- // ------------------------------- //
-
-