1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_registry.hxx"
26 
27 #include "registry/registry.hxx"
28 #include "registry/reflread.hxx"
29 #include "fileurl.hxx"
30 #include "options.hxx"
31 
32 #include "rtl/ustring.hxx"
33 #include "osl/diagnose.h"
34 
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include <vector>
39 #include <string>
40 
41 using namespace rtl;
42 using namespace registry::tools;
43 
44 #define U2S( s ) \
45 	OUStringToOString(s, RTL_TEXTENCODING_UTF8).getStr()
46 #define S2U( s ) \
47 	OStringToOUString(s, RTL_TEXTENCODING_UTF8)
48 
49 class Options_Impl : public Options
50 {
51 public:
52 	explicit Options_Impl(char const * program)
53 		: Options (program), m_bForceOutput(false)
54 		{}
55 
56     std::string const & getIndexReg() const
57         { return m_indexRegName; }
58     std::string const & getTypeReg() const
59 		{ return m_typeRegName; }
60 	bool hasBase() const
61         { return (m_base.getLength() > 0); }
62 	const OString & getBase() const
63 		{ return m_base; }
64 	bool forceOutput() const
65 		{ return m_bForceOutput; }
66 
67 protected:
68 	virtual void printUsage_Impl() const;
69     virtual bool initOptions_Impl (std::vector< std::string > & rArgs);
70 
71     std::string m_indexRegName;
72     std::string m_typeRegName;
73 	OString		m_base;
74     bool m_bForceOutput;
75 };
76 
77 // virtual
78 void Options_Impl::printUsage_Impl() const
79 {
80     std::string const & rProgName = getProgramName();
81     fprintf(stderr,
82             "Usage: %s -r<filename> -o<filename> [-options] | @<filename>\n", rProgName.c_str()
83             );
84     fprintf(stderr,
85             "    -o<filename>  = filename specifies the name of the new singleton index registry.\n"
86             "    -r<filename>  = filename specifies the name of the type registry.\n"
87             "    @<filename>   = filename specifies a command file.\n"
88             "Options:\n"
89             "    -b<name>  = name specifies the name of a start key. The types will be searched\n"
90             "                under this key in the type registry.\n"
91             "    -f        = force the output of all found singletons.\n"
92             "    -h|-?     = print this help message and exit.\n"
93             );
94     fprintf(stderr,
95             "\n%s Version 1.0\n\n", rProgName.c_str()
96             );
97 }
98 
99 // virtual
100 bool Options_Impl::initOptions_Impl(std::vector< std::string > & rArgs)
101 {
102     std::vector< std::string >::const_iterator first = rArgs.begin(), last = rArgs.end();
103     for (; first != last; ++first)
104     {
105         std::string option (*first);
106         if ((*first)[0] != '-')
107         {
108             return badOption("invalid", option.c_str());
109         }
110         switch ((*first)[1])
111         {
112         case 'r':
113         case 'R':
114             {
115                 if (!((++first != last) && ((*first)[0] != '-')))
116                 {
117                     return badOption("invalid", option.c_str());
118                 }
119                 m_typeRegName = OString((*first).c_str(), (*first).size());
120                 break;
121             }
122         case 'o':
123         case 'O':
124             {
125                 if (!((++first != last) && ((*first)[0] != '-')))
126                 {
127                     return badOption("invalid", option.c_str());
128                 }
129                 m_indexRegName = (*first);
130                 break;
131             }
132         case 'b':
133         case 'B':
134             {
135                 if (!((++first != last) && ((*first)[0] != '-')))
136                 {
137                     return badOption("invalid", option.c_str());
138                 }
139                 m_base = OString((*first).c_str(), (*first).size());
140                 break;
141             }
142         case 'f':
143         case 'F':
144             {
145 			    if ((*first).size() > 2)
146                 {
147                     return badOption("invalid", option.c_str());
148                 }
149                 m_bForceOutput = sal_True;
150                 break;
151             }
152         case 'h':
153         case '?':
154             {
155 			    if ((*first).size() > 2)
156                 {
157                     return badOption("invalid", option.c_str());
158                 }
159                 return printUsage();
160                 // break; // unreachable
161             }
162         default:
163             return badOption("unknown", option.c_str());
164             // break; // unreachable
165         }
166     }
167     return true;
168 }
169 
170 static sal_Bool checkSingletons(Options_Impl const & options, RegistryKey& singletonKey, RegistryKey& typeKey)
171 {
172 	RegValueType valueType = RG_VALUETYPE_NOT_DEFINED;
173 	sal_uInt32 size = 0;
174 	OUString tmpName;
175     sal_Bool bRet = sal_False;
176 
177 	RegError e = typeKey.getValueInfo(tmpName, &valueType, &size);
178     if ((e != REG_VALUE_NOT_EXISTS) && (e != REG_INVALID_VALUE) && (valueType == RG_VALUETYPE_BINARY))
179 	{
180         std::vector< sal_uInt8 > value(size);
181         typeKey.getValue(tmpName, &value[0]); // @@@ broken api: write to buffer w/o buffer size.
182 
183 		RegistryTypeReader reader(&value[0], value.size(), sal_False);
184 		if ( reader.isValid() && reader.getTypeClass() == RT_TYPE_SINGLETON )
185         {
186             RegistryKey entryKey;
187 			OUString    singletonName = reader.getTypeName().replace('/', '.');
188 			if ( singletonKey.createKey(singletonName, entryKey) )
189             {
190 				fprintf(stderr, "%s: could not create SINGLETONS entry for \"%s\"\n",
191 					options.getProgramName().c_str(), U2S( singletonName ));
192             }
193             else
194             {
195 				bRet = sal_True;
196                 OUString value2 = reader.getSuperTypeName();
197 
198 				if ( entryKey.setValue(tmpName, RG_VALUETYPE_UNICODE,
199                 					   (RegValue)value2.getStr(), sizeof(sal_Unicode)* (value2.getLength()+1)) )
200 				{
201 					fprintf(stderr, "%s: could not create data entry for singleton \"%s\"\n",
202 							options.getProgramName().c_str(), U2S( singletonName ));
203 				}
204 
205 				if ( options.forceOutput() )
206 				{
207 					fprintf(stderr, "%s: create SINGLETON entry for \"%s\" -> \"%s\"\n",
208 							options.getProgramName().c_str(), U2S( singletonName ), U2S(value2));
209             	}
210             }
211         }
212 	}
213 
214    	RegistryKeyArray subKeys;
215 	typeKey.openSubKeys(tmpName, subKeys);
216 
217 	sal_uInt32 length = subKeys.getLength();
218 	for (sal_uInt32 i = 0; i < length; i++)
219 	{
220         RegistryKey elementKey = subKeys.getElement(i);
221 		if ( checkSingletons(options, singletonKey, elementKey) )
222 		{
223 			bRet = sal_True;
224 		}
225 	}
226 	return bRet;
227 }
228 
229 #if (defined UNX) || (defined OS2) || (defined __MINGW32__)
230 int main( int argc, char * argv[] )
231 #else
232 int _cdecl main( int argc, char * argv[] )
233 #endif
234 {
235     std::vector< std::string > args;
236     for (int i = 1; i < argc; i++)
237     {
238         int result = Options::checkArgument(args, argv[i], strlen(argv[i]));
239         if (result != 0)
240         {
241             // failure.
242             return (result);
243         }
244     }
245 
246     Options_Impl options(argv[0]);
247     if (!options.initOptions(args))
248 	{
249         options.printUsage();
250 		return (1);
251 	}
252 
253 	OUString indexRegName( convertToFileUrl(options.getIndexReg().c_str(), options.getIndexReg().size()) );
254 	Registry indexReg;
255 	if ( indexReg.open(indexRegName, REG_READWRITE) )
256 	{
257 		if ( indexReg.create(indexRegName) )
258 		{
259 			fprintf(stderr, "%s: open registry \"%s\" failed\n",
260 					options.getProgramName().c_str(), options.getIndexReg().c_str());
261 			return (2);
262         }
263 	}
264 
265 	OUString typeRegName( convertToFileUrl(options.getTypeReg().c_str(), options.getTypeReg().size()) );
266 	Registry typeReg;
267 	if ( typeReg.open(typeRegName, REG_READONLY) )
268 	{
269 		fprintf(stderr, "%s: open registry \"%s\" failed\n",
270 				options.getProgramName().c_str(), options.getTypeReg().c_str());
271 		return (3);
272 	}
273 
274 	RegistryKey indexRoot;
275 	if ( indexReg.openRootKey(indexRoot) )
276 	{
277 		fprintf(stderr, "%s: open root key of registry \"%s\" failed\n",
278 				options.getProgramName().c_str(), options.getIndexReg().c_str());
279 		return (4);
280 	}
281 
282 	RegistryKey typeRoot;
283 	if ( typeReg.openRootKey(typeRoot) )
284 	{
285 		fprintf(stderr, "%s: open root key of registry \"%s\" failed\n",
286 				options.getProgramName().c_str(), options.getTypeReg().c_str());
287 		return (5);
288 	}
289 
290 	RegistryKey typeKey;
291 	if ( options.hasBase() )
292 	{
293 		if ( typeRoot.openKey(S2U(options.getBase()), typeKey) )
294 		{
295 			fprintf(stderr, "%s: open base key of registry \"%s\" failed\n",
296 					options.getProgramName().c_str(), options.getTypeReg().c_str());
297 			return (6);
298 		}
299 	}
300     else
301     {
302     	typeKey = typeRoot;
303     }
304 
305 	RegistryKey singletonKey;
306 	if ( indexRoot.createKey(OUString::createFromAscii("SINGLETONS"), singletonKey) )
307 	{
308 		fprintf(stderr, "%s: open/create SINGLETONS key of registry \"%s\" failed\n",
309 				options.getProgramName().c_str(), options.getIndexReg().c_str());
310 		return (7);
311 	}
312 
313 	sal_Bool bSingletonsExist = checkSingletons(options, singletonKey, typeKey);
314 
315 	indexRoot.releaseKey();
316 	typeRoot.releaseKey();
317     typeKey.releaseKey();
318     singletonKey.releaseKey();
319 	if ( indexReg.close() )
320 	{
321 		fprintf(stderr, "%s: closing registry \"%s\" failed\n",
322 				options.getProgramName().c_str(), options.getIndexReg().c_str());
323         return (9);
324 	}
325 	if ( !bSingletonsExist )
326 	{
327 		if ( indexReg.destroy(OUString()) )
328 		{
329 			fprintf(stderr, "%s: destroy registry \"%s\" failed\n",
330 					options.getProgramName().c_str(), options.getIndexReg().c_str());
331 	        return (10);
332 		}
333 	}
334 	if ( typeReg.close() )
335 	{
336 		fprintf(stderr, "%s: closing registry \"%s\" failed\n",
337 				options.getProgramName().c_str(), options.getTypeReg().c_str());
338         return (11);
339 	}
340 }
341