1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 //---------------------------------------
29 //
30 //---------------------------------------
31 
32 #include "registryw9x.hxx"
33 
34 #include <windows.h>
35 #include <malloc.h>
36 #include "registryvalueimpl.hxx"
37 #include "registryexception.hxx"
38 #include "stringconverter.hxx"
39 
40 #include <assert.h>
41 
42 #ifdef _MSC_VER
43 #pragma warning(disable : 4786 4350)
44 #endif
45 
46 //---------------------------------------
47 //
48 //---------------------------------------
49 
50 const size_t MAX_TMP_BUFF_SIZE = 1024 * sizeof(wchar_t);
51 
52 
53 //############################################
54 // Creation
55 // only possible through WindowsRegistry class
56 //############################################
57 
58 
59 //-----------------------------------------------------
60 /** Create instance and open the specified Registry key
61 */
62 RegistryKeyImplWin9x::RegistryKeyImplWin9x(HKEY RootKey, const std::wstring& KeyName) :
63 	RegistryKeyImpl(RootKey, KeyName)
64 {
65 }
66 
67 //-----------------------------------------------------
68 /** Create instance and open the specified Registry key
69 */
70 RegistryKeyImplWin9x::RegistryKeyImplWin9x(HKEY RootKey) :
71 	RegistryKeyImpl(RootKey)
72 {
73 }
74 
75 //-----------------------------------------------------
76 /** Create an instances of the specified Registry key,
77 	the key is assumed to be already opened.
78 */
79 RegistryKeyImplWin9x::RegistryKeyImplWin9x(HKEY RootKey, HKEY SubKey, const std::wstring& KeyName, bool Writeable) :
80 	RegistryKeyImpl(RootKey, SubKey, KeyName, Writeable)
81 {
82 }
83 
84 
85 //############################################
86 // Queries
87 //############################################
88 
89 
90 //-----------------------------------------------------
91 /** The number of sub values of the key at hand
92 
93 	@precond IsOpen = true
94 
95 	@throws
96 */
97 size_t RegistryKeyImplWin9x::GetSubValueCount() const
98 {
99 	assert(IsOpen());
100 
101 	DWORD nSubValues = 0;
102 
103 	LONG rc = RegQueryInfoKeyA(
104 		m_hSubKey,
105 		0, 0, 0, 0, 0, 0, &nSubValues, 0, 0, 0, 0);
106 
107 	if (ERROR_INVALID_HANDLE == rc)
108 		throw RegistryIOException(rc);
109 	else if (ERROR_SUCCESS != rc)
110 		throw RegistryException(rc);
111 
112 	return nSubValues;
113 }
114 
115 //-----------------------------------------------------
116 /** The number of sub-keys of the key at hand
117 
118 	@precond IsOpen = true
119 
120 	@throws
121 */
122 size_t RegistryKeyImplWin9x::GetSubKeyCount() const
123 {
124 	assert(IsOpen());
125 
126 	DWORD nSubKeys = 0;
127 
128 	LONG rc = RegQueryInfoKeyA(
129 		m_hSubKey,
130 		0, 0, 0, &nSubKeys, 0, 0, 0, 0, 0, 0, 0);
131 
132 	if (ERROR_INVALID_HANDLE == rc)
133 		throw RegistryIOException(rc);
134 	else if (ERROR_SUCCESS != rc)
135 		throw RegistryException(rc);
136 
137 	return nSubKeys;
138 }
139 
140 //-----------------------------------------------------
141 /**
142 */
143 StringListPtr RegistryKeyImplWin9x::GetSubKeyNames() const
144 {
145 	assert(IsOpen());
146 
147 	char        buff[1024];
148 	DWORD   buff_size = sizeof(buff);
149 	FILETIME ftime;
150 
151 	StringList* key_names = new StringList();
152 
153 	LONG rc = ERROR_SUCCESS;
154 
155 	for (DWORD i = 0; /* left empty */; i++)
156 	{
157 		rc = RegEnumKeyExA(
158 			m_hSubKey, i, buff, &buff_size,
159 			0, 0, 0, &ftime);
160 
161 		if (ERROR_SUCCESS != rc &&
162 			ERROR_MORE_DATA != rc)
163 			break;
164 
165 		buff_size = sizeof(buff);
166 
167 		key_names->push_back(AnsiToUnicodeString(buff));
168 	}
169 
170 	if (ERROR_INVALID_HANDLE == rc)
171 		throw RegistryIOException(rc);
172 	else if (ERROR_NO_MORE_ITEMS != rc && ERROR_SUCCESS != rc)
173 		throw RegistryException(rc);
174 
175 	return (StringListPtr) key_names;
176 }
177 
178 //-----------------------------------------------------
179 /**
180 */
181 StringListPtr RegistryKeyImplWin9x::GetSubValueNames() const
182 {
183 	assert(IsOpen());
184 
185 	char        buff[1024];
186 	DWORD   buff_size = sizeof(buff);
187 
188 	StringList* value_names = new StringList();
189 
190 	LONG rc = ERROR_SUCCESS;
191 
192 	for (DWORD i = 0; /* left empty */; i++)
193 	{
194         rc = RegEnumValueA(
195 			m_hSubKey, i, buff, &buff_size,
196 			0, 0, 0, 0);
197 
198 		if (ERROR_SUCCESS != rc &&
199 			ERROR_MORE_DATA != rc)
200 			break;
201 
202 		buff_size = sizeof(buff);
203 
204 		value_names->push_back(AnsiToUnicodeString(buff));
205 	}
206 
207 	if (ERROR_INVALID_HANDLE == rc)
208 		throw RegistryIOException(rc);
209 	else if (ERROR_NO_MORE_ITEMS != rc && ERROR_SUCCESS != rc)
210 		throw RegistryException(rc);
211 
212 	return (StringListPtr) value_names;
213 }
214 
215 //-----------------------------------------------------
216 /** Get the specified registry value
217 
218 	@precond IsOpen = true
219 */
220 RegistryValue RegistryKeyImplWin9x::GetValue(const std::wstring& Name) const
221 {
222 	assert(IsOpen());
223 
224 	DWORD Type;
225 	char  buff[MAX_TMP_BUFF_SIZE];
226 	DWORD size = sizeof(buff);
227 
228 	LONG rc = RegQueryValueExA(
229 		m_hSubKey,
230 		UnicodeToAnsiString(Name).c_str(),
231 		0,
232 		&Type,
233 		reinterpret_cast<LPBYTE>(buff),
234 		&size);
235 
236 	if (ERROR_FILE_NOT_FOUND == rc)
237 		throw RegistryValueNotFoundException(rc);
238 	else if (ERROR_ACCESS_DENIED == rc)
239 		throw RegistryAccessDeniedException(rc);
240 	else if (ERROR_SUCCESS != rc)
241 		throw RegistryException(rc);
242 
243 	RegistryValue regval;
244 
245 	if (REG_DWORD == Type)
246     {
247 		regval = RegistryValue(new RegistryValueImpl(Name, *(reinterpret_cast<int*>(buff))));
248     }
249 	else if (REG_SZ == Type || REG_EXPAND_SZ == Type || REG_MULTI_SZ == Type)
250     {
251         if (size > 0)
252             regval = RegistryValue(new RegistryValueImpl(Name, std::string(reinterpret_cast<char*>(buff))));
253         else
254             regval = RegistryValue(new RegistryValueImpl(Name, std::string()));
255     }
256 	else
257     {
258 		assert(false);
259     }
260 
261 	return regval;
262 }
263 
264 //-----------------------------------------------------
265 /** Get the specified registry value, return the given
266 	default value if value not found
267 
268 	@precond IsOpen = true
269 */
270 RegistryValue RegistryKeyImplWin9x::GetValue(const std::wstring& Name, const RegistryValue& Default) const
271 {
272 	assert(IsOpen());
273 
274 	DWORD Type;
275 	char  buff[MAX_TMP_BUFF_SIZE];
276 	DWORD size = sizeof(buff);
277 
278 	LONG rc = RegQueryValueExA(
279 		m_hSubKey,
280 		UnicodeToAnsiString(Name).c_str(),
281 		0,
282 		&Type,
283 		reinterpret_cast<LPBYTE>(buff),
284 		&size);
285 
286 	if (ERROR_FILE_NOT_FOUND == rc)
287 	{
288         #if !defined(__MINGW32__) && (_MSC_VER < 1300)
289 		return Default;
290 		#else
291 		RegistryValue regval_ptr;
292 		regval_ptr = RegistryValue(new RegistryValueImpl(*Default));
293 		return regval_ptr;
294 		#endif
295 		}
296 
297 	if (ERROR_ACCESS_DENIED == rc)
298 		throw RegistryAccessDeniedException(rc);
299 	else if (ERROR_SUCCESS != rc)
300 		throw RegistryException(rc);
301 
302 	RegistryValue regval;
303 
304 	if (REG_DWORD == Type)
305 		regval = RegistryValue(new RegistryValueImpl(Name, *reinterpret_cast<int*>(buff)));
306 	else if (REG_SZ == Type || REG_EXPAND_SZ == Type || REG_MULTI_SZ == Type)
307 		regval = RegistryValue(new RegistryValueImpl(Name, std::string(reinterpret_cast<char*>(buff))));
308 	else
309 		assert(false);
310 
311 	return regval;
312 }
313 
314 
315 //############################################
316 // Commands
317 //############################################
318 
319 
320 //-----------------------------------------------------
321 /** Open the registry key, has no effect if
322 	the key is already open
323 
324 	@precond IsOpen = false
325 
326 	@throws RegistryKeyNotFoundException
327 			RegistryWriteAccessDenyException
328 			RegistryAccessDenyException
329 */
330 void RegistryKeyImplWin9x::Open(bool Writeable)
331 {
332 	assert(!IsOpen());
333 
334 	REGSAM regsam = KEY_READ;
335 
336 	if (Writeable)
337 		regsam |= KEY_WRITE;
338 
339 	LONG rc = RegOpenKeyExA(
340 		m_hRootKey,
341 		UnicodeToAnsiString(m_KeyName).c_str(),
342 		0,
343 		regsam,
344 		&m_hSubKey);
345 
346 	if (ERROR_FILE_NOT_FOUND == rc)
347 		throw RegistryKeyNotFoundException(rc);
348 	else if (ERROR_ACCESS_DENIED == rc)
349 		throw RegistryAccessDeniedException(rc);
350 	else if (ERROR_SUCCESS != rc)
351 		throw RegistryException(rc);
352 
353 	m_IsWriteable = Writeable;
354 
355 	assert(IsOpen());
356 }
357 
358 //-----------------------------------------------------
359 /** Open the specified sub-key of the registry key
360 	at hand
361 
362 	@precond IsOpen = true
363 			 HasSubKey(Name) = true
364 
365 	@throws RegistryIOException
366 			RegistryKeyNotFoundException
367 			RegistryAccessDeniedException
368 */
369 RegistryKey RegistryKeyImplWin9x::OpenSubKey(const std::wstring& Name, bool Writeable)
370 {
371 	RegistryKey regkey(new RegistryKeyImplWin9x(m_hSubKey, Name));
372 	regkey->Open(Writeable);
373 	return regkey;
374 }
375 
376 //-----------------------------------------------------
377 /** Creates a new sub-key below the key at hand
378 
379 	@precond IsOpen = true
380 			 IsWriteable = true
381 
382 	@throws  RegistryIOException
383 			 RegistryWriteAccessDenyException
384 */
385 
386 RegistryKey RegistryKeyImplWin9x::CreateSubKey(const std::wstring& Name)
387 {
388 	assert(IsOpen());
389 	assert(IsWriteable());
390 
391 	HKEY hRoot = IsRootKey() ? m_hRootKey : m_hSubKey;
392 
393 	HKEY hKey;
394 
395 	LONG rc = RegCreateKeyExA(
396 		hRoot,
397 		UnicodeToAnsiString(Name).c_str(),
398 		0,
399 		0,
400 		REG_OPTION_NON_VOLATILE,
401 		KEY_READ | KEY_WRITE,
402 		0,
403 		&hKey,
404 		0);
405 
406 	if (ERROR_INVALID_HANDLE == rc)
407 		throw RegistryIOException(rc);
408 	else if (ERROR_ACCESS_DENIED == rc)
409 		throw RegistryAccessDeniedException(rc);
410 	else if (ERROR_SUCCESS != rc)
411 		throw RegistryException(rc);
412 
413 	return RegistryKey(new RegistryKeyImplWin9x(hRoot, hKey, Name));
414 }
415 
416 //-----------------------------------------------------
417 /** Deletes a sub-key below the key at hand, the
418 	key must not have sub-keys
419 
420 	@precond IsOpen = true
421 			 IsWriteable = true
422 
423 	@throws  RegistryIOException
424 			 RegistryWriteAccessDenyException
425 */
426 void RegistryKeyImplWin9x::DeleteSubKey(const std::wstring& Name)
427 {
428 	assert(IsOpen());
429 	assert(IsWriteable());
430 	assert(HasSubKey(Name));
431 
432 	RegistryKey SubKey = OpenSubKey(Name);
433 
434 	size_t nSubKeyCount = SubKey->GetSubKeyCount();
435 
436 	assert(0 == nSubKeyCount);
437 
438 	if (nSubKeyCount)
439 		throw RegistryInvalidOperationException(ERROR_NOT_SUPPORTED);
440 
441 	LONG rc = RegDeleteKeyA(m_hSubKey, UnicodeToAnsiString(Name).c_str());
442 
443 	if (ERROR_INVALID_HANDLE == rc)
444 		throw RegistryIOException(rc);
445 	else if (ERROR_ACCESS_DENIED == rc)
446 		throw RegistryAccessDeniedException(rc);
447 	else if (ERROR_SUCCESS != rc)
448 		throw RegistryException(rc);
449 }
450 
451 //-----------------------------------------------------
452 /** Deletes a sub-key below the key at hand with all
453 	its sub-keys
454 
455 	@precond IsOpen = true
456 			 IsWriteable = true;
457 
458 	@throws  RegistryIOException
459 			 RegistryWriteAccessDenyException
460 */
461 void RegistryKeyImplWin9x::DeleteSubKeyTree(const std::wstring& Name)
462 {
463 	LONG rc = RegDeleteKeyA(m_hSubKey, UnicodeToAnsiString(Name).c_str());
464 
465 	if (ERROR_INVALID_HANDLE == rc)
466 		throw RegistryIOException(rc);
467 	else if (ERROR_ACCESS_DENIED == rc)
468 		throw RegistryAccessDeniedException(rc);
469 	else if (ERROR_SUCCESS != rc)
470 		throw RegistryException(rc);
471 }
472 
473 //-----------------------------------------------------
474 /** Delete the specified value
475 
476 		@precond IsOpen = true
477 				 IsWriteable = true
478 				 HasValue(Name) = true
479 
480 		@throws	RegistryIOException
481 				RegistryWriteAccessDeniedException
482 				RegistryValueNotFoundException
483 */
484 void RegistryKeyImplWin9x::DeleteValue(const std::wstring& Name)
485 {
486 	assert(IsOpen());
487 	assert(HasValue(Name));
488 	assert(IsWriteable());
489 
490 	LONG rc = RegDeleteValueA(
491 		m_hSubKey,
492 		UnicodeToAnsiString(Name).c_str());
493 
494 	if (ERROR_INVALID_HANDLE == rc)
495 		throw RegistryIOException(rc);
496 	else if (ERROR_ACCESS_DENIED == rc)
497 		throw RegistryNoWriteAccessException(rc);
498 	else if (ERROR_FILE_NOT_FOUND == rc)
499 		throw RegistryValueNotFoundException(rc);
500 	else if (ERROR_SUCCESS != rc)
501 		throw RegistryException(rc);
502 }
503 
504 //-----------------------------------------------------
505 /** Set the specified registry value
506 
507 	@precond IsOpen = true
508 			 IsWriteable = true
509 
510 	@throws  RegistryIOException
511 			 RegistryWriteAccessDenyException
512 */
513 void RegistryKeyImplWin9x::SetValue(const RegistryValue& Value)
514 {
515 	assert(IsOpen());
516 	assert(IsWriteable());
517 
518 	LONG rc = ERROR_SUCCESS;
519 
520 	if (REG_SZ == Value->GetType())
521 	{
522 		std::string AnsiStr = Value->GetDataAsAnsiString();
523 
524 		rc = RegSetValueExA(
525 			m_hSubKey,
526 			UnicodeToAnsiString(Value->GetName()).c_str(),
527 			0,
528 			Value->GetType(),
529 			reinterpret_cast<const unsigned char*>(AnsiStr.c_str()),
530 			static_cast<DWORD>((AnsiStr.length() + 1)));
531 	}
532 	else
533 	{
534 		rc = RegSetValueExA(
535 			m_hSubKey,
536 			UnicodeToAnsiString(Value->GetName()).c_str(),
537 			0,
538 			Value->GetType(),
539 			reinterpret_cast<const unsigned char*>(Value->GetDataBuffer()),
540 			static_cast<DWORD>(Value->GetDataSize()));
541 	}
542 
543 	if (ERROR_INVALID_HANDLE == rc)
544 		throw RegistryIOException(rc);
545 	else if (ERROR_ACCESS_DENIED == rc)
546 		throw RegistryAccessDeniedException(rc);
547 	else if (ERROR_SUCCESS != rc)
548 		throw RegistryException(rc);
549 }
550 
551