📄 cl.cpp
字号:
{
meta = "Y";
use_meta = true;
}
else if (!strnicmp(argv[i], "/width:", 7) || !strnicmp(argv[i], "-width:", 7))
{
output_width = atoi(&argv[i][7]);
}
else if (!strnicmp(argv[i], "/lognative", 10) || !strnicmp(argv[i], "-lognative", 10))
{
log_native_msgs = true;
}
else
{
// surround each arg with double quotes to avoid long filename problems
string nextarg = "\""; // insert opening quote
char *b = argv[i];
char *p = strchr(b, '"'); // find next double quote char
while (p != 0) // while there is another double quote char...
{
*p = '\0'; // copy everything up to (not incl.) the quote
nextarg += b;
nextarg += "\\\""; // escape the quote
b = p + 1; // keep looking for quotes...
p = strchr(b, '"');
}
nextarg += b; // copy remainder of the arg text
int n = nextarg.length() - 1; // if arg ends with pattern [^\]\,
if (nextarg[n-1] != '\\' && nextarg[n] == '\\') // add another backslash so we don't
nextarg += "\\"; // end up with an escaped " at the end!
nextarg += "\""; // insert closing quote
if (i > 0) // if not command name, add to args list for filtering
args += nextarg;
new_argv[new_argc] = new char[nextarg.length() + 1]; // and build new_argv in case
strcpy(new_argv[new_argc++], nextarg.c_str()); // we end up spawning CL
}
args += " ";
}
new_argv[new_argc] = NULL;
full_filt_cmd += " /width:" + toString(output_width);
full_filt_cmd += " /iter:" + iterator_policy;
full_filt_cmd += " /alloc:" + allocator_policy;
full_filt_cmd += " /func:" + functor_policy;
full_filt_cmd += " /with:" + with_policy;
full_filt_cmd += " /break:" + break_algorithm;
full_filt_cmd += " /cbreak:" + cbreak;
full_filt_cmd += " /closewrap:" + closewrap;
if (use_meta)
full_filt_cmd += " /meta:" + meta;
full_filt_cmd += " /banner:n"; // disable the Perl script's banner, since
// we provide the banner in this case
if (log_native_msgs)
full_filt_cmd += " /lognative";
int status;
log("full_filt_cmd = " + full_filt_cmd);
if (filtering)
{
// Let's just make sure that the Perl interpreter and script are where
// they're supposed to be:
struct stat dummy_stat_buf;
if (stat(perl_exe.c_str(), &dummy_stat_buf) == -1)
{
cerr << "Proxy CL: Perl interpreter configured as " << perl_exe <<
" not present.\nBailing out." << endl;
exit (1);
}
if (stat(filter_script.c_str(), &dummy_stat_buf) == -1)
{
cerr << "Proxy CL: Perl script configured as " << filter_script <<
" not present.\nBailing out." << endl;
exit (1);
}
// Okay, we're in business...
if (!silent)
cout << " ****** {"CL_ID"} STL Message Decryption is ON! ******" << endl;
// Create some "C" strings to pass to the doWin32Stuff function...
char *full_filt_cmd_cstr = new char[full_filt_cmd.length() + 1];
strcpy(full_filt_cmd_cstr, full_filt_cmd.c_str());
// Create replacement command line
string cmdline = native_cl + args; // start with native CL.EXE and append
log(cmdline); // whatever args were passed
char *cmdline_cstr = new char[cmdline.length() + 1];
strcpy(cmdline_cstr, cmdline.c_str());
status = doWin32Stuff(full_filt_cmd_cstr, cmdline_cstr);
delete [] full_filt_cmd_cstr;
delete [] cmdline_cstr;
}
else
{
if (!silent)
cout << " ****** {"CL_ID"} STL Message Decryption is Off ******" << endl;
#if DEBUG_CAPABLE
for (i = 1; i < new_argc; i++)
log("new_argv[" + toString(i) + "] = '" + new_argv[i] + "'");
#endif
// if not filtering, use native CL:
status = _spawnvp(_P_WAIT, native_cl.c_str(), new_argv);
if (status == -1)
{
cerr << "Proxy CL: Failure to start " << native_cl << " (does your PATH include it?)" << endl;
status = 1;
}
}
for(i = 0; i < new_argc; i++) // release the "new_argv" dynamic memory
delete[] new_argv[i];
delete [] new_argv;
return status;
}
// This has to be in its own function, since we can't mix __try / __finally
// and string objects in main()...Geez Louise...
int doWin32Stuff(char *full_filt_cmd, char *cmdline)
{
using namespace std;
// Get std device handles
HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE hStdError = GetStdHandle(STD_ERROR_HANDLE);
// Create an anonymous pipe for communication between native_cl and Perl
//
HANDLE hPipeWrite = NULL;
HANDLE hPipeRead = NULL;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
if( ! ::CreatePipe(
&hPipeRead, // address of variable for read handle
&hPipeWrite, // address of variable for write handle
&sa, // pointer to security attributes
0 // number of bytes reserved for pipe
) )
{
cerr << "Proxy CL: Failure to create pipe between " << native_cl << " and Perl" << endl;
return 1;
}
// Start perl
//
PROCESS_INFORMATION pi_perl;
pi_perl.hProcess = NULL;
pi_perl.hThread = NULL;
STARTUPINFO si_perl;
memset(&si_perl, '\0', sizeof(si_perl));
si_perl.cb = sizeof(si_perl);
si_perl.dwFlags = STARTF_USESTDHANDLES;
si_perl.hStdInput = hPipeRead; // read side of pipe
si_perl.hStdOutput = hStdOut; // stdout of parent
si_perl.hStdError = hStdOut; // stderr of parent
if( ! ::CreateProcess(
NULL,
full_filt_cmd, // something like: perl stlfilt.pl [/iter:n]
NULL, // pointer to process security attributes
NULL, // pointer to thread security attributes
TRUE, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&si_perl, // pointer to STARTUPINFO
&pi_perl // pointer to PROCESS_INFORMATION
) )
{
cerr << "Proxy CL: Failure to start perl.exe (check pathname in CL.CPP)" << endl;
return 1;
}
// Try-finally block for closing handles and sending EOF to perl.
//
PROCESS_INFORMATION pi_cl2 ;
pi_cl2.hProcess = NULL;
pi_cl2.hThread = NULL;
//
bool bWriteEofSuccess = true;
__try
{
// Start native_cl:
//
STARTUPINFO si_cl2;
memset(&si_cl2, '\0', sizeof(si_cl2));
si_cl2.cb = sizeof(si_cl2);
si_cl2.dwFlags = STARTF_USESTDHANDLES;
si_cl2.hStdInput = hStdIn; // stdin of parent
si_cl2.hStdOutput = hPipeWrite; // write side of child-to-parent
si_cl2.hStdError = hStdError; // stderr of parent
if( ! ::CreateProcess(NULL,
cmdline,
NULL, // pointer to process security attributes
NULL, // pointer to thread security attributes
TRUE, // handle inheritance flag
0, // creation flags
NULL, // pointer to new environment block
NULL, // pointer to current directory name
&si_cl2, // pointer to STARTUPINFO
&pi_cl2 // pointer to PROCESS_INFORMATION
) )
{
cerr << "Proxy CL: Failure to start " << native_cl << " (does your PATH include it?)" << endl;
return 1;
}
// Wait for native_cl to finish.
if( WAIT_FAILED == ::WaitForSingleObject(pi_cl2.hProcess, INFINITE) )
{
cerr << "Proxy CL: Failure waiting for " << native_cl << " to terminate" << endl;
return 1;
}
}
__finally
{
if( ! WriteEofToPipe(hPipeWrite) )
bWriteEofSuccess = false;
}
if( !bWriteEofSuccess )
{
puts("Proxy CL: Failure to send EOF to perl.exe");
return 1;
}
// Wait for perl.exe to finish.
if( WAIT_FAILED == ::WaitForSingleObject(pi_perl.hProcess, INFINITE) )
{
cerr << "Proxy CL: Failure waiting for perl.exe to terminate" << endl;
return 1;
}
// Get exit code for native_cl. This is possible because we have not closed
// the process handle yet.
//
DWORD dwExitCode;
if( ! GetExitCodeProcess(
pi_cl2.hProcess, // handle to the process
&dwExitCode // address to receive termination status
) )
{
cerr << "Proxy CL: Could not get exit code for " << native_cl << endl;
return 1;
}
// Close all handles, just to make the point.
//
::CloseHandle(hPipeWrite);
::CloseHandle(hPipeRead);
::CloseHandle(pi_perl.hProcess);
::CloseHandle(pi_perl.hThread);
::CloseHandle(pi_cl2.hProcess);
::CloseHandle(pi_cl2.hThread);
return dwExitCode;
}
BOOL WriteEofToPipe(HANDLE hPipe)
{
SYSTEM_INFO info; // Check for > 1 processor...
GetSystemInfo(&info);
if (info.dwNumberOfProcessors > 1)
Sleep(100); // Fixes obscure timing problem on dual PIII system
// We must precede the EOF with an extra newline because we don't
// know whether CL's output ended with a newline, and EOF without
// preceding newlines is always iffy. The perlscript ensures that
// the extra newline is discarded unless the CL output didn't end
// with a newline, in which case we want to add it.
//
DWORD dwNumBytesToWrite = 2;
DWORD dwNumBytesWritten = 0 ;
BOOL bWriteRetVal = WriteFile(
hPipe, // handle to file to write to
"\012\032", // pointer to data to write to file
dwNumBytesToWrite, // number of bytes to write
&dwNumBytesWritten, // pointer to number of bytes written
NULL) ; // addr. of structure needed for overlapped I/O
if( ! bWriteRetVal || dwNumBytesToWrite != dwNumBytesWritten )
return FALSE;
::FlushFileBuffers(hPipe);
return TRUE;
}
bool hasExt(const std::string &filenam, const std::string extensions[], int nexts)
{
using namespace std;
string filename = filenam;
int length;
int i;
if (filename.length() < 2)
return false;
// get rid of trailing whitespace on the filename...
for (i = filename.length() - 1; i >= 0; i--)
if (!isspace(filename[i]))
break;
filename.resize(length = i + 1);
log(string("hasExt() testing: \"") + filename + "\"");
for (i = 0; i < nexts; i++)
{
int extLen = extensions[i].length();
log("testing extension:" + extensions[i]);
if (length >= extLen + 1 &&
!stricmp(filename.substr(length - extLen).c_str(), extensions[i].c_str()))
{
log(string("hasExt() found extension: ") + extensions[i]);
return true;
}
}
log("hasExt() did not find a matching extension.\n");
return false;
}
// remove trailing whitespace from a string:
void chompSpace(std::string &pathname)
{
while (isspace(pathname[pathname.length() - 1]))
pathname.resize(pathname.length() - 1);
}
// remove trailing slash, if any, from string:
void chompSlash(std::string &pathname)
{
chompSpace(pathname); // first remove all trailing whitespace
char c;
if ((c = pathname[pathname.length() - 1]) == '/' || c == '\\')
pathname.resize(pathname.length() - 1);
}
// remove trailing comment, if any:
void stripComment(std::string &txt)
{
chompSpace(txt); // first remove all trailing whitespace
for (int i = txt.length() - 1; i > 1; i--) // search for semicolon
{
if (txt[i] == ';')
{ // found semicolon; now search for first
int j; // non-whitespace before that
for (j = i - 1; j > 0; j--)
if (!isspace(txt[j]))
break;
txt.resize(j + 1);
log("just stripped comment. result: \"" + txt + "\"");
return;
}
}
}
// remove quotation marks around pathname, if any:
void stripQuotes(std::string &txt, const std::string &unprocessed_line)
{
char c;
char quoteFound = 0;
int i;
chompSpace(txt); // first remove all trailing whitespace
for (i = 0; i < txt.length() && isspace(c = txt[i]); i++) // skip leading whitespace
;
if (i == txt.length()) // null parameter value? Not good.
{
std::cerr << "Proxy CL: A parameter value in " + configFile + " is null.\n" +
" All uncommented lines must specify a value.\nBailing out.";
exit(1);
}
if (c == '\'' || c == '"') // allow single or double quotes, as long as
{ // they match...
quoteFound = c;
txt.erase(i, 1); // delete the opening quote
c = txt[txt.length() - 1]; // make sure close quote matches open
if (c == quoteFound)
{
txt.resize(txt.length() - 1); // delete the closing quote
return; // and we're done
}
}
if (!quoteFound && // now check for funky unmatched quote at end
(c = txt[txt.length() - 1]) != '\'' && c != '"')
return; // OK if none
std::cerr << "Proxy CL: Funky quoting detected in " + configFile + "\n" +
" The offending parameter value:\n " +
unprocessed_line + "\nProxy CL is bailing out.";
exit(1);
}
// give pathnames/filenames the full treatment:
void massage_pathname(std::string &txt)
{
std::string raw(txt);
stripComment(txt);
stripQuotes(txt, raw);
chompSlash(txt);
}
#if DEBUG_CAPABLE
void logit(const std::string &msg)
{
if (!debug)
return;
std::ofstream out(debug_log.c_str(), std::ios_base::app);
if (!out) {
std::cerr << "Can't append to " << debug_log << ":" << std::endl;
std::cerr << "Offending message: " << msg << std::endl;
}
else
{
out << msg << std::endl;
out.close();
}
}
std::string toString(int n)
{
char buf[20];
sprintf(buf, "%d", n);
return buf;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -