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