1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
13 #pragma warning(push, 1) /* disable warnings within system headers */
15 #define WIN32_LEAN_AND_MEAN
22 #include <com/sun/star/uno/RuntimeException.hpp>
23 #include <com/sun/star/uno/XInterface.hpp>
24 #include <rtl/ustring.hxx>
25 #include <sal/log.hxx>
27 #include <osl/file.hxx>
29 #include "writemodfile.hxx"
31 #define MAX_KEY_LENGTH 255
36 // This is not a generic registry reader. We assume the following structure:
37 // Last element of Key becomes prop, first part is the path and optionally nodes,
38 // when the node has oor:op attribute.
39 // Values can be the following: Value (string), Type (string, optional),
40 // Final (dword, optional), External (dword, optional), ExternalBackend (string, optional)
42 // For example the following registry setting:
43 // [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\LibreOffice\org.openoffice.UserProfile\Data\o]
44 // "Value"="Example Corp."
45 // "Final"=dword:00000001
46 // becomes the following in configuration:
47 // <!-- set the Company name -->
48 // <item oor:path="/org.openoffice.UserProfile/Data">
49 // <prop oor:name="o" oor:finalized="true">
50 // <value>Example Corp.</value>
55 // [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\LibreOffice\org.openoffice.Office.OptionsDialog\OptionsDialogGroups\ProductName/#fuse\Pages\Java/#fuse\Hide]
57 // becomes the following in configuration:
58 // <!-- Hide Tools - Options - LibreOffice - Advanced panel -->
59 // <item oor:path="/org.openoffice.Office.OptionsDialog/OptionsDialogGroups">
60 // <node oor:name="ProductName" oor:op="fuse">
61 // <node oor:name="Pages">
62 // <node oor:name="Java" oor:op="fuse">
63 // <prop oor:name="Hide">
64 // <value>true</value>
71 // Third example (property of an extensible group -> needs type):
72 // [HKEY_LOCAL_MACHINE\SOFTWARE\Policies\LibreOffice\org.openoffice.Office.Jobs\Jobs\org.openoffice.Office.Jobs:Job['UpdateCheck']\Arguments\AutoCheckEnabled]
74 // "Final"=dword:00000001
75 // "Type"="xs:boolean"
76 // becomes the following in configuration:
77 // <item oor:path="/org.openoffice.Office.Jobs/Jobs/org.openoffice.Office.Jobs:Job['UpdateCheck']/Arguments">
78 // <prop oor:name="AutoCheckEnabled" oor:type="xs::boolean" oor:finalized="true">
79 // <value>false</value>
83 // External (component data) example:
84 // [HKEY_CURRENT_USER\Software\Policies\LibreOffice\org.openoffice.UserProfile\Data\o]
86 // "Final"=dword:00000001
87 // "External"=dword:00000001
88 // "ExternalBackend"="com.sun.star.configuration.backend.LdapUserProfileBe"
89 // becomes the following in configuration:
90 // <item oor:path="/org.openoffice.UserProfile/Data">
91 // <prop oor:name="o" oor:finalized="true">
92 // <value oor:external="com.sun.star.configuration.backend.LdapUserProfileBe company"/>
96 void dumpWindowsRegistryKey(HKEY hKey
, OUString
const & aKeyName
, TempFile
&aFileHandle
)
100 if(RegOpenKeyExW(hKey
, aKeyName
.getStr(), 0, KEY_READ
, &hCurKey
) == ERROR_SUCCESS
)
104 DWORD nLongestValueNameLen
, nLongestValueLen
;
105 // Query the number of subkeys
106 RegQueryInfoKeyW(hCurKey
, nullptr, nullptr, nullptr, &nSubKeys
, nullptr, nullptr, &nValues
, &nLongestValueNameLen
, &nLongestValueLen
, nullptr, nullptr);
109 //Look for subkeys in this key
110 for(DWORD i
= 0; i
< nSubKeys
; i
++)
112 wchar_t buffKeyName
[MAX_KEY_LENGTH
];
113 buffKeyName
[0] = '\0';
114 DWORD buffSize
=MAX_KEY_LENGTH
;
115 OUString aSubkeyName
;
117 RegEnumKeyExW(hCurKey
, i
, buffKeyName
, &buffSize
, nullptr, nullptr, nullptr, nullptr);
119 //Make up full key name
120 if(aKeyName
.isEmpty())
121 aSubkeyName
= aKeyName
+ OUString(buffKeyName
);
123 aSubkeyName
= aKeyName
+ "\\" + OUString(buffKeyName
);
125 //Recursion, until no more subkeys are found
126 dumpWindowsRegistryKey(hKey
, aSubkeyName
, aFileHandle
);
131 // No more subkeys, we are at a leaf
132 wchar_t* pValueName
= new wchar_t[nLongestValueNameLen
+ 1];
133 wchar_t* pValue
= new wchar_t[nLongestValueLen
+ 1];
136 bool bExternal
= false;
139 OUString aExternalBackend
;
141 for(DWORD i
= 0; i
< nValues
; ++i
)
143 DWORD nValueNameLen
= nLongestValueNameLen
+ 1;
144 DWORD nValueLen
= nLongestValueLen
+ 1;
146 RegEnumValueW(hCurKey
, i
, pValueName
, &nValueNameLen
, nullptr, nullptr, reinterpret_cast<LPBYTE
>(pValue
), &nValueLen
);
148 if (!wcscmp(pValueName
, L
"Value"))
149 aValue
= OUString(pValue
);
150 else if (!wcscmp(pValueName
, L
"Type"))
151 aType
= OUString(pValue
);
152 else if (!wcscmp(pValueName
, L
"Final"))
154 if (*reinterpret_cast<DWORD
*>(pValue
) == 1)
157 else if (!wcscmp(pValueName
, L
"External"))
159 if (*reinterpret_cast<DWORD
*>(pValue
) == 1)
162 else if (!wcscmp(pValueName
, L
"ExternalBackend"))
163 aExternalBackend
= OUString(pValue
);
167 // type and external are mutually exclusive
170 // Prepend backend, like in
171 // "com.sun.star.configuration.backend.LdapUserProfileBe company"
172 if (!aExternalBackend
.isEmpty())
173 aValue
= aExternalBackend
+ " " + aValue
;
176 sal_Int32 aLastSeparator
= aKeyName
.lastIndexOf('\\');
177 OUString aPathAndNodes
= aKeyName
.copy(0, aLastSeparator
);
178 OUString aProp
= aKeyName
.copy(aLastSeparator
+ 1);
179 bool bHasNode
= false;
180 sal_Int32 nCloseNode
= 0;
182 writeData(aFileHandle
, "<item oor:path=\"");
183 for(sal_Int32 nIndex
= 0;; ++nIndex
)
185 OUString aNextPathPart
= aPathAndNodes
.getToken(nIndex
, '\\');
187 if(!aNextPathPart
.isEmpty())
189 if((aNextPathPart
.lastIndexOf("/#") != -1) || bHasNode
)
193 writeData(aFileHandle
, "\"><node oor:name=\"");
194 sal_Int32 nCommandSeparator
= aNextPathPart
.lastIndexOf('#');
195 if(nCommandSeparator
!= -1)
197 OUString aNodeOp
= aNextPathPart
.copy(nCommandSeparator
+ 1);
198 writeAttributeValue(aFileHandle
, aNextPathPart
.copy(0, nCommandSeparator
- 1));
199 writeData(aFileHandle
, "\" oor:op=\"");
200 writeAttributeValue(aFileHandle
, aNodeOp
);
204 writeAttributeValue(aFileHandle
, aNextPathPart
);
209 writeAttributeValue(aFileHandle
, "/" + aNextPathPart
);
214 writeData(aFileHandle
, "\">");
219 writeData(aFileHandle
, "<prop oor:name=\"");
220 writeAttributeValue(aFileHandle
, aProp
);
221 writeData(aFileHandle
, "\"");
224 writeData(aFileHandle
, " oor:type=\"");
225 writeAttributeValue(aFileHandle
, aType
);
226 writeData(aFileHandle
, "\"");
229 writeData(aFileHandle
, " oor:finalized=\"true\"");
230 writeData(aFileHandle
, "><value");
233 writeData(aFileHandle
, " oor:external=\"");
234 writeAttributeValue(aFileHandle
, aValue
);
235 writeData(aFileHandle
, "\"/");
239 writeData(aFileHandle
, ">");
240 writeValueContent(aFileHandle
, aValue
);
241 writeData(aFileHandle
, "</value");
243 writeData(aFileHandle
, "></prop>");
244 for(; nCloseNode
> 0; nCloseNode
--)
245 writeData(aFileHandle
, "</node>");
246 writeData(aFileHandle
, "</item>\n");
250 RegCloseKey(hCurKey
);
255 bool dumpWindowsRegistry(OUString
* pFileURL
, WinRegType eType
)
258 HKEY hDomain
= eType
== LOCAL_MACHINE
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
;
259 if(RegOpenKeyExW(hDomain
, L
"SOFTWARE\\Policies\\LibreOffice", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
263 ("Windows registry settings do not exist in HKLM\\SOFTWARE\\Policies\\LibreOffice"));
267 TempFile aFileHandle
;
268 switch (osl::FileBase::createTempFile(nullptr, &aFileHandle
.handle
, pFileURL
)) {
269 case osl::FileBase::E_None
:
271 case osl::FileBase::E_ACCES
:
274 ("cannot create temp Windows registry dump (E_ACCES)"));
277 throw css::uno::RuntimeException(
278 "cannot create temporary file");
280 aFileHandle
.url
= *pFileURL
;
283 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<oor:items"
284 " xmlns:oor=\"http://openoffice.org/2001/registry\""
285 " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\""
286 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n");
287 dumpWindowsRegistryKey(hKey
, "", aFileHandle
);
288 writeData(aFileHandle
, "</oor:items>");
289 oslFileError e
= aFileHandle
.closeWithoutUnlink();
290 if (e
!= osl_File_E_None
)
291 SAL_WARN("configmgr", "osl_closeFile failed with " << +e
);
298 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */