1 /* 2 * regexpl - Console Registry Explorer 3 * 4 * Copyright (C) 2000-2005 Nedko Arnaudov <nedko@users.sourceforge.net> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; see the file COPYING. If not, write to 18 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 * Boston, MA 02111-1307, USA. 20 */ 21 22 // ShellCommandValue.cpp: implementation of the CShellCommandValue class. 23 // 24 ////////////////////////////////////////////////////////////////////// 25 26 #include "ph.h" 27 #include "RegistryExplorer.h" 28 #include "ShellCommandValue.h" 29 #include "RegistryTree.h" 30 #include "RegistryKey.h" 31 32 #define VALUE_CMD _T("VV") 33 #define VALUE_CMD_LENGTH COMMAND_LENGTH(VALUE_CMD) 34 #define VALUE_CMD_SHORT_DESC VALUE_CMD _T(" command is used to view value.\n") 35 36 ////////////////////////////////////////////////////////////////////// 37 // Construction/Destruction 38 ////////////////////////////////////////////////////////////////////// 39 40 CShellCommandValue::CShellCommandValue(CRegistryTree& rTree):m_rTree(rTree) 41 { 42 } 43 44 CShellCommandValue::~CShellCommandValue() 45 { 46 } 47 48 BOOL CShellCommandValue::Match(const TCHAR *pchCommand) 49 { 50 if (_tcsicmp(pchCommand,VALUE_CMD) == 0) 51 return TRUE; 52 if (_tcsnicmp(pchCommand,VALUE_CMD _T(".."),VALUE_CMD_LENGTH+2*sizeof(TCHAR)) == 0) 53 return TRUE; 54 if (_tcsnicmp(pchCommand,VALUE_CMD _T("/"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0) 55 return TRUE; 56 if (_tcsnicmp(pchCommand,VALUE_CMD _T("\\"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0) 57 return TRUE; 58 return FALSE; 59 } 60 61 int CShellCommandValue::Execute(CConsole &rConsole, CArgumentParser& rArguments) 62 { 63 rArguments.ResetArgumentIteration(); 64 TCHAR *pchCommandItself = rArguments.GetNextArgument(); 65 66 TCHAR *pchParameter; 67 TCHAR *pchValueFull = NULL; 68 BOOL blnUnicodeDump = FALSE; 69 BOOL blnBadParameter = FALSE; 70 BOOL blnHelp = FALSE; 71 LONG nError; 72 DWORD dwValueSize; 73 DWORD dwType = REG_NONE; 74 BYTE *pDataBuffer = NULL; 75 TCHAR *pchFilename = NULL; 76 77 if ((_tcsnicmp(pchCommandItself,VALUE_CMD _T(".."),VALUE_CMD_LENGTH+2*sizeof(TCHAR)) == 0)|| 78 (_tcsnicmp(pchCommandItself,VALUE_CMD _T("\\"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0)) 79 { 80 pchValueFull = pchCommandItself + VALUE_CMD_LENGTH; 81 } 82 else if (_tcsnicmp(pchCommandItself,VALUE_CMD _T("/"),VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0) 83 { 84 pchParameter = pchCommandItself + VALUE_CMD_LENGTH; 85 goto CheckValueArgument; 86 } 87 88 while((pchParameter = rArguments.GetNextArgument()) != NULL) 89 { 90 CheckValueArgument: 91 blnBadParameter = FALSE; 92 if ((_tcsicmp(pchParameter,_T("/?")) == 0) 93 ||(_tcsicmp(pchParameter,_T("-?")) == 0)) 94 { 95 blnHelp = TRUE; 96 break; 97 } 98 else if (_tcsicmp(pchParameter,_T("/u")) == 0) 99 { 100 blnUnicodeDump = TRUE; 101 } 102 else if ((*pchParameter == _T('/'))&&(*(pchParameter+1) == _T('f'))) 103 { 104 pchFilename = pchParameter+2; 105 } 106 else if (!pchValueFull) 107 { 108 pchValueFull = pchParameter; 109 } 110 else 111 { 112 blnBadParameter = TRUE; 113 } 114 if (blnBadParameter) 115 { 116 rConsole.Write(_T("Bad parameter: ")); 117 rConsole.Write(pchParameter); 118 rConsole.Write(_T("\n")); 119 } 120 } 121 122 CRegistryKey Key; 123 TCHAR *pchValueName; 124 const TCHAR *pszEmpty = _T(""); 125 const TCHAR *pszPath; 126 127 if (blnHelp) 128 { 129 rConsole.Write(GetHelpString()); 130 131 if (pDataBuffer) 132 delete pDataBuffer; 133 134 return 0; 135 } 136 137 if (pchValueFull) 138 { 139 if (_tcscmp(pchValueFull,_T("\\")) == 0) 140 goto ValueCommandNAonRoot; 141 142 TCHAR *pchSep = _tcsrchr(pchValueFull,_T('\\')); 143 pchValueName = pchSep?(pchSep+1):(pchValueFull); 144 pszPath = pchSep?pchValueFull:_T("."); 145 146 //if (_tcsrchr(pchValueName,_T('.'))) 147 //{ 148 // pchValueName = _T(""); 149 // pchPath = pchValueFull; 150 //} 151 //else 152 if (pchSep) 153 *pchSep = 0; 154 } 155 else 156 { 157 pchValueName = (TCHAR*)pszEmpty; 158 pszPath = _T("."); 159 } 160 161 if (!m_rTree.GetKey(pszPath,KEY_READ,Key)) 162 { 163 rConsole.Write(m_rTree.GetLastErrorDescription()); 164 goto SkipValueCommand; 165 } 166 167 if (Key.IsRoot()) 168 goto ValueCommandNAonRoot; 169 170 { 171 rConsole.Write(_T("Value name : \"")); 172 rConsole.Write(_T("\\")); 173 rConsole.Write(Key.GetKeyName()); 174 size_t l = _tcslen(pchValueName); 175 if (l&& 176 (*pchValueName == _T('\"'))&& 177 (pchValueName[l-1] == _T('\"'))) 178 { 179 pchValueName[l-1] = 0; 180 pchValueName++; 181 } 182 rConsole.Write(pchValueName); 183 rConsole.Write(_T("\"\n")); 184 185 nError = Key.GetValue(pchValueName,NULL,NULL,&dwValueSize); 186 if (nError == ERROR_SUCCESS) 187 { 188 pDataBuffer = new BYTE [dwValueSize]; 189 Key.GetValue(pchValueName,&dwType,pDataBuffer,&dwValueSize); 190 rConsole.Write(_T("Value type : ")); 191 rConsole.Write(CRegistryKey::GetValueTypeName(dwType)); 192 rConsole.Write(_T("\nValue data : ")); 193 switch(dwType) 194 { 195 case REG_DWORD_LITTLE_ENDIAN: 196 { 197 TCHAR Buffer[3]; 198 rConsole.Write(_T("0x")); 199 for (unsigned int i = 0 ; i < dwValueSize ; i++) 200 { 201 _stprintf(Buffer,_T("%02X"),*(pDataBuffer+((dwValueSize-1)-i))); 202 rConsole.Write(Buffer); 203 } 204 } 205 rConsole.Write(_T("\n")); 206 break; 207 case REG_DWORD_BIG_ENDIAN: 208 { 209 TCHAR Buffer[3]; 210 rConsole.Write(_T("0x")); 211 for (unsigned int i = 0 ; i < dwValueSize ; i++) 212 { 213 _stprintf(Buffer,_T("%02X"),*(pDataBuffer+i)); 214 rConsole.Write(Buffer); 215 } 216 } 217 rConsole.Write(_T("\n")); 218 break; 219 case REG_LINK: 220 break; 221 case REG_MULTI_SZ: 222 { 223 TCHAR *pchCurrentString = (TCHAR *)pDataBuffer; 224 rConsole.Write(_T("\n")); 225 while(*pchCurrentString) 226 { 227 rConsole.Write(_T("\"")); 228 rConsole.Write(pchCurrentString); 229 rConsole.Write(_T("\"\n")); 230 pchCurrentString += _tcslen(pchCurrentString)+1; 231 } 232 } 233 break; 234 case REG_RESOURCE_LIST: 235 break; 236 case REG_SZ: 237 case REG_EXPAND_SZ: 238 rConsole.Write(_T("\"")); 239 rConsole.Write((TCHAR *)pDataBuffer); 240 rConsole.Write(_T("\"\n")); 241 break; 242 case REG_BINARY: 243 default: 244 { 245 TCHAR Buffer[256]; 246 DWORD i, j; 247 for (i = 0 ; i < dwValueSize ; i++) 248 { 249 if (i%16 == 0) 250 { // ok this is begining of line 251 rConsole.Write(_T("\n")); 252 // print offset 253 _stprintf(Buffer,_T("0x%08X "),(unsigned int)i); 254 rConsole.Write(Buffer); 255 } 256 else if (i%8 == 0) 257 { // this is the additional space between 7th and 8th byte in current line 258 rConsole.Write(_T(" ")); 259 } 260 261 // print current byte 262 unsigned int n = *(pDataBuffer+i); 263 _stprintf(Buffer,_T("%02X "),n); 264 rConsole.Write(Buffer); 265 266 if (i && (i%16 == 15)) 267 { // if this is the last byte in line 268 // Dump text representation 269 for (j = i-15; j <= i; j += blnUnicodeDump?2:1)\ 270 { 271 if ((j%8 == 0)&&(j%16 != 0)) 272 { // this is the additional space between 7th and 8th byte in current line 273 rConsole.Write(_T(" ")); 274 } 275 ASSERT(i-j < 16); 276 // write current char representation 277 if (blnUnicodeDump) 278 { 279 ASSERT(j%2 == 0); 280 wchar_t ch = *(TCHAR *)(pDataBuffer+j); 281 282 _stprintf(Buffer, 283 #ifdef _UNICODE 284 _T("%c"), 285 #else 286 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3)) 287 // %C in format string is a Microsoft extension. 288 _T("%C"), 289 #endif 290 iswprint(ch)?ch:L'.'); 291 } 292 else 293 { 294 unsigned char ch = *(pDataBuffer+j); 295 296 _stprintf(Buffer, 297 #ifdef _UNICODE 298 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3)) 299 // %C in format string is a Microsoft extension. 300 _T("%C"), 301 #else 302 _T("%c"), 303 #endif 304 isprint(ch)?ch:'.'); 305 } 306 rConsole.Write(Buffer); 307 } // for 308 } // if 309 } // for 310 311 // print text representation of last line if it is not full (it have less than 16 bytes) 312 // k is pseudo offset 313 for (DWORD k = i; k%16 != 0; k++) 314 { 315 if (k%8 == 0) 316 { // this is the additional space between 7th and 8th byte in current line 317 rConsole.Write(_T(" ")); 318 } 319 _tcscpy(Buffer,_T(" ")); // the replacement of two digit of current byte + spacing 320 rConsole.Write(Buffer); 321 if (k && (k%16 == 15)) 322 { // if this is the last byte in line 323 ASSERT((k-15)%16 == 0); // k-15 must point at begin of last line 324 for (j = k-15; j < i; j += blnUnicodeDump?2:1) 325 { 326 if (blnUnicodeDump&&(j+1 >= i)) 327 { // ok, buffer size is odd number, so we don't display last byte. 328 ASSERT(j+1 == i); 329 break; 330 } 331 if ((j%8 == 0)&&(j%16 != 0)) 332 { // this is the additional space between 7th and 8th byte in current line 333 rConsole.Write(_T(" ")); 334 } 335 336 // write current char representation 337 if (blnUnicodeDump) 338 { 339 ASSERT(j%2 == 0); 340 wchar_t ch = *(TCHAR *)(pDataBuffer+j); 341 342 _stprintf(Buffer, 343 #ifdef _UNICODE 344 _T("%c"), 345 #else 346 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3)) 347 // %C in format string is a Microsoft extension. 348 _T("%C"), 349 #endif 350 iswprint(ch)?ch:L'.'); 351 } 352 else 353 { 354 unsigned char ch = *(pDataBuffer+j); 355 356 _stprintf(Buffer, 357 #ifdef _UNICODE 358 // g++ may print warnings here (warning: __wchar_t format, different type arg (arg 3)) 359 // %C in format string is a Microsoft extension. 360 _T("%C"), 361 #else 362 _T("%c"), 363 #endif 364 isprint(ch)?ch:'.'); 365 } 366 rConsole.Write(Buffer); 367 } // for 368 } // if 369 } // for 370 } // default: 371 rConsole.Write(_T("\n")); 372 } // switch 373 rConsole.Write(_T("\n")); 374 375 if (pchFilename) 376 { 377 rConsole.Write(_T("Exporting value data to ")); 378 rConsole.Write(pchFilename); 379 rConsole.Write(_T(" ...\n")); 380 381 HANDLE hFile = CreateFile(pchFilename,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL); 382 if (hFile == INVALID_HANDLE_VALUE) 383 { 384 rConsole.Write(_T("Cannot create new file ")); 385 rConsole.Write(pchFilename); 386 rConsole.Write(_T("\n")); 387 goto SkipValueCommand; 388 } 389 390 DWORD dwBytesWritten; 391 if (!WriteFile(hFile,pDataBuffer,dwValueSize,&dwBytesWritten,NULL)) 392 { 393 rConsole.Write(_T("Error writing file.\n")); 394 VERIFY(CloseHandle(hFile)); 395 goto SkipValueCommand; 396 } 397 398 ASSERT(dwBytesWritten == dwValueSize); 399 VERIFY(CloseHandle(hFile)); 400 } 401 } 402 else 403 { 404 rConsole.Write(_T("Error ")); 405 TCHAR Buffer[256]; 406 rConsole.Write(_itoa(nError,Buffer,10)); 407 rConsole.Write(_T("\n")); 408 if (nError == ERROR_FILE_NOT_FOUND) 409 { 410 rConsole.Write(_T("(System cannot find the value specified)\n")); 411 } 412 } 413 } 414 415 SkipValueCommand: 416 if (pDataBuffer) 417 delete[] pDataBuffer; 418 return 0; 419 ValueCommandNAonRoot: 420 rConsole.Write(VALUE_CMD COMMAND_NA_ON_ROOT); 421 return 0; 422 } 423 424 const TCHAR * CShellCommandValue::GetHelpString() 425 { 426 return VALUE_CMD_SHORT_DESC 427 _T("Syntax: ") VALUE_CMD _T(" [<PATH>][<VALUE_NAME>] [/u] [/?]\n\n") 428 _T(" <PATH> - Optional relative path of key which value will be processed.\n") 429 _T(" <VALUE_NAME> - Name of key's value. Default is key's default value.\n") 430 _T(" /u - On binary dump view as Unicode.\n") 431 _T(" /fFILE - Export value data to FILE.\n") 432 _T(" /? - This help.\n\n") 433 _T("Without parameters, command displays default value of current key.\n"); 434 } 435 436 const TCHAR * CShellCommandValue::GetHelpShortDescriptionString() 437 { 438 return VALUE_CMD_SHORT_DESC; 439 } 440