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 // ShellCommandSetValue.cpp: implementation of the CShellCommandSetValue class. 23 // 24 ////////////////////////////////////////////////////////////////////// 25 26 #include "ph.h" 27 #include "ShellCommandSetValue.h" 28 #include "RegistryExplorer.h" 29 #include "RegistryTree.h" 30 #include "RegistryKey.h" 31 32 #define SET_VALUE_CMD _T("SV") 33 #define SET_VALUE_CMD_LENGTH COMMAND_LENGTH(SET_VALUE_CMD) 34 #define SET_VALUE_CMD_SHORT_DESC SET_VALUE_CMD _T(" command is used to set value.\n") 35 36 BOOL StringToDWORD(DWORD& rdwOut, const TCHAR *pszIn) 37 { 38 const TCHAR *pszDigits; 39 const TCHAR *pszOctalNumbers = _T("01234567"); 40 const TCHAR *pszDecimalNumbers = _T("0123456789"); 41 const TCHAR *pszHexNumbers = _T("0123456789ABCDEF"); 42 const TCHAR *pszNumbers; 43 unsigned int nBase = 0; 44 if (*pszIn == _T('0')) 45 { 46 if ((*(pszIn+1) == _T('x'))||((*(pszIn+1) == _T('X')))) 47 { // hex 48 nBase = 16; 49 pszDigits = pszIn+2; 50 pszNumbers = pszHexNumbers; 51 } 52 else 53 { // octal 54 nBase = 8; 55 pszDigits = pszIn+1; 56 pszNumbers = pszOctalNumbers; 57 } 58 } 59 else 60 { //decimal 61 nBase = 10; 62 pszDigits = pszIn; 63 pszNumbers = pszDecimalNumbers; 64 } 65 66 const TCHAR *pszDigit = pszDigits; 67 pszDigit += _tcslen(pszDigit); 68 69 DWORD nMul = 1; 70 rdwOut = 0; 71 DWORD dwAdd; 72 const TCHAR *pszNumber; 73 while (pszDigit > pszDigits) 74 { 75 pszDigit--; 76 pszNumber = _tcschr(pszNumbers,*pszDigit); 77 if (!pszNumber) 78 return FALSE; // wrong char in input string 79 80 dwAdd = (pszNumber-pszNumbers)*nMul; 81 82 if (rdwOut + dwAdd < rdwOut) 83 return FALSE; // overflow 84 rdwOut += dwAdd; 85 86 if (nMul * nBase < nMul) 87 return FALSE; // overflow 88 nMul *= nBase; 89 }; 90 91 return TRUE; 92 } 93 94 ////////////////////////////////////////////////////////////////////// 95 // Construction/Destruction 96 ////////////////////////////////////////////////////////////////////// 97 98 CShellCommandSetValue::CShellCommandSetValue(CRegistryTree& rTree):m_rTree(rTree) 99 { 100 } 101 102 CShellCommandSetValue::~CShellCommandSetValue() 103 { 104 } 105 106 BOOL CShellCommandSetValue::Match(const TCHAR *pszCommand) 107 { 108 if (_tcsicmp(pszCommand,SET_VALUE_CMD) == 0) 109 return TRUE; 110 if (_tcsnicmp(pszCommand,SET_VALUE_CMD _T(".."),SET_VALUE_CMD_LENGTH+2*sizeof(TCHAR)) == 0) 111 return TRUE; 112 if (_tcsnicmp(pszCommand,SET_VALUE_CMD _T("/"),SET_VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0) 113 return TRUE; 114 if (_tcsnicmp(pszCommand,SET_VALUE_CMD _T("\\"),SET_VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0) 115 return TRUE; 116 return FALSE; 117 } 118 119 int CShellCommandSetValue::Execute(CConsole &rConsole, CArgumentParser& rArguments) 120 { 121 LONG nError; 122 123 rArguments.ResetArgumentIteration(); 124 TCHAR *pszCommandItself = rArguments.GetNextArgument(); 125 126 TCHAR *pszParameter; 127 TCHAR *pszValueFull = NULL; 128 TCHAR *pszValueData = NULL; 129 BOOL blnBadParameter = FALSE; 130 BOOL blnHelp = FALSE; 131 DWORD dwValueSize = 0; 132 DWORD dwType = REG_NONE; 133 BYTE *pDataBuffer = NULL; 134 135 if ((_tcsnicmp(pszCommandItself,SET_VALUE_CMD _T(".."),SET_VALUE_CMD_LENGTH+2*sizeof(TCHAR)) == 0)|| 136 (_tcsnicmp(pszCommandItself,SET_VALUE_CMD _T("\\"),SET_VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0)) 137 { 138 pszValueFull = pszCommandItself + SET_VALUE_CMD_LENGTH; 139 } 140 else if (_tcsnicmp(pszCommandItself,SET_VALUE_CMD _T("/"),SET_VALUE_CMD_LENGTH+1*sizeof(TCHAR)) == 0) 141 { 142 pszParameter = pszCommandItself + SET_VALUE_CMD_LENGTH; 143 goto CheckValueArgument; 144 } 145 146 while((pszParameter = rArguments.GetNextArgument()) != NULL) 147 { 148 CheckValueArgument: 149 blnBadParameter = FALSE; 150 if (((*pszParameter == _T('/'))||(*pszParameter == _T('-'))) 151 &&(*(pszParameter+1) == _T('?'))) 152 { 153 blnHelp = TRUE; 154 } 155 else if (dwType == REG_NONE) 156 { 157 if (_tcsicmp(pszParameter,_T("b")) == 0) 158 { 159 dwType = REG_BINARY; 160 } 161 else if (_tcsicmp(pszParameter,_T("dw")) == 0) 162 { 163 dwType = REG_DWORD; 164 } 165 else if (_tcsicmp(pszParameter,_T("dwle")) == 0) 166 { 167 dwType = REG_DWORD_LITTLE_ENDIAN; 168 } 169 else if (_tcsicmp(pszParameter,_T("dwbe")) == 0) 170 { 171 dwType = REG_DWORD_BIG_ENDIAN; 172 } 173 else if (_tcsicmp(pszParameter,_T("sz")) == 0) 174 { 175 dwType = REG_SZ; 176 } 177 else if (_tcsicmp(pszParameter,_T("esz")) == 0) 178 { 179 dwType = REG_EXPAND_SZ; 180 } 181 else 182 { 183 blnBadParameter = TRUE; 184 } 185 } 186 else if (pszValueData == NULL) 187 { 188 pszValueData = pszParameter; 189 } 190 else if (!pszValueFull) 191 { 192 pszValueFull = pszParameter; 193 } 194 else 195 { 196 blnBadParameter = TRUE; 197 } 198 if (blnBadParameter) 199 { 200 rConsole.Write(_T("Bad parameter: ")); 201 rConsole.Write(pszParameter); 202 rConsole.Write(_T("\n")); 203 } 204 } 205 206 if (!pszValueData) 207 blnHelp = TRUE; 208 209 CRegistryKey Key; 210 TCHAR *pszValueName; 211 const TCHAR *pszEmpty = _T(""); 212 const TCHAR *pszPath; 213 214 if (blnHelp) 215 { 216 rConsole.Write(GetHelpString()); 217 218 if (pDataBuffer) 219 delete pDataBuffer; 220 221 return 0; 222 } 223 224 if (pszValueFull) 225 { 226 if (_tcscmp(pszValueFull,_T("\\")) == 0) 227 goto CommandNAonRoot; 228 229 TCHAR *pchSep = _tcsrchr(pszValueFull,_T('\\')); 230 pszValueName = pchSep?(pchSep+1):(pszValueFull); 231 pszPath = pchSep?pszValueFull:_T("."); 232 233 //if (_tcsrchr(pszValueName,_T('.'))) 234 //{ 235 // pszValueName = _T(""); 236 // pszPath = pszValueFull; 237 //} 238 //else 239 if (pchSep) 240 *pchSep = 0; 241 } 242 else 243 { 244 pszValueName = (TCHAR*)pszEmpty; 245 pszPath = _T("."); 246 } 247 248 if (!m_rTree.GetKey(pszPath,KEY_SET_VALUE,Key)) 249 { 250 rConsole.Write(m_rTree.GetLastErrorDescription()); 251 goto SkipCommand; 252 } 253 254 if (Key.IsRoot()) 255 goto CommandNAonRoot; 256 257 switch (dwType) 258 { 259 case REG_BINARY: 260 { 261 HANDLE hFile; 262 DWORD dwBytesReaded; 263 hFile = CreateFile(pszValueData,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); 264 if (hFile == INVALID_HANDLE_VALUE) 265 { 266 rConsole.Write(_T("Cannot open file ")); 267 rConsole.Write(pszValueData); 268 rConsole.Write(_T("\n")); 269 goto SkipCommand; 270 } 271 dwValueSize = GetFileSize(hFile,NULL); 272 if (dwValueSize == (DWORD)-1) // ok, that's right, we compare signed with unsigned here. 273 // GetFileSize is documented and declared to return DWORD. 274 // Error is indicated by checking if return is -1. Design->documentation bug ??? 275 { 276 rConsole.Write(_T("Cannot get size of file ")); 277 rConsole.Write(pszValueData); 278 rConsole.Write(_T("\n")); 279 VERIFY(CloseHandle(hFile)); 280 goto SkipCommand; 281 } 282 pDataBuffer = new BYTE [dwValueSize]; 283 if (!pDataBuffer) 284 { 285 rConsole.Write(_T("Cannot load file into memory. Out of memory.\n")); 286 VERIFY(CloseHandle(hFile)); 287 goto SkipCommand; 288 } 289 if (!ReadFile(hFile,pDataBuffer,dwValueSize,&dwBytesReaded,NULL)) 290 { 291 rConsole.Write(_T("Cannot load file into memory. Error reading file.\n")); 292 VERIFY(CloseHandle(hFile)); 293 goto SkipCommand; 294 } 295 296 VERIFY(CloseHandle(hFile)); 297 ASSERT(dwBytesReaded == dwValueSize); 298 } 299 break; 300 case REG_DWORD_LITTLE_ENDIAN: 301 case REG_DWORD_BIG_ENDIAN: 302 dwValueSize = 4; 303 pDataBuffer = (BYTE *) new BYTE [dwValueSize]; 304 if (!StringToDWORD(*(DWORD *)pDataBuffer,pszValueData)) 305 { 306 rConsole.Write(_T("Cannot convert ")); 307 rConsole.Write(pszValueData); 308 rConsole.Write(_T(" to DWORD \n")); 309 goto SkipCommand; 310 } 311 if (dwType == REG_DWORD_BIG_ENDIAN) 312 { 313 unsigned char nByte; 314 nByte = *pDataBuffer; 315 *pDataBuffer = *(pDataBuffer+3); 316 *(pDataBuffer+3) = nByte; 317 nByte = *(pDataBuffer+1); 318 *(pDataBuffer+1) = *(pDataBuffer+2); 319 *(pDataBuffer+2) = nByte; 320 } 321 break; 322 case REG_SZ: 323 case REG_EXPAND_SZ: 324 dwValueSize = _tcslen(pszValueData)+1; 325 if (*pszValueData == _T('\"')) 326 { 327 dwValueSize -= 2; 328 *(pszValueData+dwValueSize) = 0; 329 pszValueData++; 330 } 331 dwValueSize *= sizeof(TCHAR); 332 pDataBuffer = (BYTE *) new BYTE [dwValueSize]; 333 334 { 335 const TCHAR *pchSrc = pszValueData; 336 TCHAR *pchDest = (TCHAR *)pDataBuffer; 337 while(*pchSrc) 338 { 339 if (pchSrc[0] == _T('^')) 340 { 341 if (pchSrc[1] == _T('a')) 342 *pchDest = _T('\a'); 343 else if (pchSrc[1] == _T('b')) 344 *pchDest = _T('\b'); 345 else if (pchSrc[1] == _T('f')) 346 *pchDest = _T('\f'); 347 else if (pchSrc[1] == _T('n')) 348 *pchDest = _T('\n'); 349 else if (pchSrc[1] == _T('r')) 350 *pchDest = _T('\r'); 351 else if (pchSrc[1] == _T('t')) 352 *pchDest = _T('\t'); 353 else 354 *pchDest = pchSrc[1]; 355 356 pchSrc +=2; 357 pchDest++; 358 dwValueSize--; 359 } 360 else 361 { 362 *pchDest = *pchSrc; 363 pchSrc++; 364 pchDest++; 365 } 366 } 367 *pchDest = _T('\0'); 368 } 369 break; 370 default: 371 ASSERT(FALSE); 372 } 373 374 { 375 size_t s = _tcslen(pszValueName); 376 if (s && (pszValueName[0] == _T('\"'))&&(pszValueName[s-1] == _T('\"'))) 377 { 378 pszValueName[s-1] = 0; 379 pszValueName++; 380 } 381 } 382 383 nError = Key.SetValue(pszValueName,dwType,pDataBuffer,dwValueSize); 384 if (nError != ERROR_SUCCESS) 385 { 386 char Buffer[254]; 387 _stprintf(Buffer,_T("Cannot set value. Error is %u\n"),(unsigned int)nError); 388 rConsole.Write(Buffer); 389 } 390 else 391 { 392 InvalidateCompletion(); 393 } 394 395 SkipCommand: 396 if (pDataBuffer) 397 delete[] pDataBuffer; 398 return 0; 399 400 CommandNAonRoot: 401 rConsole.Write(SET_VALUE_CMD COMMAND_NA_ON_ROOT); 402 return 0; 403 } 404 405 const TCHAR * CShellCommandSetValue::GetHelpString() 406 { 407 return SET_VALUE_CMD_SHORT_DESC 408 _T("Syntax: ") SET_VALUE_CMD _T(" <TYPE> <VALUE> [<PATH>][<VALUE_NAME>] [/?]\n\n") 409 _T(" <TYPE> - Type of value to be set. Must be one of following:\n") 410 _T(" b - binary value.\n") 411 _T(" dw - A 32-bit number.\n") 412 _T(" dwle - A 32-bit number in little-endian format.\n") 413 _T(" dwbe - A 32-bit number in big-endian format.\n") 414 _T(" sz - A null-terminated string.\n") 415 _T(" esz - A null-terminated string that contains unexpanded\n") 416 _T(" references to environment variables.\n") 417 // _T(" msz - An array of null-terminated strings,\n") 418 // _T(" terminated by two null characters.\n") 419 _T(" <VALUE> - The data to be set. According to <TYPE>, <VALUE> means:\n") 420 _T(" b - name of file from which to read binary data.\n") 421 _T(" dw \\\n") 422 _T(" dwle - number with syntax: [0 [{ x | X }]] [digits]\n") 423 _T(" dwbe /\n") 424 _T(" sz \\\n") 425 _T(" esz - <VALUE> string is interpreted as string\n") 426 _T(" <PATH> - Optional relative path of key which value will be processed. ^ is the escape char\n") 427 _T(" <VALUE_NAME> - Name of key's value. Default is key's default value.\n") 428 _T(" /? - This help.\n"); 429 } 430 431 const TCHAR * CShellCommandSetValue::GetHelpShortDescriptionString() 432 { 433 return SET_VALUE_CMD_SHORT_DESC; 434 } 435