xref: /aosp_15_r20/external/lzma/CPP/Windows/Registry.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Windows/Registry.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <wchar.h>
6 // #include <stdio.h>
7 
8 #ifndef _UNICODE
9 #include "../Common/StringConvert.h"
10 #endif
11 #include "Registry.h"
12 
13 #ifndef _UNICODE
14 extern bool g_IsNT;
15 #endif
16 
17 namespace NWindows {
18 namespace NRegistry {
19 
20 #define MYASSERT(expr) // _ASSERTE(expr)
21 #define MY_ASSUME(expr)
22 
23 /*
24 static void Error()
25 {
26   #ifdef _CONSOLE
27   printf("\nregistry error\n");
28   #else
29   MessageBoxW(0, L"registry error", L"", 0);
30   // exit(1);
31   #endif
32 }
33 
34 #define MY_ASSUME(expr) { if (!(expr)) Error(); }
35 */
36 
Create(HKEY parentKey,LPCTSTR keyName,LPTSTR keyClass,DWORD options,REGSAM accessMask,LPSECURITY_ATTRIBUTES securityAttributes,LPDWORD disposition)37 LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,
38     LPTSTR keyClass, DWORD options, REGSAM accessMask,
39     LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw()
40 {
41   MY_ASSUME(parentKey != NULL);
42   DWORD dispositionReal;
43   HKEY key = NULL;
44   LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass,
45       options, accessMask, securityAttributes, &key, &dispositionReal);
46   if (disposition != NULL)
47     *disposition = dispositionReal;
48   if (res == ERROR_SUCCESS)
49   {
50     res = Close();
51     _object = key;
52   }
53   return res;
54 }
55 
Open(HKEY parentKey,LPCTSTR keyName,REGSAM accessMask)56 LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw()
57 {
58   MY_ASSUME(parentKey != NULL);
59   HKEY key = NULL;
60   LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key);
61   if (res == ERROR_SUCCESS)
62   {
63     res = Close();
64     MYASSERT(res == ERROR_SUCCESS);
65     _object = key;
66   }
67   return res;
68 }
69 
Close()70 LONG CKey::Close() throw()
71 {
72   LONG res = ERROR_SUCCESS;
73   if (_object != NULL)
74   {
75     res = RegCloseKey(_object);
76     _object = NULL;
77   }
78   return res;
79 }
80 
81 // win95, win98: deletes subkey and all its subkeys
82 // winNT to be deleted must not have subkeys
DeleteSubKey(LPCTSTR subKeyName)83 LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
84 {
85   MY_ASSUME(_object != NULL);
86   return RegDeleteKey(_object, subKeyName);
87 }
88 
RecurseDeleteKey(LPCTSTR subKeyName)89 LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw()
90 {
91   {
92     CKey key;
93     LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
94     if (res != ERROR_SUCCESS)
95       return res;
96     FILETIME fileTime;
97     const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
98     TCHAR buffer[kBufSize];
99     // we use loop limit here for some unexpected code failure
100     for (unsigned loop_cnt = 0; loop_cnt < (1u << 26); loop_cnt++)
101     {
102       DWORD size = kBufSize;
103       // we always request starting item (index==0) in each iteration,
104       // because we remove starting item (index==0) in each loop iteration.
105       res = RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime);
106       if (res != ERROR_SUCCESS)
107       {
108         // possible return codes:
109         //   ERROR_NO_MORE_ITEMS : are no more subkeys available
110         //   ERROR_MORE_DATA     : name buffer is too small
111         // we can try to remove (subKeyName), even if there is non ERROR_NO_MORE_ITEMS error.
112         // if (res != ERROR_NO_MORE_ITEMS) return res;
113         break;
114       }
115       res = key.RecurseDeleteKey(buffer);
116       if (res != ERROR_SUCCESS)
117         return res;
118     }
119     // key.Close();
120   }
121   return DeleteSubKey(subKeyName);
122 }
123 
124 
125 /////////////////////////
126 // Value Functions
127 
BoolToUINT32(bool value)128 static inline UInt32 BoolToUINT32(bool value) {  return (value ? 1: 0); }
UINT32ToBool(UInt32 value)129 static inline bool UINT32ToBool(UInt32 value) {  return (value != 0); }
130 
131 
DeleteValue(LPCTSTR name)132 LONG CKey::DeleteValue(LPCTSTR name) throw()
133 {
134   MY_ASSUME(_object != NULL);
135   return ::RegDeleteValue(_object, name);
136 }
137 
138 #ifndef _UNICODE
DeleteValue(LPCWSTR name)139 LONG CKey::DeleteValue(LPCWSTR name)
140 {
141   MY_ASSUME(_object != NULL);
142   if (g_IsNT)
143     return ::RegDeleteValueW(_object, name);
144   return DeleteValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name));
145 }
146 #endif
147 
SetValue(LPCTSTR name,UInt32 value)148 LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw()
149 {
150   MY_ASSUME(_object != NULL);
151   return RegSetValueEx(_object, name, 0, REG_DWORD,
152       (const BYTE *)&value, sizeof(UInt32));
153 }
154 
SetValue(LPCTSTR name,bool value)155 LONG CKey::SetValue(LPCTSTR name, bool value) throw()
156 {
157   return SetValue(name, BoolToUINT32(value));
158 }
159 
160 
161 // value must be string that is NULL terminated
SetValue(LPCTSTR name,LPCTSTR value)162 LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw()
163 {
164   MYASSERT(value != NULL);
165   MY_ASSUME(_object != NULL);
166   // note: RegSetValueEx supports (value == NULL), if (cbData == 0)
167   return RegSetValueEx(_object, name, 0, REG_SZ,
168       (const BYTE *)value, (DWORD)(((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)));
169 }
170 
171 /*
172 LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
173 {
174   MYASSERT(value != NULL);
175   MY_ASSUME(_object != NULL);
176   return RegSetValueEx(_object, name, 0, REG_SZ,
177       (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR));
178 }
179 */
180 
181 #ifndef _UNICODE
182 
SetValue(LPCWSTR name,LPCWSTR value)183 LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
184 {
185   MYASSERT(value != NULL);
186   MY_ASSUME(_object != NULL);
187   if (g_IsNT)
188     return RegSetValueExW(_object, name, 0, REG_SZ,
189         (const BYTE *)value, (DWORD)(((DWORD)wcslen(value) + 1) * sizeof(wchar_t)));
190   return SetValue(name == NULL ? NULL :
191         (LPCSTR)GetSystemString(name),
192         (LPCSTR)GetSystemString(value));
193 }
194 
195 #endif
196 
197 
SetValue(LPCTSTR name,const void * value,UInt32 size)198 LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw()
199 {
200   MYASSERT(value != NULL);
201   MY_ASSUME(_object != NULL);
202   return RegSetValueEx(_object, name, 0, REG_BINARY,
203       (const BYTE *)value, size);
204 }
205 
SetValue(HKEY parentKey,LPCTSTR keyName,LPCTSTR valueName,LPCTSTR value)206 LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
207 {
208   MYASSERT(value != NULL);
209   CKey key;
210   LONG res = key.Create(parentKey, keyName);
211   if (res == ERROR_SUCCESS)
212     res = key.SetValue(valueName, value);
213   return res;
214 }
215 
SetKeyValue(LPCTSTR keyName,LPCTSTR valueName,LPCTSTR value)216 LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw()
217 {
218   MYASSERT(value != NULL);
219   CKey key;
220   LONG res = key.Create(_object, keyName);
221   if (res == ERROR_SUCCESS)
222     res = key.SetValue(valueName, value);
223   return res;
224 }
225 
226 
GetValue_UInt32_IfOk(LPCTSTR name,UInt32 & value)227 LONG CKey::GetValue_UInt32_IfOk(LPCTSTR name, UInt32 &value) throw()
228 {
229   DWORD type = 0;
230   DWORD count = sizeof(value);
231   UInt32 value2; // = value;
232   const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
233   if (res == ERROR_SUCCESS)
234   {
235     // ERROR_UNSUPPORTED_TYPE
236     if (count != sizeof(value) || type != REG_DWORD)
237       return ERROR_UNSUPPORTED_TYPE; // ERROR_INVALID_DATA;
238     value = value2;
239   }
240   return res;
241 }
242 
GetValue_UInt64_IfOk(LPCTSTR name,UInt64 & value)243 LONG CKey::GetValue_UInt64_IfOk(LPCTSTR name, UInt64 &value) throw()
244 {
245   DWORD type = 0;
246   DWORD count = sizeof(value);
247   UInt64 value2; // = value;
248   const LONG res = QueryValueEx(name, &type, (LPBYTE)&value2, &count);
249   if (res == ERROR_SUCCESS)
250   {
251     if (count != sizeof(value) || type != REG_QWORD)
252       return ERROR_UNSUPPORTED_TYPE;
253     value = value2;
254   }
255   return res;
256 }
257 
GetValue_bool_IfOk(LPCTSTR name,bool & value)258 LONG CKey::GetValue_bool_IfOk(LPCTSTR name, bool &value) throw()
259 {
260   UInt32 uintValue;
261   const LONG res = GetValue_UInt32_IfOk(name, uintValue);
262   if (res == ERROR_SUCCESS)
263     value = UINT32ToBool(uintValue);
264   return res;
265 }
266 
267 
268 
QueryValue(LPCTSTR name,CSysString & value)269 LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
270 {
271   value.Empty();
272   LONG res = ERROR_SUCCESS;
273   {
274     // if we don't want multiple calls here,
275     // we can use big value (264) here.
276     // 3 is default available length in new string.
277     DWORD size_prev = 3 * sizeof(TCHAR);
278     // at least 2 attempts are required. But we use more attempts for cases,
279     // where string can be changed by anothner process
280     for (unsigned i = 0; i < 2 + 2; i++)
281     {
282       DWORD type = 0;
283       DWORD size = size_prev;
284       {
285         LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(TCHAR));
286         res = QueryValueEx(name, &type, size == 0 ? NULL : buf, &size);
287         // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
288       }
289       if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
290       {
291         if (type != REG_SZ && type != REG_EXPAND_SZ)
292         {
293           res = ERROR_UNSUPPORTED_TYPE;
294           size = 0;
295         }
296       }
297       else
298         size = 0;
299       if (size > size_prev)
300       {
301         size_prev = size;
302         size = 0;
303         res = ERROR_MORE_DATA;
304       }
305       value.ReleaseBuf_CalcLen(size / sizeof(TCHAR));
306       if (res != ERROR_MORE_DATA)
307         return res;
308     }
309   }
310   return res;
311 }
312 
313 
314 #ifndef _UNICODE
315 
QueryValue(LPCWSTR name,UString & value)316 LONG CKey::QueryValue(LPCWSTR name, UString &value)
317 {
318   value.Empty();
319   LONG res = ERROR_SUCCESS;
320   if (g_IsNT)
321   {
322     DWORD size_prev = 3 * sizeof(wchar_t);
323     for (unsigned i = 0; i < 2 + 2; i++)
324     {
325       DWORD type = 0;
326       DWORD size = size_prev;
327       {
328         LPBYTE buf = (LPBYTE)value.GetBuf(size / sizeof(wchar_t));
329         res = RegQueryValueExW(_object, name, NULL, &type,
330             size == 0 ? NULL : buf, &size);
331       }
332       if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
333       {
334         if (type != REG_SZ && type != REG_EXPAND_SZ)
335         {
336           res = ERROR_UNSUPPORTED_TYPE;
337           size = 0;
338         }
339       }
340       else
341         size = 0;
342       if (size > size_prev)
343       {
344         size_prev = size;
345         size = 0;
346         res = ERROR_MORE_DATA;
347       }
348       value.ReleaseBuf_CalcLen(size / sizeof(wchar_t));
349       if (res != ERROR_MORE_DATA)
350         return res;
351     }
352   }
353   else
354   {
355     AString vTemp;
356     res = QueryValue(name == NULL ? NULL : (LPCSTR)GetSystemString(name), vTemp);
357     value = GetUnicodeString(vTemp);
358   }
359   return res;
360 }
361 
362 #endif
363 
364 
QueryValue_Binary(LPCTSTR name,CByteBuffer & value)365 LONG CKey::QueryValue_Binary(LPCTSTR name, CByteBuffer &value)
366 {
367   // value.Free();
368   DWORD size_prev = 0;
369   LONG res = ERROR_SUCCESS;
370   for (unsigned i = 0; i < 2 + 2; i++)
371   {
372     DWORD type = 0;
373     DWORD size = size_prev;
374     value.Alloc(size_prev);
375     res = QueryValueEx(name, &type, value.NonConstData(), &size);
376     // if (size_prev == 0), then (res == ERROR_SUCCESS) is expected here, because we requested only size.
377     if (res == ERROR_SUCCESS || res == ERROR_MORE_DATA)
378     {
379       if (type != REG_BINARY)
380       {
381         res = ERROR_UNSUPPORTED_TYPE;
382         size = 0;
383       }
384     }
385     else
386       size = 0;
387     if (size > size_prev)
388     {
389       size_prev = size;
390       size = 0;
391       res = ERROR_MORE_DATA;
392     }
393     if (size < value.Size())
394       value.ChangeSize_KeepData(size, size);
395     if (res != ERROR_MORE_DATA)
396       return res;
397   }
398   return res;
399 }
400 
401 
EnumKeys(CSysStringVector & keyNames)402 LONG CKey::EnumKeys(CSysStringVector &keyNames)
403 {
404   keyNames.Clear();
405   CSysString keyName;
406   for (DWORD index = 0; ; index++)
407   {
408     const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL
409     FILETIME lastWriteTime;
410     DWORD nameSize = kBufSize;
411     const LONG res = ::RegEnumKeyEx(_object, index,
412         keyName.GetBuf(kBufSize), &nameSize,
413         NULL, NULL, NULL, &lastWriteTime);
414     keyName.ReleaseBuf_CalcLen(kBufSize);
415     if (res == ERROR_NO_MORE_ITEMS)
416       return ERROR_SUCCESS;
417     if (res != ERROR_SUCCESS)
418       return res;
419     keyNames.Add(keyName);
420   }
421 }
422 
423 
SetValue_Strings(LPCTSTR valueName,const UStringVector & strings)424 LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
425 {
426   size_t numChars = 0;
427   unsigned i;
428 
429   for (i = 0; i < strings.Size(); i++)
430     numChars += strings[i].Len() + 1;
431 
432   CObjArray<wchar_t> buffer(numChars);
433   size_t pos = 0;
434 
435   for (i = 0; i < strings.Size(); i++)
436   {
437     const UString &s = strings[i];
438     const size_t size = s.Len() + 1;
439     wmemcpy(buffer + pos, s, size);
440     pos += size;
441   }
442   // if (pos != numChars) return E_FAIL;
443   return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t));
444 }
445 
GetValue_Strings(LPCTSTR valueName,UStringVector & strings)446 LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
447 {
448   strings.Clear();
449   CByteBuffer buffer;
450   const LONG res = QueryValue_Binary(valueName, buffer);
451   if (res != ERROR_SUCCESS)
452     return res;
453   const size_t dataSize = buffer.Size();
454   if (dataSize % sizeof(wchar_t))
455     return ERROR_INVALID_DATA;
456   const wchar_t *data = (const wchar_t *)(const void *)(const Byte  *)buffer;
457   const size_t numChars = dataSize / sizeof(wchar_t);
458   // we can check that all names are finished
459   // if (numChars != 0 && data[numChars - 1] != 0) return ERROR_INVALID_DATA;
460   size_t prev = 0;
461   UString s;
462   for (size_t i = 0; i < numChars; i++)
463   {
464     if (data[i] == 0)
465     {
466       s = data + prev;
467       strings.Add(s);
468       prev = i + 1;
469     }
470   }
471   return res;
472 }
473 
474 }}
475