Chameleon Applications

Chameleon Applications Svn Source Tree

Root/trunk/ChameleonPrefPane/Sources/PropertyList.cpp

1/*
2 * property_list.cpp
3 *
4 * Created by Rekursor on 1/17/10.
5 *
6 */
7
8#import "ChameleonPropertyList.h"
9#include "file_util.h"
10#include <string.h>
11#include <sys/stat.h>
12
13
14//--------------------------------------------------------------------------
15// Simple parsing and splitting args function, does handle env. vars
16//--------------------------------------------------------------------------
17static void parseArgs(const char * args, const char* argv[], int argvlen)
18{
19// Create a list of args fron the space delimited args parameters
20int n=0;
21if (args && *args)
22{
23bool skipSpaces = true;
24bool prevCharwasDelim =false;
25char * buf = strdup(args);
26char lastPriorityDelim=' ';
27
28// printf("Parsing <%s>\n", args);
29
30int k=0;
31for (int i=0; i< strlen(args); i++)
32{
33switch (args[i])
34{
35case ' ': case '\t':
36if(!skipSpaces) {
37buf[k++]=args[i];
38}
39else {
40prevCharwasDelim = true; // // keep a track of delim to further split tokens
41}
42break;
43case '\0':
44case '\'':
45case '"':
46if (!skipSpaces &&lastPriorityDelim!=args[i])
47{ // consider the imbricated delim as a simple char
48buf[k++]=args[i];
49break;
50}
51
52if (!skipSpaces) // end of priority substr
53{
54skipSpaces = true;
55lastPriorityDelim=' ';
56buf[k]='\0';
57argv[n++]=strdup(buf); // copy the priority substr
58k=0; // reset the buf index for next token
59buf[0]='\0';
60}
61else
62{ // start of priority substr
63skipSpaces=false;
64lastPriorityDelim=args[i];
65if(k>0) // previous string to store first
66{
67buf[k++]='\0'; // finish the substr
68argv[n++]=strdup(buf); // copy the substr
69k=0; // rest the index for next token
70buf[0]='\0';
71}
72//if (args[i] !='\0') buf[k++] = args[i]; // start the new priority substr
73}
74break;
75default: // non delimiters chars
76if(skipSpaces && prevCharwasDelim)
77{
78if(k>0) // a previous substr was before the space
79{ // store previous token
80buf[k++]='\0'; // finish the substr
81argv[n++]=strdup(buf); // copy the substr
82k=0; // rest the index for next token
83buf[0]='\0';
84}
85}
86prevCharwasDelim = false;
87buf[k++]=args[i];
88break;
89}
90}
91
92if(*buf)
93{
94buf[k]='\0';
95argv[n++]=strdup(buf); // copy the last buffer
96}
97free((void*) buf);
98}
99argv[n]=NULL;
100}
101
102//--------------------------------------------------------------------------
103// Execute a priviledge shell command : will wait for execution termination
104// by calling wait()
105//--------------------------------------------------------------------------
106 bool executePrivilegedCmd(AuthorizationRef auth,
107 const char* pathToTool,
108 const char* args,
109 AuthorizationFlags flags)
110{
111const char * argv[16];
112
113parseArgs(args, argv, sizeof(argv)/sizeof(const char*));
114
115// Execute Cmd
116OSStatus status = AuthorizationExecuteWithPrivileges(auth, pathToTool,flags, (char**)argv, NULL);
117// Wait for the child process of AEWP to terminate:
118int wait_status=0;
119/* pid_t pid = */
120wait(&wait_status);
121// usleep(10000); // 10 ms
122// Cleanup mem
123for (int i=0; argv[i]; i++) free ((void*) argv[i]);
124
125 return status ? false : true;
126}
127
128//--------------------------------------------------------------------------
129// Execute priviledged chmod for accessing system files
130//--------------------------------------------------------------------------
131bool PropertyList::chmodFile(const char * path, const char * chmodMask,
132 AuthorizationRef auth, AuthorizationFlags flags)
133{
134if (!path || !*path) return false;
135
136if (auth)
137{ // give write temporary write rights to the file
138std::string args = chmodMask;
139args += ' ';
140args += path;
141struct stat st;
142if (stat(path,&st)!=0)
143executePrivilegedCmd(auth, "/usr/bin/touch", path, flags);
144if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))
145return false;
146}
147return true;
148
149}
150
151//--------------------------------------------------------------------------
152// Write a property list from a file
153//--------------------------------------------------------------------------
154bool WritePropertyListToFile( CFPropertyListRef propertyList, CFURLRef fileURL )
155{
156CFDataRef xmlData;
157Boolean status;
158SInt32 errorCode;
159
160// Convert the property list into XML data.
161xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, propertyList );
162
163// Write the XML data to the file.
164status = CFURLWriteDataAndPropertiesToResource (
165fileURL, // URL to use
166xmlData, // data to write
167NULL,
168&errorCode);
169CFRelease(xmlData);
170
171return status ? true: false;
172}
173
174//--------------------------------------------------------------------------
175// Read a property list from a file
176//--------------------------------------------------------------------------
177static CFPropertyListRef CreatePropertyListFromFile( CFURLRef fileURL,
178const std::string& filePath,
179CFStringRef * errorString,
180bool createIfNotExist) {
181CFPropertyListRef propertyList;
182CFDataRef resourceData;
183Boolean status;
184SInt32 errorCode;
185//
186if (!fileExists(filePath))
187{
188if (createIfNotExist)
189{
190CFMutableDictionaryRef dict =
191 CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
192 &kCFTypeDictionaryKeyCallBacks,
193 &kCFTypeDictionaryValueCallBacks );
194WritePropertyListToFile(dict, fileURL);
195}
196
197}
198// Read the XML file.
199status = CFURLCreateDataAndPropertiesFromResource(
200 kCFAllocatorDefault,
201 fileURL,
202 &resourceData, // place to put file data
203 NULL,
204 NULL,
205 &errorCode);
206if (!status) return NULL;
207
208// Reconstitute the dictionary using the XML data.
209propertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
210 resourceData,
211 kCFPropertyListMutableContainersAndLeaves,
212 errorString);
213
214
215CFRelease( resourceData );
216return propertyList;
217}
218
219//--------------------------------------------------------------------------
220// Always return a valid static const string,
221// if the CFSTR is not valid, then we return ""
222//--------------------------------------------------------------------------
223static const char * CfsToCs(CFStringRef inRef)
224{
225static char *buffer=NULL;
226CFIndex len = CFStringGetLength(inRef);
227if (buffer) {
228delete[] buffer;
229}
230buffer = new char[len+1];
231if(CFStringGetFileSystemRepresentation (inRef, buffer, len+1))
232return buffer;
233return "";
234}
235
236//--------------------------------------------------------------------------
237// Destruct a PropertyList Instance
238//--------------------------------------------------------------------------
239PropertyList::~PropertyList()
240{
241cleanup();
242}
243
244//--------------------------------------------------------------------------
245// Cleanup a PropertyList Instance
246//--------------------------------------------------------------------------
247void PropertyList::cleanup()
248{
249if (_CFURLRef)
250{
251CFRelease(_CFURLRef);
252_CFURLRef = NULL;
253}
254
255if (_proplistRef)
256{
257CFRelease(_proplistRef);
258_proplistRef = NULL;
259}
260_propFilePath = "";
261}
262
263//--------------------------------------------------------------------------
264// Open a property list from a path name with auth
265//--------------------------------------------------------------------------
266bool PropertyList::open(const char * path, bool createIfNotExist, AuthorizationRef auth, AuthorizationFlags flags)
267{
268bool ret = false;
269
270cleanup();
271
272if (!path || !*path || !(createIfNotExist || fileExists(path)) )
273return false;
274
275_propFilePath = path;
276CFStringRef cfPath = CFStringCreateWithCString (kCFAllocatorDefault, path, kCFStringEncodingUTF8);
277CFURLRef inURL = CFURLCreateWithFileSystemPath( kCFAllocatorDefault,
278cfPath,
279kCFURLPOSIXPathStyle, // interpret as POSIX path
280false ); // is it a directory?
281CFRelease(cfPath);
282if (_CFURLRef) CFRelease(_CFURLRef);
283_CFURLRef = inURL;
284
285if (_CFURLRef)
286{
287CFRetain(_CFURLRef);
288
289// give write temporary write rights to the file
290if (!chmodFile(path,"0777", auth, flags)) return false;
291
292_proplistRef = CreatePropertyListFromFile(inURL, _propFilePath, &_errorString, createIfNotExist);
293
294// restore rights
295ret= chmodFile(path,"0644", auth, flags);
296
297if (_proplistRef) {
298CFRetain(_proplistRef);
299ret= true;
300}
301}
302
303return ret;
304}
305
306//--------------------------------------------------------------------------
307// Save the current property list
308//--------------------------------------------------------------------------
309bool PropertyList::save(AuthorizationRef auth, AuthorizationFlags flags)
310{
311bool ret=false;
312if (auth)
313{ // give write temporary write rights to the file
314std::string args = " 0777 "+ _propFilePath;
315if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))
316return false;
317}
318if (_proplistRef && _CFURLRef)
319ret= WritePropertyListToFile(_proplistRef,_CFURLRef);
320if (auth)
321{ // give write temporary write rights to the file
322std::string args = " 0644 "+ _propFilePath;
323if(!executePrivilegedCmd(auth, "/bin/chmod", args.c_str(), flags))
324return false;
325}
326return ret;
327}
328
329//--------------------------------------------------------------------------
330// Get a string value from a property list key,
331// value returned is not owned by caller, copy it necessary.
332//--------------------------------------------------------------------------
333const char * PropertyList::getStringForKey(const char *key)
334{
335if (!_proplistRef) return NULL;
336CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);
337CFStringRef myString;
338
339if (_proplistRef && CFDictionaryGetValueIfPresent((CFMutableDictionaryRef)_proplistRef,
340 cfKey, (const void **) &myString))
341{
342CFRelease(cfKey);
343return CfsToCs(myString);
344}
345
346if(cfKey) CFRelease(cfKey);
347return NULL;
348}
349
350//--------------------------------------------------------------------------
351// Replace or add a string value from a property list key,
352// value returned is not owned by caller, copy it necessary.
353//--------------------------------------------------------------------------
354bool PropertyList::setStringForKey(const char *key, const char * value)
355{
356if (!_proplistRef) return false;
357bool ret = false;
358CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);
359CFStringRef myString = CFStringCreateWithCString (kCFAllocatorDefault, value, kCFStringEncodingUTF8);
360CFMutableDictionaryRef myDict = (CFMutableDictionaryRef) _proplistRef;
361
362if (myDict)
363{
364CFDictionarySetValue(myDict, cfKey, myString);
365ret=true;
366}
367if(cfKey) CFRelease(cfKey);
368if(myString) CFRelease(myString);
369return ret;
370}
371
372//--------------------------------------------------------------------------
373// Delete a key and its value from the dictionary
374//--------------------------------------------------------------------------
375bool PropertyList::removeKeyAndValue(const char *key)
376{
377if (!_proplistRef) return false;
378bool ret = false;
379
380CFStringRef cfKey = CFStringCreateWithCString (kCFAllocatorDefault, key, kCFStringEncodingUTF8);
381
382if (_proplistRef) {
383CFDictionaryRemoveValue((CFMutableDictionaryRef) _proplistRef, cfKey);
384ret=true;
385}
386if(cfKey) CFRelease(cfKey);
387return ret;
388}
389
390

Archive Download this file

Revision: 453