Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenprofile.c
Go to the documentation of this file.
00001 /* 00002 * Profile functions 00003 * 00004 * Copyright 1993 Miguel de Icaza 00005 * Copyright 1996 Alexandre Julliard 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 */ 00021 00022 //#include "config.h" 00023 //#include "wine/port.h" 00024 00025 #include <string.h> 00026 #include <stdarg.h> 00027 00028 #include "windef.h" 00029 #include "winbase.h" 00030 #include "winnls.h" 00031 #include "winerror.h" 00032 #include "winternl.h" 00033 #include "wine/unicode.h" 00034 #include "wine/library.h" 00035 #include "wine/debug.h" 00036 00037 #define HeapAlloc RtlAllocateHeap 00038 #define HeapReAlloc RtlReAllocateHeap 00039 #define HeapFree RtlFreeHeap 00040 WINE_DEFAULT_DEBUG_CHANNEL(profile); 00041 00042 static const char bom_utf8[] = {0xEF,0xBB,0xBF}; 00043 00044 typedef enum 00045 { 00046 ENCODING_ANSI = 1, 00047 ENCODING_UTF8, 00048 ENCODING_UTF16LE, 00049 ENCODING_UTF16BE 00050 } ENCODING; 00051 00052 typedef struct tagPROFILEKEY 00053 { 00054 WCHAR *value; 00055 struct tagPROFILEKEY *next; 00056 WCHAR name[1]; 00057 } PROFILEKEY; 00058 00059 typedef struct tagPROFILESECTION 00060 { 00061 struct tagPROFILEKEY *key; 00062 struct tagPROFILESECTION *next; 00063 WCHAR name[1]; 00064 } PROFILESECTION; 00065 00066 00067 typedef struct 00068 { 00069 BOOL changed; 00070 PROFILESECTION *section; 00071 WCHAR *filename; 00072 FILETIME LastWriteTime; 00073 ENCODING encoding; 00074 } PROFILE; 00075 00076 00077 #define N_CACHED_PROFILES 10 00078 00079 /* Cached profile files */ 00080 static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL}; 00081 00082 #define CurProfile (MRUProfile[0]) 00083 00084 /* Check for comments in profile */ 00085 #define IS_ENTRY_COMMENT(str) ((str)[0] == ';') 00086 00087 static const WCHAR emptystringW[] = {0}; 00088 static const WCHAR wininiW[] = { 'w','i','n','.','i','n','i',0 }; 00089 00090 static RTL_CRITICAL_SECTION PROFILE_CritSect; 00091 static RTL_CRITICAL_SECTION_DEBUG critsect_debug = 00092 { 00093 0, 0, &PROFILE_CritSect, 00094 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 00095 0, 0, 0 00096 }; 00097 static RTL_CRITICAL_SECTION PROFILE_CritSect = { &critsect_debug, -1, 0, 0, 0, 0 }; 00098 00099 static const char hex[16] = "0123456789ABCDEF"; 00100 00101 /*********************************************************************** 00102 * PROFILE_CopyEntry 00103 * 00104 * Copy the content of an entry into a buffer, removing quotes, and possibly 00105 * translating environment variables. 00106 */ 00107 static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len, 00108 BOOL strip_quote ) 00109 { 00110 WCHAR quote = '\0'; 00111 00112 if(!buffer) return; 00113 00114 if (strip_quote && ((*value == '\'') || (*value == '\"'))) 00115 { 00116 if (value[1] && (value[strlenW(value)-1] == *value)) quote = *value++; 00117 } 00118 00119 lstrcpynW( buffer, value, len ); 00120 if (quote && (len >= lstrlenW(value))) buffer[strlenW(buffer)-1] = '\0'; 00121 } 00122 00123 /* byte-swaps shorts in-place in a buffer. len is in WCHARs */ 00124 static inline void PROFILE_ByteSwapShortBuffer(WCHAR * buffer, int len) 00125 { 00126 int i; 00127 USHORT * shortbuffer = buffer; 00128 for (i = 0; i < len; i++) 00129 shortbuffer[i] = RtlUshortByteSwap(shortbuffer[i]); 00130 } 00131 00132 /* writes any necessary encoding marker to the file */ 00133 static inline void PROFILE_WriteMarker(HANDLE hFile, ENCODING encoding) 00134 { 00135 DWORD dwBytesWritten; 00136 WCHAR bom; 00137 switch (encoding) 00138 { 00139 case ENCODING_ANSI: 00140 break; 00141 case ENCODING_UTF8: 00142 WriteFile(hFile, bom_utf8, sizeof(bom_utf8), &dwBytesWritten, NULL); 00143 break; 00144 case ENCODING_UTF16LE: 00145 bom = 0xFEFF; 00146 WriteFile(hFile, &bom, sizeof(bom), &dwBytesWritten, NULL); 00147 break; 00148 case ENCODING_UTF16BE: 00149 bom = 0xFFFE; 00150 WriteFile(hFile, &bom, sizeof(bom), &dwBytesWritten, NULL); 00151 break; 00152 } 00153 } 00154 00155 static void PROFILE_WriteLine( HANDLE hFile, WCHAR * szLine, int len, ENCODING encoding) 00156 { 00157 char * write_buffer; 00158 int write_buffer_len; 00159 DWORD dwBytesWritten; 00160 00161 TRACE("writing: %s\n", debugstr_wn(szLine, len)); 00162 00163 switch (encoding) 00164 { 00165 case ENCODING_ANSI: 00166 write_buffer_len = WideCharToMultiByte(CP_ACP, 0, szLine, len, NULL, 0, NULL, NULL); 00167 write_buffer = HeapAlloc(GetProcessHeap(), 0, write_buffer_len); 00168 if (!write_buffer) return; 00169 len = WideCharToMultiByte(CP_ACP, 0, szLine, len, write_buffer, write_buffer_len, NULL, NULL); 00170 WriteFile(hFile, write_buffer, len, &dwBytesWritten, NULL); 00171 HeapFree(GetProcessHeap(), 0, write_buffer); 00172 break; 00173 case ENCODING_UTF8: 00174 write_buffer_len = WideCharToMultiByte(CP_UTF8, 0, szLine, len, NULL, 0, NULL, NULL); 00175 write_buffer = HeapAlloc(GetProcessHeap(), 0, write_buffer_len); 00176 if (!write_buffer) return; 00177 len = WideCharToMultiByte(CP_UTF8, 0, szLine, len, write_buffer, write_buffer_len, NULL, NULL); 00178 WriteFile(hFile, write_buffer, len, &dwBytesWritten, NULL); 00179 HeapFree(GetProcessHeap(), 0, write_buffer); 00180 break; 00181 case ENCODING_UTF16LE: 00182 WriteFile(hFile, szLine, len * sizeof(WCHAR), &dwBytesWritten, NULL); 00183 break; 00184 case ENCODING_UTF16BE: 00185 PROFILE_ByteSwapShortBuffer(szLine, len); 00186 WriteFile(hFile, szLine, len * sizeof(WCHAR), &dwBytesWritten, NULL); 00187 break; 00188 default: 00189 FIXME("encoding type %d not implemented\n", encoding); 00190 } 00191 } 00192 00193 /*********************************************************************** 00194 * PROFILE_Save 00195 * 00196 * Save a profile tree to a file. 00197 */ 00198 static void PROFILE_Save( HANDLE hFile, const PROFILESECTION *section, ENCODING encoding ) 00199 { 00200 PROFILEKEY *key; 00201 WCHAR *buffer, *p; 00202 00203 PROFILE_WriteMarker(hFile, encoding); 00204 00205 for ( ; section; section = section->next) 00206 { 00207 int len = 0; 00208 00209 if (section->name[0]) len += strlenW(section->name) + 4; 00210 00211 for (key = section->key; key; key = key->next) 00212 { 00213 len += strlenW(key->name) + 2; 00214 if (key->value) len += strlenW(key->value) + 1; 00215 } 00216 00217 buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 00218 if (!buffer) return; 00219 00220 p = buffer; 00221 if (section->name[0]) 00222 { 00223 *p++ = '['; 00224 strcpyW( p, section->name ); 00225 p += strlenW(p); 00226 *p++ = ']'; 00227 *p++ = '\r'; 00228 *p++ = '\n'; 00229 } 00230 00231 for (key = section->key; key; key = key->next) 00232 { 00233 strcpyW( p, key->name ); 00234 p += strlenW(p); 00235 if (key->value) 00236 { 00237 *p++ = '='; 00238 strcpyW( p, key->value ); 00239 p += strlenW(p); 00240 } 00241 *p++ = '\r'; 00242 *p++ = '\n'; 00243 } 00244 PROFILE_WriteLine( hFile, buffer, len, encoding ); 00245 HeapFree(GetProcessHeap(), 0, buffer); 00246 } 00247 } 00248 00249 00250 /*********************************************************************** 00251 * PROFILE_Free 00252 * 00253 * Free a profile tree. 00254 */ 00255 static void PROFILE_Free( PROFILESECTION *section ) 00256 { 00257 PROFILESECTION *next_section; 00258 PROFILEKEY *key, *next_key; 00259 00260 for ( ; section; section = next_section) 00261 { 00262 for (key = section->key; key; key = next_key) 00263 { 00264 next_key = key->next; 00265 HeapFree( GetProcessHeap(), 0, key->value ); 00266 HeapFree( GetProcessHeap(), 0, key ); 00267 } 00268 next_section = section->next; 00269 HeapFree( GetProcessHeap(), 0, section ); 00270 } 00271 } 00272 00273 /* returns 1 if a character white space else 0 */ 00274 static inline int PROFILE_isspaceW(WCHAR c) 00275 { 00276 /* ^Z (DOS EOF) is a space too (found on CD-ROMs) */ 00277 return isspaceW(c) || c == 0x1a; 00278 } 00279 00280 static inline ENCODING PROFILE_DetectTextEncoding(const void * buffer, int * len) 00281 { 00282 int flags = IS_TEXT_UNICODE_SIGNATURE | 00283 IS_TEXT_UNICODE_REVERSE_SIGNATURE | 00284 IS_TEXT_UNICODE_ODD_LENGTH; 00285 if (*len >= sizeof(bom_utf8) && !memcmp(buffer, bom_utf8, sizeof(bom_utf8))) 00286 { 00287 *len = sizeof(bom_utf8); 00288 return ENCODING_UTF8; 00289 } 00290 RtlIsTextUnicode(buffer, *len, &flags); 00291 if (flags & IS_TEXT_UNICODE_SIGNATURE) 00292 { 00293 *len = sizeof(WCHAR); 00294 return ENCODING_UTF16LE; 00295 } 00296 if (flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE) 00297 { 00298 *len = sizeof(WCHAR); 00299 return ENCODING_UTF16BE; 00300 } 00301 *len = 0; 00302 return ENCODING_ANSI; 00303 } 00304 00305 00306 /*********************************************************************** 00307 * PROFILE_Load 00308 * 00309 * Load a profile tree from a file. 00310 */ 00311 static PROFILESECTION *PROFILE_Load(HANDLE hFile, ENCODING * pEncoding) 00312 { 00313 void *buffer_base, *pBuffer; 00314 WCHAR * szFile; 00315 const WCHAR *szLineStart, *szLineEnd; 00316 const WCHAR *szValueStart, *szEnd, *next_line; 00317 int line = 0, len; 00318 PROFILESECTION *section, *first_section; 00319 PROFILESECTION **next_section; 00320 PROFILEKEY *key, *prev_key, **next_key; 00321 DWORD dwFileSize; 00322 00323 TRACE("%p\n", hFile); 00324 00325 dwFileSize = GetFileSize(hFile, NULL); 00326 if (dwFileSize == INVALID_FILE_SIZE || dwFileSize == 0) 00327 return NULL; 00328 00329 buffer_base = HeapAlloc(GetProcessHeap(), 0 , dwFileSize); 00330 if (!buffer_base) return NULL; 00331 00332 if (!ReadFile(hFile, buffer_base, dwFileSize, &dwFileSize, NULL)) 00333 { 00334 HeapFree(GetProcessHeap(), 0, buffer_base); 00335 WARN("Error %d reading file\n", GetLastError()); 00336 return NULL; 00337 } 00338 len = dwFileSize; 00339 *pEncoding = PROFILE_DetectTextEncoding(buffer_base, &len); 00340 /* len is set to the number of bytes in the character marker. 00341 * we want to skip these bytes */ 00342 pBuffer = (char *)buffer_base + len; 00343 dwFileSize -= len; 00344 switch (*pEncoding) 00345 { 00346 case ENCODING_ANSI: 00347 TRACE("ANSI encoding\n"); 00348 00349 len = MultiByteToWideChar(CP_ACP, 0, pBuffer, dwFileSize, NULL, 0); 00350 szFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 00351 if (!szFile) 00352 { 00353 HeapFree(GetProcessHeap(), 0, buffer_base); 00354 return NULL; 00355 } 00356 MultiByteToWideChar(CP_ACP, 0, pBuffer, dwFileSize, szFile, len); 00357 szEnd = szFile + len; 00358 break; 00359 case ENCODING_UTF8: 00360 TRACE("UTF8 encoding\n"); 00361 00362 len = MultiByteToWideChar(CP_UTF8, 0, pBuffer, dwFileSize, NULL, 0); 00363 szFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 00364 if (!szFile) 00365 { 00366 HeapFree(GetProcessHeap(), 0, buffer_base); 00367 return NULL; 00368 } 00369 MultiByteToWideChar(CP_UTF8, 0, pBuffer, dwFileSize, szFile, len); 00370 szEnd = szFile + len; 00371 break; 00372 case ENCODING_UTF16LE: 00373 TRACE("UTF16 Little Endian encoding\n"); 00374 szFile = pBuffer; 00375 szEnd = (WCHAR *)((char *)pBuffer + dwFileSize); 00376 break; 00377 case ENCODING_UTF16BE: 00378 TRACE("UTF16 Big Endian encoding\n"); 00379 szFile = pBuffer; 00380 szEnd = (WCHAR *)((char *)pBuffer + dwFileSize); 00381 PROFILE_ByteSwapShortBuffer(szFile, dwFileSize / sizeof(WCHAR)); 00382 break; 00383 default: 00384 FIXME("encoding type %d not implemented\n", *pEncoding); 00385 HeapFree(GetProcessHeap(), 0, buffer_base); 00386 return NULL; 00387 } 00388 00389 first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) ); 00390 if(first_section == NULL) 00391 { 00392 if (szFile != pBuffer) 00393 HeapFree(GetProcessHeap(), 0, szFile); 00394 HeapFree(GetProcessHeap(), 0, buffer_base); 00395 return NULL; 00396 } 00397 first_section->name[0] = 0; 00398 first_section->key = NULL; 00399 first_section->next = NULL; 00400 next_section = &first_section->next; 00401 next_key = &first_section->key; 00402 prev_key = NULL; 00403 next_line = szFile; 00404 00405 while (next_line < szEnd) 00406 { 00407 szLineStart = next_line; 00408 next_line = memchrW(szLineStart, '\n', szEnd - szLineStart); 00409 if (!next_line) next_line = memchrW(szLineStart, '\r', szEnd - szLineStart); 00410 if (!next_line) next_line = szEnd; 00411 else next_line++; 00412 szLineEnd = next_line; 00413 00414 line++; 00415 00416 /* get rid of white space */ 00417 while (szLineStart < szLineEnd && PROFILE_isspaceW(*szLineStart)) szLineStart++; 00418 while ((szLineEnd > szLineStart) && PROFILE_isspaceW(szLineEnd[-1])) szLineEnd--; 00419 00420 if (szLineStart >= szLineEnd) continue; 00421 00422 if (*szLineStart == '[') /* section start */ 00423 { 00424 const WCHAR * szSectionEnd; 00425 if (!(szSectionEnd = memrchrW( szLineStart, ']', szLineEnd - szLineStart ))) 00426 { 00427 WARN("Invalid section header at line %d: %s\n", 00428 line, debugstr_wn(szLineStart, (int)(szLineEnd - szLineStart)) ); 00429 } 00430 else 00431 { 00432 szLineStart++; 00433 len = (int)(szSectionEnd - szLineStart); 00434 /* no need to allocate +1 for NULL terminating character as 00435 * already included in structure */ 00436 if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) ))) 00437 break; 00438 memcpy(section->name, szLineStart, len * sizeof(WCHAR)); 00439 section->name[len] = '\0'; 00440 section->key = NULL; 00441 section->next = NULL; 00442 *next_section = section; 00443 next_section = §ion->next; 00444 next_key = §ion->key; 00445 prev_key = NULL; 00446 00447 TRACE("New section: %s\n", debugstr_w(section->name)); 00448 00449 continue; 00450 } 00451 } 00452 00453 /* get rid of white space after the name and before the start 00454 * of the value */ 00455 len = szLineEnd - szLineStart; 00456 if ((szValueStart = memchrW( szLineStart, '=', szLineEnd - szLineStart )) != NULL) 00457 { 00458 const WCHAR *szNameEnd = szValueStart; 00459 while ((szNameEnd > szLineStart) && PROFILE_isspaceW(szNameEnd[-1])) szNameEnd--; 00460 len = szNameEnd - szLineStart; 00461 szValueStart++; 00462 while (szValueStart < szLineEnd && PROFILE_isspaceW(*szValueStart)) szValueStart++; 00463 } 00464 00465 if (len || !prev_key || *prev_key->name) 00466 { 00467 /* no need to allocate +1 for NULL terminating character as 00468 * already included in structure */ 00469 if (!(key = HeapAlloc( GetProcessHeap(), 0, sizeof(*key) + len * sizeof(WCHAR) ))) break; 00470 memcpy(key->name, szLineStart, len * sizeof(WCHAR)); 00471 key->name[len] = '\0'; 00472 if (szValueStart) 00473 { 00474 len = (int)(szLineEnd - szValueStart); 00475 key->value = HeapAlloc( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) ); 00476 memcpy(key->value, szValueStart, len * sizeof(WCHAR)); 00477 key->value[len] = '\0'; 00478 } 00479 else key->value = NULL; 00480 00481 key->next = NULL; 00482 *next_key = key; 00483 next_key = &key->next; 00484 prev_key = key; 00485 00486 TRACE("New key: name=%s, value=%s\n", 00487 debugstr_w(key->name), key->value ? debugstr_w(key->value) : "(none)"); 00488 } 00489 } 00490 if (szFile != pBuffer) 00491 HeapFree(GetProcessHeap(), 0, szFile); 00492 HeapFree(GetProcessHeap(), 0, buffer_base); 00493 return first_section; 00494 } 00495 00496 00497 /*********************************************************************** 00498 * PROFILE_DeleteSection 00499 * 00500 * Delete a section from a profile tree. 00501 */ 00502 static BOOL PROFILE_DeleteSection( PROFILESECTION **section, LPCWSTR name ) 00503 { 00504 while (*section) 00505 { 00506 if ((*section)->name[0] && !strcmpiW( (*section)->name, name )) 00507 { 00508 PROFILESECTION *to_del = *section; 00509 *section = to_del->next; 00510 to_del->next = NULL; 00511 PROFILE_Free( to_del ); 00512 return TRUE; 00513 } 00514 section = &(*section)->next; 00515 } 00516 return FALSE; 00517 } 00518 00519 00520 /*********************************************************************** 00521 * PROFILE_DeleteKey 00522 * 00523 * Delete a key from a profile tree. 00524 */ 00525 static BOOL PROFILE_DeleteKey( PROFILESECTION **section, 00526 LPCWSTR section_name, LPCWSTR key_name ) 00527 { 00528 while (*section) 00529 { 00530 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name )) 00531 { 00532 PROFILEKEY **key = &(*section)->key; 00533 while (*key) 00534 { 00535 if (!strcmpiW( (*key)->name, key_name )) 00536 { 00537 PROFILEKEY *to_del = *key; 00538 *key = to_del->next; 00539 HeapFree( GetProcessHeap(), 0, to_del->value); 00540 HeapFree( GetProcessHeap(), 0, to_del ); 00541 return TRUE; 00542 } 00543 key = &(*key)->next; 00544 } 00545 } 00546 section = &(*section)->next; 00547 } 00548 return FALSE; 00549 } 00550 00551 00552 /*********************************************************************** 00553 * PROFILE_DeleteAllKeys 00554 * 00555 * Delete all keys from a profile tree. 00556 */ 00557 static void PROFILE_DeleteAllKeys( LPCWSTR section_name) 00558 { 00559 PROFILESECTION **section= &CurProfile->section; 00560 while (*section) 00561 { 00562 if ((*section)->name[0] && !strcmpiW( (*section)->name, section_name )) 00563 { 00564 PROFILEKEY **key = &(*section)->key; 00565 while (*key) 00566 { 00567 PROFILEKEY *to_del = *key; 00568 *key = to_del->next; 00569 HeapFree( GetProcessHeap(), 0, to_del->value); 00570 HeapFree( GetProcessHeap(), 0, to_del ); 00571 CurProfile->changed =TRUE; 00572 } 00573 } 00574 section = &(*section)->next; 00575 } 00576 } 00577 00578 00579 /*********************************************************************** 00580 * PROFILE_Find 00581 * 00582 * Find a key in a profile tree, optionally creating it. 00583 */ 00584 static PROFILEKEY *PROFILE_Find( PROFILESECTION **section, LPCWSTR section_name, 00585 LPCWSTR key_name, BOOL create, BOOL create_always ) 00586 { 00587 LPCWSTR p; 00588 int seclen, keylen; 00589 00590 while (PROFILE_isspaceW(*section_name)) section_name++; 00591 if (*section_name) 00592 p = section_name + strlenW(section_name) - 1; 00593 else 00594 p = section_name; 00595 00596 while ((p > section_name) && PROFILE_isspaceW(*p)) p--; 00597 seclen = p - section_name + 1; 00598 00599 while (PROFILE_isspaceW(*key_name)) key_name++; 00600 if (*key_name) 00601 p = key_name + strlenW(key_name) - 1; 00602 else 00603 p = key_name; 00604 00605 while ((p > key_name) && PROFILE_isspaceW(*p)) p--; 00606 keylen = p - key_name + 1; 00607 00608 while (*section) 00609 { 00610 if ( ((*section)->name[0]) 00611 && (!(strncmpiW( (*section)->name, section_name, seclen ))) 00612 && (((*section)->name)[seclen] == '\0') ) 00613 { 00614 PROFILEKEY **key = &(*section)->key; 00615 00616 while (*key) 00617 { 00618 /* If create_always is FALSE then we check if the keyname 00619 * already exists. Otherwise we add it regardless of its 00620 * existence, to allow keys to be added more than once in 00621 * some cases. 00622 */ 00623 if(!create_always) 00624 { 00625 if ( (!(strncmpiW( (*key)->name, key_name, keylen ))) 00626 && (((*key)->name)[keylen] == '\0') ) 00627 return *key; 00628 } 00629 key = &(*key)->next; 00630 } 00631 if (!create) return NULL; 00632 if (!(*key = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) ))) 00633 return NULL; 00634 strcpyW( (*key)->name, key_name ); 00635 (*key)->value = NULL; 00636 (*key)->next = NULL; 00637 return *key; 00638 } 00639 section = &(*section)->next; 00640 } 00641 if (!create) return NULL; 00642 *section = HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILESECTION) + strlenW(section_name) * sizeof(WCHAR) ); 00643 if(*section == NULL) return NULL; 00644 strcpyW( (*section)->name, section_name ); 00645 (*section)->next = NULL; 00646 if (!((*section)->key = HeapAlloc( GetProcessHeap(), 0, 00647 sizeof(PROFILEKEY) + strlenW(key_name) * sizeof(WCHAR) ))) 00648 { 00649 HeapFree(GetProcessHeap(), 0, *section); 00650 return NULL; 00651 } 00652 strcpyW( (*section)->key->name, key_name ); 00653 (*section)->key->value = NULL; 00654 (*section)->key->next = NULL; 00655 return (*section)->key; 00656 } 00657 00658 00659 /*********************************************************************** 00660 * PROFILE_FlushFile 00661 * 00662 * Flush the current profile to disk if changed. 00663 */ 00664 static BOOL PROFILE_FlushFile(void) 00665 { 00666 HANDLE hFile = NULL; 00667 FILETIME LastWriteTime; 00668 00669 if(!CurProfile) 00670 { 00671 WARN("No current profile!\n"); 00672 return FALSE; 00673 } 00674 00675 if (!CurProfile->changed) return TRUE; 00676 00677 hFile = CreateFileW(CurProfile->filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 00678 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 00679 00680 if (hFile == INVALID_HANDLE_VALUE) 00681 { 00682 WARN("could not save profile file %s (error was %d)\n", debugstr_w(CurProfile->filename), GetLastError()); 00683 return FALSE; 00684 } 00685 00686 TRACE("Saving %s\n", debugstr_w(CurProfile->filename)); 00687 PROFILE_Save( hFile, CurProfile->section, CurProfile->encoding ); 00688 if(GetFileTime(hFile, NULL, NULL, &LastWriteTime)) 00689 CurProfile->LastWriteTime=LastWriteTime; 00690 CloseHandle( hFile ); 00691 CurProfile->changed = FALSE; 00692 return TRUE; 00693 } 00694 00695 00696 /*********************************************************************** 00697 * PROFILE_ReleaseFile 00698 * 00699 * Flush the current profile to disk and remove it from the cache. 00700 */ 00701 static void PROFILE_ReleaseFile(void) 00702 { 00703 PROFILE_FlushFile(); 00704 PROFILE_Free( CurProfile->section ); 00705 HeapFree( GetProcessHeap(), 0, CurProfile->filename ); 00706 CurProfile->changed = FALSE; 00707 CurProfile->section = NULL; 00708 CurProfile->filename = NULL; 00709 CurProfile->encoding = ENCODING_ANSI; 00710 ZeroMemory(&CurProfile->LastWriteTime, sizeof(CurProfile->LastWriteTime)); 00711 } 00712 00713 /*********************************************************************** 00714 * 00715 * Compares a file time with the current time. If the file time is 00716 * at least 2.1 seconds in the past, return true. 00717 * 00718 * Intended as cache safety measure: The time resolution on FAT is 00719 * two seconds, so files that are not at least two seconds old might 00720 * keep their time even on modification, so don't cache them. 00721 */ 00722 static BOOL is_not_current(FILETIME * ft) 00723 { 00724 FILETIME Now; 00725 LONGLONG ftll, nowll; 00726 GetSystemTimeAsFileTime(&Now); 00727 ftll = ((LONGLONG)ft->dwHighDateTime << 32) + ft->dwLowDateTime; 00728 nowll = ((LONGLONG)Now.dwHighDateTime << 32) + Now.dwLowDateTime; 00729 TRACE("%08x;%08x\n",(unsigned)ftll+21000000,(unsigned)nowll); 00730 return ftll + 21000000 < nowll; 00731 } 00732 00733 /*********************************************************************** 00734 * PROFILE_Open 00735 * 00736 * Open a profile file, checking the cached file first. 00737 */ 00738 static BOOL PROFILE_Open( LPCWSTR filename, BOOL write_access ) 00739 { 00740 WCHAR buffer[MAX_PATH]; 00741 HANDLE hFile = INVALID_HANDLE_VALUE; 00742 FILETIME LastWriteTime; 00743 int i,j; 00744 PROFILE *tempProfile; 00745 00746 ZeroMemory(&LastWriteTime, sizeof(LastWriteTime)); 00747 00748 /* First time around */ 00749 00750 if(!CurProfile) 00751 for(i=0;i<N_CACHED_PROFILES;i++) 00752 { 00753 MRUProfile[i]=HeapAlloc( GetProcessHeap(), 0, sizeof(PROFILE) ); 00754 if(MRUProfile[i] == NULL) break; 00755 MRUProfile[i]->changed=FALSE; 00756 MRUProfile[i]->section=NULL; 00757 MRUProfile[i]->filename=NULL; 00758 MRUProfile[i]->encoding=ENCODING_ANSI; 00759 ZeroMemory(&MRUProfile[i]->LastWriteTime, sizeof(FILETIME)); 00760 } 00761 00762 if (!filename) 00763 filename = wininiW; 00764 00765 if ((RtlDetermineDosPathNameType_U(filename) == RELATIVE_PATH) && 00766 !strchrW(filename, '\\') && !strchrW(filename, '/')) 00767 { 00768 static const WCHAR wszSeparator[] = {'\\', 0}; 00769 WCHAR windirW[MAX_PATH]; 00770 GetWindowsDirectoryW( windirW, MAX_PATH ); 00771 strcpyW(buffer, windirW); 00772 strcatW(buffer, wszSeparator); 00773 strcatW(buffer, filename); 00774 } 00775 else 00776 { 00777 LPWSTR dummy; 00778 GetFullPathNameW(filename, sizeof(buffer)/sizeof(buffer[0]), buffer, &dummy); 00779 } 00780 00781 TRACE("path: %s\n", debugstr_w(buffer)); 00782 00783 hFile = CreateFileW(buffer, GENERIC_READ | (write_access ? GENERIC_WRITE : 0), 00784 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, 00785 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 00786 00787 if ((hFile == INVALID_HANDLE_VALUE) && (GetLastError() != ERROR_FILE_NOT_FOUND)) 00788 { 00789 WARN("Error %d opening file %s\n", GetLastError(), debugstr_w(buffer)); 00790 return FALSE; 00791 } 00792 00793 for(i=0;i<N_CACHED_PROFILES;i++) 00794 { 00795 if ((MRUProfile[i]->filename && !strcmpiW( buffer, MRUProfile[i]->filename ))) 00796 { 00797 TRACE("MRU Filename: %s, new filename: %s\n", debugstr_w(MRUProfile[i]->filename), debugstr_w(buffer)); 00798 if(i) 00799 { 00800 PROFILE_FlushFile(); 00801 tempProfile=MRUProfile[i]; 00802 for(j=i;j>0;j--) 00803 MRUProfile[j]=MRUProfile[j-1]; 00804 CurProfile=tempProfile; 00805 } 00806 00807 if (hFile != INVALID_HANDLE_VALUE) 00808 { 00809 GetFileTime(hFile, NULL, NULL, &LastWriteTime); 00810 if (!memcmp( &CurProfile->LastWriteTime, &LastWriteTime, sizeof(FILETIME) ) && 00811 is_not_current(&LastWriteTime)) 00812 TRACE("(%s): already opened (mru=%d)\n", 00813 debugstr_w(buffer), i); 00814 else 00815 { 00816 TRACE("(%s): already opened, needs refreshing (mru=%d)\n", 00817 debugstr_w(buffer), i); 00818 PROFILE_Free(CurProfile->section); 00819 CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding); 00820 CurProfile->LastWriteTime = LastWriteTime; 00821 } 00822 CloseHandle(hFile); 00823 } 00824 else TRACE("(%s): already opened, not yet created (mru=%d)\n", 00825 debugstr_w(buffer), i); 00826 return TRUE; 00827 } 00828 } 00829 00830 /* Flush the old current profile */ 00831 PROFILE_FlushFile(); 00832 00833 /* Make the oldest profile the current one only in order to get rid of it */ 00834 if(i==N_CACHED_PROFILES) 00835 { 00836 tempProfile=MRUProfile[N_CACHED_PROFILES-1]; 00837 for(i=N_CACHED_PROFILES-1;i>0;i--) 00838 MRUProfile[i]=MRUProfile[i-1]; 00839 CurProfile=tempProfile; 00840 } 00841 if(CurProfile->filename) PROFILE_ReleaseFile(); 00842 00843 /* OK, now that CurProfile is definitely free we assign it our new file */ 00844 CurProfile->filename = HeapAlloc( GetProcessHeap(), 0, (strlenW(buffer)+1) * sizeof(WCHAR) ); 00845 strcpyW( CurProfile->filename, buffer ); 00846 00847 if (hFile != INVALID_HANDLE_VALUE) 00848 { 00849 CurProfile->section = PROFILE_Load(hFile, &CurProfile->encoding); 00850 GetFileTime(hFile, NULL, NULL, &CurProfile->LastWriteTime); 00851 CloseHandle(hFile); 00852 } 00853 else 00854 { 00855 /* Does not exist yet, we will create it in PROFILE_FlushFile */ 00856 WARN("profile file %s not found\n", debugstr_w(buffer) ); 00857 } 00858 return TRUE; 00859 } 00860 00861 00862 /*********************************************************************** 00863 * PROFILE_GetSection 00864 * 00865 * Returns all keys of a section. 00866 * If return_values is TRUE, also include the corresponding values. 00867 */ 00868 static INT PROFILE_GetSection( PROFILESECTION *section, LPCWSTR section_name, 00869 LPWSTR buffer, DWORD len, BOOL return_values ) 00870 { 00871 PROFILEKEY *key; 00872 00873 if(!buffer) return 0; 00874 00875 TRACE("%s,%p,%u\n", debugstr_w(section_name), buffer, len); 00876 00877 while (section) 00878 { 00879 if (section->name[0] && !strcmpiW( section->name, section_name )) 00880 { 00881 UINT oldlen = len; 00882 for (key = section->key; key; key = key->next) 00883 { 00884 if (len <= 2) break; 00885 if (!*key->name) continue; /* Skip empty lines */ 00886 if (IS_ENTRY_COMMENT(key->name)) continue; /* Skip comments */ 00887 if (!return_values && !key->value) continue; /* Skip lines w.o. '=' */ 00888 PROFILE_CopyEntry( buffer, key->name, len - 1, 0 ); 00889 len -= strlenW(buffer) + 1; 00890 buffer += strlenW(buffer) + 1; 00891 if (len < 2) 00892 break; 00893 if (return_values && key->value) { 00894 buffer[-1] = '='; 00895 PROFILE_CopyEntry ( buffer, key->value, len - 1, 0 ); 00896 len -= strlenW(buffer) + 1; 00897 buffer += strlenW(buffer) + 1; 00898 } 00899 } 00900 *buffer = '\0'; 00901 if (len <= 1) 00902 /*If either lpszSection or lpszKey is NULL and the supplied 00903 destination buffer is too small to hold all the strings, 00904 the last string is truncated and followed by two null characters. 00905 In this case, the return value is equal to cchReturnBuffer 00906 minus two. */ 00907 { 00908 buffer[-1] = '\0'; 00909 return oldlen - 2; 00910 } 00911 return oldlen - len; 00912 } 00913 section = section->next; 00914 } 00915 buffer[0] = buffer[1] = '\0'; 00916 return 0; 00917 } 00918 00919 /* See GetPrivateProfileSectionNamesA for documentation */ 00920 static INT PROFILE_GetSectionNames( LPWSTR buffer, DWORD len ) 00921 { 00922 LPWSTR buf; 00923 UINT buflen,tmplen; 00924 PROFILESECTION *section; 00925 00926 TRACE("(%p, %d)\n", buffer, len); 00927 00928 if (!buffer || !len) 00929 return 0; 00930 if (len==1) { 00931 *buffer='\0'; 00932 return 0; 00933 } 00934 00935 buflen=len-1; 00936 buf=buffer; 00937 section = CurProfile->section; 00938 while ((section!=NULL)) { 00939 if (section->name[0]) { 00940 tmplen = strlenW(section->name)+1; 00941 if (tmplen >= buflen) { 00942 if (buflen > 0) { 00943 memcpy(buf, section->name, (buflen-1) * sizeof(WCHAR)); 00944 buf += buflen-1; 00945 *buf++='\0'; 00946 } 00947 *buf='\0'; 00948 return len-2; 00949 } 00950 memcpy(buf, section->name, tmplen * sizeof(WCHAR)); 00951 buf += tmplen; 00952 buflen -= tmplen; 00953 } 00954 section = section->next; 00955 } 00956 *buf='\0'; 00957 return buf-buffer; 00958 } 00959 00960 00961 /*********************************************************************** 00962 * PROFILE_GetString 00963 * 00964 * Get a profile string. 00965 * 00966 * Tests with GetPrivateProfileString16, W95a, 00967 * with filled buffer ("****...") and section "set1" and key_name "1" valid: 00968 * section key_name def_val res buffer 00969 * "set1" "1" "x" 43 [data] 00970 * "set1" "1 " "x" 43 [data] (!) 00971 * "set1" " 1 "' "x" 43 [data] (!) 00972 * "set1" "" "x" 1 "x" 00973 * "set1" "" "x " 1 "x" (!) 00974 * "set1" "" " x " 3 " x" (!) 00975 * "set1" NULL "x" 6 "1\02\03\0\0" 00976 * "set1" "" "x" 1 "x" 00977 * NULL "1" "x" 0 "" (!) 00978 * "" "1" "x" 1 "x" 00979 * NULL NULL "" 0 "" 00980 * 00981 * 00982 */ 00983 static INT PROFILE_GetString( LPCWSTR section, LPCWSTR key_name, 00984 LPCWSTR def_val, LPWSTR buffer, DWORD len ) 00985 { 00986 PROFILEKEY *key = NULL; 00987 static const WCHAR empty_strW[] = { 0 }; 00988 00989 if(!buffer || !len) return 0; 00990 00991 if (!def_val) def_val = empty_strW; 00992 if (key_name) 00993 { 00994 if (!key_name[0]) 00995 { 00996 PROFILE_CopyEntry(buffer, def_val, len, TRUE); 00997 return strlenW(buffer); 00998 } 00999 key = PROFILE_Find( &CurProfile->section, section, key_name, FALSE, FALSE); 01000 PROFILE_CopyEntry( buffer, (key && key->value) ? key->value : def_val, 01001 len, TRUE ); 01002 TRACE("(%s,%s,%s): returning %s\n", 01003 debugstr_w(section), debugstr_w(key_name), 01004 debugstr_w(def_val), debugstr_w(buffer) ); 01005 return strlenW( buffer ); 01006 } 01007 /* no "else" here ! */ 01008 if (section && section[0]) 01009 { 01010 INT ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, FALSE); 01011 if (!buffer[0]) /* no luck -> def_val */ 01012 { 01013 PROFILE_CopyEntry(buffer, def_val, len, TRUE); 01014 ret = strlenW(buffer); 01015 } 01016 return ret; 01017 } 01018 buffer[0] = '\0'; 01019 return 0; 01020 } 01021 01022 01023 /*********************************************************************** 01024 * PROFILE_SetString 01025 * 01026 * Set a profile string. 01027 */ 01028 static BOOL PROFILE_SetString( LPCWSTR section_name, LPCWSTR key_name, 01029 LPCWSTR value, BOOL create_always ) 01030 { 01031 if (!key_name) /* Delete a whole section */ 01032 { 01033 TRACE("(%s)\n", debugstr_w(section_name)); 01034 CurProfile->changed |= PROFILE_DeleteSection( &CurProfile->section, 01035 section_name ); 01036 return TRUE; /* Even if PROFILE_DeleteSection() has failed, 01037 this is not an error on application's level.*/ 01038 } 01039 else if (!value) /* Delete a key */ 01040 { 01041 TRACE("(%s,%s)\n", debugstr_w(section_name), debugstr_w(key_name) ); 01042 CurProfile->changed |= PROFILE_DeleteKey( &CurProfile->section, 01043 section_name, key_name ); 01044 return TRUE; /* same error handling as above */ 01045 } 01046 else /* Set the key value */ 01047 { 01048 PROFILEKEY *key = PROFILE_Find(&CurProfile->section, section_name, 01049 key_name, TRUE, create_always ); 01050 TRACE("(%s,%s,%s):\n", 01051 debugstr_w(section_name), debugstr_w(key_name), debugstr_w(value) ); 01052 if (!key) return FALSE; 01053 01054 /* strip the leading spaces. We can safely strip \n\r and 01055 * friends too, they should not happen here anyway. */ 01056 while (PROFILE_isspaceW(*value)) value++; 01057 01058 if (key->value) 01059 { 01060 if (!strcmpW( key->value, value )) 01061 { 01062 TRACE(" no change needed\n" ); 01063 return TRUE; /* No change needed */ 01064 } 01065 TRACE(" replacing %s\n", debugstr_w(key->value) ); 01066 HeapFree( GetProcessHeap(), 0, key->value ); 01067 } 01068 else TRACE(" creating key\n" ); 01069 key->value = HeapAlloc( GetProcessHeap(), 0, (strlenW(value)+1) * sizeof(WCHAR) ); 01070 strcpyW( key->value, value ); 01071 CurProfile->changed = TRUE; 01072 } 01073 return TRUE; 01074 } 01075 01076 01077 /********************* API functions **********************************/ 01078 01079 01080 /*********************************************************************** 01081 * GetProfileIntA (KERNEL32.@) 01082 */ 01083 UINT WINAPI GetProfileIntA( LPCSTR section, LPCSTR entry, INT def_val ) 01084 { 01085 return GetPrivateProfileIntA( section, entry, def_val, "win.ini" ); 01086 } 01087 01088 /*********************************************************************** 01089 * GetProfileIntW (KERNEL32.@) 01090 */ 01091 UINT WINAPI GetProfileIntW( LPCWSTR section, LPCWSTR entry, INT def_val ) 01092 { 01093 return GetPrivateProfileIntW( section, entry, def_val, wininiW ); 01094 } 01095 01096 /*********************************************************************** 01097 * GetPrivateProfileStringW (KERNEL32.@) 01098 */ 01099 DWORD WINAPI GetPrivateProfileStringW( LPCWSTR section, LPCWSTR entry, 01100 LPCWSTR def_val, LPWSTR buffer, 01101 DWORD len, LPCWSTR filename ) 01102 { 01103 int ret; 01104 LPWSTR defval_tmp = NULL; 01105 01106 TRACE("%s,%s,%s,%p,%u,%s\n", debugstr_w(section), debugstr_w(entry), 01107 debugstr_w(def_val), buffer, len, debugstr_w(filename)); 01108 01109 /* strip any trailing ' ' of def_val. */ 01110 if (def_val) 01111 { 01112 LPCWSTR p = def_val + strlenW(def_val) - 1; 01113 01114 while (p > def_val && *p == ' ') 01115 p--; 01116 01117 if (p >= def_val) 01118 { 01119 int len = (int)(p - def_val) + 1; 01120 01121 defval_tmp = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR)); 01122 memcpy(defval_tmp, def_val, len * sizeof(WCHAR)); 01123 defval_tmp[len] = '\0'; 01124 def_val = defval_tmp; 01125 } 01126 } 01127 01128 RtlEnterCriticalSection( &PROFILE_CritSect ); 01129 01130 if (PROFILE_Open( filename, FALSE )) { 01131 if (section == NULL) 01132 ret = PROFILE_GetSectionNames(buffer, len); 01133 else 01134 /* PROFILE_GetString can handle the 'entry == NULL' case */ 01135 ret = PROFILE_GetString( section, entry, def_val, buffer, len ); 01136 } else if (buffer && def_val) { 01137 lstrcpynW( buffer, def_val, len ); 01138 ret = strlenW( buffer ); 01139 } 01140 else 01141 ret = 0; 01142 01143 RtlLeaveCriticalSection( &PROFILE_CritSect ); 01144 01145 HeapFree(GetProcessHeap(), 0, defval_tmp); 01146 01147 TRACE("returning %s, %d\n", debugstr_w(buffer), ret); 01148 01149 return ret; 01150 } 01151 01152 /*********************************************************************** 01153 * GetPrivateProfileStringA (KERNEL32.@) 01154 */ 01155 DWORD WINAPI GetPrivateProfileStringA( LPCSTR section, LPCSTR entry, 01156 LPCSTR def_val, LPSTR buffer, 01157 DWORD len, LPCSTR filename ) 01158 { 01159 UNICODE_STRING sectionW, entryW, def_valW, filenameW; 01160 LPWSTR bufferW; 01161 INT retW, ret = 0; 01162 01163 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)) : NULL; 01164 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); 01165 else sectionW.Buffer = NULL; 01166 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry); 01167 else entryW.Buffer = NULL; 01168 if (def_val) RtlCreateUnicodeStringFromAsciiz(&def_valW, def_val); 01169 else def_valW.Buffer = NULL; 01170 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01171 else filenameW.Buffer = NULL; 01172 01173 retW = GetPrivateProfileStringW( sectionW.Buffer, entryW.Buffer, 01174 def_valW.Buffer, bufferW, len, 01175 filenameW.Buffer); 01176 if (len && buffer) 01177 { 01178 if (retW) 01179 { 01180 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW, buffer, len - 1, NULL, NULL); 01181 if (!ret) 01182 ret = len - 1; 01183 } 01184 buffer[ret] = 0; 01185 } 01186 01187 RtlFreeUnicodeString(§ionW); 01188 RtlFreeUnicodeString(&entryW); 01189 RtlFreeUnicodeString(&def_valW); 01190 RtlFreeUnicodeString(&filenameW); 01191 HeapFree(GetProcessHeap(), 0, bufferW); 01192 return ret; 01193 } 01194 01195 /*********************************************************************** 01196 * GetProfileStringA (KERNEL32.@) 01197 */ 01198 DWORD WINAPI GetProfileStringA( LPCSTR section, LPCSTR entry, LPCSTR def_val, 01199 LPSTR buffer, DWORD len ) 01200 { 01201 return GetPrivateProfileStringA( section, entry, def_val, 01202 buffer, len, "win.ini" ); 01203 } 01204 01205 /*********************************************************************** 01206 * GetProfileStringW (KERNEL32.@) 01207 */ 01208 DWORD WINAPI GetProfileStringW( LPCWSTR section, LPCWSTR entry, 01209 LPCWSTR def_val, LPWSTR buffer, DWORD len ) 01210 { 01211 return GetPrivateProfileStringW( section, entry, def_val, 01212 buffer, len, wininiW ); 01213 } 01214 01215 /*********************************************************************** 01216 * WriteProfileStringA (KERNEL32.@) 01217 */ 01218 BOOL WINAPI WriteProfileStringA( LPCSTR section, LPCSTR entry, 01219 LPCSTR string ) 01220 { 01221 return WritePrivateProfileStringA( section, entry, string, "win.ini" ); 01222 } 01223 01224 /*********************************************************************** 01225 * WriteProfileStringW (KERNEL32.@) 01226 */ 01227 BOOL WINAPI WriteProfileStringW( LPCWSTR section, LPCWSTR entry, 01228 LPCWSTR string ) 01229 { 01230 return WritePrivateProfileStringW( section, entry, string, wininiW ); 01231 } 01232 01233 01234 /*********************************************************************** 01235 * GetPrivateProfileIntW (KERNEL32.@) 01236 */ 01237 UINT WINAPI GetPrivateProfileIntW( LPCWSTR section, LPCWSTR entry, 01238 INT def_val, LPCWSTR filename ) 01239 { 01240 WCHAR buffer[30]; 01241 UNICODE_STRING bufferW; 01242 INT len; 01243 ULONG result; 01244 01245 if (!(len = GetPrivateProfileStringW( section, entry, emptystringW, 01246 buffer, sizeof(buffer)/sizeof(WCHAR), 01247 filename ))) 01248 return def_val; 01249 01250 /* FIXME: if entry can be found but it's empty, then Win16 is 01251 * supposed to return 0 instead of def_val ! Difficult/problematic 01252 * to implement (every other failure also returns zero buffer), 01253 * thus wait until testing framework avail for making sure nothing 01254 * else gets broken that way. */ 01255 if (!buffer[0]) return (UINT)def_val; 01256 01257 RtlInitUnicodeString( &bufferW, buffer ); 01258 RtlUnicodeStringToInteger( &bufferW, 0, &result); 01259 return result; 01260 } 01261 01262 /*********************************************************************** 01263 * GetPrivateProfileIntA (KERNEL32.@) 01264 * 01265 * FIXME: rewrite using unicode 01266 */ 01267 UINT WINAPI GetPrivateProfileIntA( LPCSTR section, LPCSTR entry, 01268 INT def_val, LPCSTR filename ) 01269 { 01270 UNICODE_STRING entryW, filenameW, sectionW; 01271 UINT res; 01272 if(entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry); 01273 else entryW.Buffer = NULL; 01274 if(filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01275 else filenameW.Buffer = NULL; 01276 if(section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); 01277 else sectionW.Buffer = NULL; 01278 res = GetPrivateProfileIntW(sectionW.Buffer, entryW.Buffer, def_val, 01279 filenameW.Buffer); 01280 RtlFreeUnicodeString(§ionW); 01281 RtlFreeUnicodeString(&filenameW); 01282 RtlFreeUnicodeString(&entryW); 01283 return res; 01284 } 01285 01286 /*********************************************************************** 01287 * GetPrivateProfileSectionW (KERNEL32.@) 01288 */ 01289 DWORD WINAPI GetPrivateProfileSectionW( LPCWSTR section, LPWSTR buffer, 01290 DWORD len, LPCWSTR filename ) 01291 { 01292 int ret = 0; 01293 01294 if (!section || !buffer) 01295 { 01296 SetLastError(ERROR_INVALID_PARAMETER); 01297 return 0; 01298 } 01299 01300 TRACE("(%s, %p, %d, %s)\n", debugstr_w(section), buffer, len, debugstr_w(filename)); 01301 01302 RtlEnterCriticalSection( &PROFILE_CritSect ); 01303 01304 if (PROFILE_Open( filename, FALSE )) 01305 ret = PROFILE_GetSection(CurProfile->section, section, buffer, len, TRUE); 01306 01307 RtlLeaveCriticalSection( &PROFILE_CritSect ); 01308 01309 return ret; 01310 } 01311 01312 /*********************************************************************** 01313 * GetPrivateProfileSectionA (KERNEL32.@) 01314 */ 01315 DWORD WINAPI GetPrivateProfileSectionA( LPCSTR section, LPSTR buffer, 01316 DWORD len, LPCSTR filename ) 01317 { 01318 UNICODE_STRING sectionW, filenameW; 01319 LPWSTR bufferW; 01320 INT retW, ret = 0; 01321 01322 if (!section || !buffer) 01323 { 01324 SetLastError(ERROR_INVALID_PARAMETER); 01325 return 0; 01326 } 01327 01328 bufferW = HeapAlloc(GetProcessHeap(), 0, len * 2 * sizeof(WCHAR)); 01329 RtlCreateUnicodeStringFromAsciiz(§ionW, section); 01330 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01331 else filenameW.Buffer = NULL; 01332 01333 retW = GetPrivateProfileSectionW(sectionW.Buffer, bufferW, len * 2, filenameW.Buffer); 01334 if (retW) 01335 { 01336 if (retW == len * 2 - 2) retW++; /* overflow */ 01337 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW + 1, buffer, len, NULL, NULL); 01338 if (!ret || ret == len) /* overflow */ 01339 { 01340 ret = len - 2; 01341 buffer[len-2] = 0; 01342 buffer[len-1] = 0; 01343 } 01344 else ret--; 01345 } 01346 else 01347 { 01348 buffer[0] = 0; 01349 buffer[1] = 0; 01350 } 01351 01352 RtlFreeUnicodeString(§ionW); 01353 RtlFreeUnicodeString(&filenameW); 01354 HeapFree(GetProcessHeap(), 0, bufferW); 01355 return ret; 01356 } 01357 01358 /*********************************************************************** 01359 * GetProfileSectionA (KERNEL32.@) 01360 */ 01361 DWORD WINAPI GetProfileSectionA( LPCSTR section, LPSTR buffer, DWORD len ) 01362 { 01363 return GetPrivateProfileSectionA( section, buffer, len, "win.ini" ); 01364 } 01365 01366 /*********************************************************************** 01367 * GetProfileSectionW (KERNEL32.@) 01368 */ 01369 DWORD WINAPI GetProfileSectionW( LPCWSTR section, LPWSTR buffer, DWORD len ) 01370 { 01371 return GetPrivateProfileSectionW( section, buffer, len, wininiW ); 01372 } 01373 01374 01375 /*********************************************************************** 01376 * WritePrivateProfileStringW (KERNEL32.@) 01377 */ 01378 BOOL WINAPI WritePrivateProfileStringW( LPCWSTR section, LPCWSTR entry, 01379 LPCWSTR string, LPCWSTR filename ) 01380 { 01381 BOOL ret = FALSE; 01382 01383 RtlEnterCriticalSection( &PROFILE_CritSect ); 01384 01385 if (!section && !entry && !string) /* documented "file flush" case */ 01386 { 01387 if (!filename || PROFILE_Open( filename, TRUE )) 01388 { 01389 if (CurProfile) PROFILE_ReleaseFile(); /* always return FALSE in this case */ 01390 } 01391 } 01392 else if (PROFILE_Open( filename, TRUE )) 01393 { 01394 if (!section) { 01395 SetLastError(ERROR_FILE_NOT_FOUND); 01396 } else { 01397 ret = PROFILE_SetString( section, entry, string, FALSE); 01398 PROFILE_FlushFile(); 01399 } 01400 } 01401 01402 RtlLeaveCriticalSection( &PROFILE_CritSect ); 01403 return ret; 01404 } 01405 01406 /*********************************************************************** 01407 * WritePrivateProfileStringA (KERNEL32.@) 01408 */ 01409 BOOL WINAPI WritePrivateProfileStringA( LPCSTR section, LPCSTR entry, 01410 LPCSTR string, LPCSTR filename ) 01411 { 01412 UNICODE_STRING sectionW, entryW, stringW, filenameW; 01413 BOOL ret; 01414 01415 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); 01416 else sectionW.Buffer = NULL; 01417 if (entry) RtlCreateUnicodeStringFromAsciiz(&entryW, entry); 01418 else entryW.Buffer = NULL; 01419 if (string) RtlCreateUnicodeStringFromAsciiz(&stringW, string); 01420 else stringW.Buffer = NULL; 01421 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01422 else filenameW.Buffer = NULL; 01423 01424 ret = WritePrivateProfileStringW(sectionW.Buffer, entryW.Buffer, 01425 stringW.Buffer, filenameW.Buffer); 01426 RtlFreeUnicodeString(§ionW); 01427 RtlFreeUnicodeString(&entryW); 01428 RtlFreeUnicodeString(&stringW); 01429 RtlFreeUnicodeString(&filenameW); 01430 return ret; 01431 } 01432 01433 /*********************************************************************** 01434 * WritePrivateProfileSectionW (KERNEL32.@) 01435 */ 01436 BOOL WINAPI WritePrivateProfileSectionW( LPCWSTR section, 01437 LPCWSTR string, LPCWSTR filename ) 01438 { 01439 BOOL ret = FALSE; 01440 LPWSTR p; 01441 01442 RtlEnterCriticalSection( &PROFILE_CritSect ); 01443 01444 if (!section && !string) 01445 { 01446 if (!filename || PROFILE_Open( filename, TRUE )) 01447 { 01448 if (CurProfile) PROFILE_ReleaseFile(); /* always return FALSE in this case */ 01449 } 01450 } 01451 else if (PROFILE_Open( filename, TRUE )) { 01452 if (!string) {/* delete the named section*/ 01453 ret = PROFILE_SetString(section,NULL,NULL, FALSE); 01454 PROFILE_FlushFile(); 01455 } else { 01456 PROFILE_DeleteAllKeys(section); 01457 ret = TRUE; 01458 while(*string) { 01459 LPWSTR buf = HeapAlloc( GetProcessHeap(), 0, (strlenW(string)+1) * sizeof(WCHAR) ); 01460 strcpyW( buf, string ); 01461 if((p = strchrW( buf, '='))) { 01462 *p='\0'; 01463 ret = PROFILE_SetString( section, buf, p+1, TRUE); 01464 } 01465 HeapFree( GetProcessHeap(), 0, buf ); 01466 string += strlenW(string)+1; 01467 } 01468 PROFILE_FlushFile(); 01469 } 01470 } 01471 01472 RtlLeaveCriticalSection( &PROFILE_CritSect ); 01473 return ret; 01474 } 01475 01476 /*********************************************************************** 01477 * WritePrivateProfileSectionA (KERNEL32.@) 01478 */ 01479 BOOL WINAPI WritePrivateProfileSectionA( LPCSTR section, 01480 LPCSTR string, LPCSTR filename) 01481 01482 { 01483 UNICODE_STRING sectionW, filenameW; 01484 LPWSTR stringW; 01485 BOOL ret; 01486 01487 if (string) 01488 { 01489 INT lenA, lenW; 01490 LPCSTR p = string; 01491 01492 while(*p) p += strlen(p) + 1; 01493 lenA = p - string + 1; 01494 lenW = MultiByteToWideChar(CP_ACP, 0, string, lenA, NULL, 0); 01495 if ((stringW = HeapAlloc(GetProcessHeap(), 0, lenW * sizeof(WCHAR)))) 01496 MultiByteToWideChar(CP_ACP, 0, string, lenA, stringW, lenW); 01497 } 01498 else stringW = NULL; 01499 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); 01500 else sectionW.Buffer = NULL; 01501 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01502 else filenameW.Buffer = NULL; 01503 01504 ret = WritePrivateProfileSectionW(sectionW.Buffer, stringW, filenameW.Buffer); 01505 01506 HeapFree(GetProcessHeap(), 0, stringW); 01507 RtlFreeUnicodeString(§ionW); 01508 RtlFreeUnicodeString(&filenameW); 01509 return ret; 01510 } 01511 01512 /*********************************************************************** 01513 * WriteProfileSectionA (KERNEL32.@) 01514 */ 01515 BOOL WINAPI WriteProfileSectionA( LPCSTR section, LPCSTR keys_n_values) 01516 01517 { 01518 return WritePrivateProfileSectionA( section, keys_n_values, "win.ini"); 01519 } 01520 01521 /*********************************************************************** 01522 * WriteProfileSectionW (KERNEL32.@) 01523 */ 01524 BOOL WINAPI WriteProfileSectionW( LPCWSTR section, LPCWSTR keys_n_values) 01525 { 01526 return WritePrivateProfileSectionW(section, keys_n_values, wininiW); 01527 } 01528 01529 01530 /*********************************************************************** 01531 * GetPrivateProfileSectionNamesW (KERNEL32.@) 01532 * 01533 * Returns the section names contained in the specified file. 01534 * FIXME: Where do we find this file when the path is relative? 01535 * The section names are returned as a list of strings with an extra 01536 * '\0' to mark the end of the list. Except for that the behavior 01537 * depends on the Windows version. 01538 * 01539 * Win95: 01540 * - if the buffer is 0 or 1 character long then it is as if it was of 01541 * infinite length. 01542 * - otherwise, if the buffer is too small only the section names that fit 01543 * are returned. 01544 * - note that this means if the buffer was too small to return even just 01545 * the first section name then a single '\0' will be returned. 01546 * - the return value is the number of characters written in the buffer, 01547 * except if the buffer was too small in which case len-2 is returned 01548 * 01549 * Win2000: 01550 * - if the buffer is 0, 1 or 2 characters long then it is filled with 01551 * '\0' and the return value is 0 01552 * - otherwise if the buffer is too small then the first section name that 01553 * does not fit is truncated so that the string list can be terminated 01554 * correctly (double '\0') 01555 * - the return value is the number of characters written in the buffer 01556 * except for the trailing '\0'. If the buffer is too small, then the 01557 * return value is len-2 01558 * - Win2000 has a bug that triggers when the section names and the 01559 * trailing '\0' fit exactly in the buffer. In that case the trailing 01560 * '\0' is missing. 01561 * 01562 * Wine implements the observed Win2000 behavior (except for the bug). 01563 * 01564 * Note that when the buffer is big enough then the return value may be any 01565 * value between 1 and len-1 (or len in Win95), including len-2. 01566 */ 01567 DWORD WINAPI GetPrivateProfileSectionNamesW( LPWSTR buffer, DWORD size, 01568 LPCWSTR filename) 01569 { 01570 DWORD ret = 0; 01571 01572 RtlEnterCriticalSection( &PROFILE_CritSect ); 01573 01574 if (PROFILE_Open( filename, FALSE )) 01575 ret = PROFILE_GetSectionNames(buffer, size); 01576 01577 RtlLeaveCriticalSection( &PROFILE_CritSect ); 01578 01579 return ret; 01580 } 01581 01582 01583 /*********************************************************************** 01584 * GetPrivateProfileSectionNamesA (KERNEL32.@) 01585 */ 01586 DWORD WINAPI GetPrivateProfileSectionNamesA( LPSTR buffer, DWORD size, 01587 LPCSTR filename) 01588 { 01589 UNICODE_STRING filenameW; 01590 LPWSTR bufferW; 01591 INT retW, ret = 0; 01592 01593 bufferW = buffer ? HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)) : NULL; 01594 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01595 else filenameW.Buffer = NULL; 01596 01597 retW = GetPrivateProfileSectionNamesW(bufferW, size, filenameW.Buffer); 01598 if (retW && size) 01599 { 01600 ret = WideCharToMultiByte(CP_ACP, 0, bufferW, retW+1, buffer, size-1, NULL, NULL); 01601 if (!ret) 01602 { 01603 ret = size-2; 01604 buffer[size-1] = 0; 01605 } 01606 else 01607 ret = ret-1; 01608 } 01609 else if(size) 01610 buffer[0] = '\0'; 01611 01612 RtlFreeUnicodeString(&filenameW); 01613 HeapFree(GetProcessHeap(), 0, bufferW); 01614 return ret; 01615 } 01616 01617 /*********************************************************************** 01618 * GetPrivateProfileStructW (KERNEL32.@) 01619 * 01620 * Should match Win95's behaviour pretty much 01621 */ 01622 BOOL WINAPI GetPrivateProfileStructW (LPCWSTR section, LPCWSTR key, 01623 LPVOID buf, UINT len, LPCWSTR filename) 01624 { 01625 BOOL ret = FALSE; 01626 01627 RtlEnterCriticalSection( &PROFILE_CritSect ); 01628 01629 if (PROFILE_Open( filename, FALSE )) { 01630 PROFILEKEY *k = PROFILE_Find ( &CurProfile->section, section, key, FALSE, FALSE); 01631 if (k) { 01632 TRACE("value (at %p): %s\n", k->value, debugstr_w(k->value)); 01633 if (((strlenW(k->value) - 2) / 2) == len) 01634 { 01635 LPWSTR end, p; 01636 BOOL valid = TRUE; 01637 WCHAR c; 01638 DWORD chksum = 0; 01639 01640 end = k->value + strlenW(k->value); /* -> '\0' */ 01641 /* check for invalid chars in ASCII coded hex string */ 01642 for (p=k->value; p < end; p++) 01643 { 01644 if (!isxdigitW(*p)) 01645 { 01646 WARN("invalid char '%x' in file %s->[%s]->%s !\n", 01647 *p, debugstr_w(filename), debugstr_w(section), debugstr_w(key)); 01648 valid = FALSE; 01649 break; 01650 } 01651 } 01652 if (valid) 01653 { 01654 BOOL highnibble = TRUE; 01655 BYTE b = 0, val; 01656 LPBYTE binbuf = buf; 01657 01658 end -= 2; /* don't include checksum in output data */ 01659 /* translate ASCII hex format into binary data */ 01660 for (p=k->value; p < end; p++) 01661 { 01662 c = toupperW(*p); 01663 val = (c > '9') ? 01664 (c - 'A' + 10) : (c - '0'); 01665 01666 if (highnibble) 01667 b = val << 4; 01668 else 01669 { 01670 b += val; 01671 *binbuf++ = b; /* feed binary data into output */ 01672 chksum += b; /* calculate checksum */ 01673 } 01674 highnibble ^= 1; /* toggle */ 01675 } 01676 /* retrieve stored checksum value */ 01677 c = toupperW(*p++); 01678 b = ( (c > '9') ? (c - 'A' + 10) : (c - '0') ) << 4; 01679 c = toupperW(*p); 01680 b += (c > '9') ? (c - 'A' + 10) : (c - '0'); 01681 if (b == (chksum & 0xff)) /* checksums match ? */ 01682 ret = TRUE; 01683 } 01684 } 01685 } 01686 } 01687 RtlLeaveCriticalSection( &PROFILE_CritSect ); 01688 01689 return ret; 01690 } 01691 01692 /*********************************************************************** 01693 * GetPrivateProfileStructA (KERNEL32.@) 01694 */ 01695 BOOL WINAPI GetPrivateProfileStructA (LPCSTR section, LPCSTR key, 01696 LPVOID buffer, UINT len, LPCSTR filename) 01697 { 01698 UNICODE_STRING sectionW, keyW, filenameW; 01699 INT ret; 01700 01701 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); 01702 else sectionW.Buffer = NULL; 01703 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key); 01704 else keyW.Buffer = NULL; 01705 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01706 else filenameW.Buffer = NULL; 01707 01708 ret = GetPrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buffer, len, 01709 filenameW.Buffer); 01710 /* Do not translate binary data. */ 01711 01712 RtlFreeUnicodeString(§ionW); 01713 RtlFreeUnicodeString(&keyW); 01714 RtlFreeUnicodeString(&filenameW); 01715 return ret; 01716 } 01717 01718 01719 01720 /*********************************************************************** 01721 * WritePrivateProfileStructW (KERNEL32.@) 01722 */ 01723 BOOL WINAPI WritePrivateProfileStructW (LPCWSTR section, LPCWSTR key, 01724 LPVOID buf, UINT bufsize, LPCWSTR filename) 01725 { 01726 BOOL ret = FALSE; 01727 LPBYTE binbuf; 01728 LPWSTR outstring, p; 01729 DWORD sum = 0; 01730 01731 if (!section && !key && !buf) /* flush the cache */ 01732 return WritePrivateProfileStringW( NULL, NULL, NULL, filename ); 01733 01734 /* allocate string buffer for hex chars + checksum hex char + '\0' */ 01735 outstring = HeapAlloc( GetProcessHeap(), 0, (bufsize*2 + 2 + 1) * sizeof(WCHAR) ); 01736 p = outstring; 01737 for (binbuf = (LPBYTE)buf; binbuf < (LPBYTE)buf+bufsize; binbuf++) { 01738 *p++ = hex[*binbuf >> 4]; 01739 *p++ = hex[*binbuf & 0xf]; 01740 sum += *binbuf; 01741 } 01742 /* checksum is sum & 0xff */ 01743 *p++ = hex[(sum & 0xf0) >> 4]; 01744 *p++ = hex[sum & 0xf]; 01745 *p++ = '\0'; 01746 01747 RtlEnterCriticalSection( &PROFILE_CritSect ); 01748 01749 if (PROFILE_Open( filename, TRUE )) { 01750 ret = PROFILE_SetString( section, key, outstring, FALSE); 01751 PROFILE_FlushFile(); 01752 } 01753 01754 RtlLeaveCriticalSection( &PROFILE_CritSect ); 01755 01756 HeapFree( GetProcessHeap(), 0, outstring ); 01757 01758 return ret; 01759 } 01760 01761 /*********************************************************************** 01762 * WritePrivateProfileStructA (KERNEL32.@) 01763 */ 01764 BOOL WINAPI WritePrivateProfileStructA (LPCSTR section, LPCSTR key, 01765 LPVOID buf, UINT bufsize, LPCSTR filename) 01766 { 01767 UNICODE_STRING sectionW, keyW, filenameW; 01768 INT ret; 01769 01770 if (section) RtlCreateUnicodeStringFromAsciiz(§ionW, section); 01771 else sectionW.Buffer = NULL; 01772 if (key) RtlCreateUnicodeStringFromAsciiz(&keyW, key); 01773 else keyW.Buffer = NULL; 01774 if (filename) RtlCreateUnicodeStringFromAsciiz(&filenameW, filename); 01775 else filenameW.Buffer = NULL; 01776 01777 /* Do not translate binary data. */ 01778 ret = WritePrivateProfileStructW(sectionW.Buffer, keyW.Buffer, buf, bufsize, 01779 filenameW.Buffer); 01780 01781 RtlFreeUnicodeString(§ionW); 01782 RtlFreeUnicodeString(&keyW); 01783 RtlFreeUnicodeString(&filenameW); 01784 return ret; 01785 } 01786 01787 01788 /*********************************************************************** 01789 * OpenProfileUserMapping (KERNEL32.@) 01790 */ 01791 BOOL WINAPI OpenProfileUserMapping(void) { 01792 FIXME("(), stub!\n"); 01793 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 01794 return FALSE; 01795 } 01796 01797 /*********************************************************************** 01798 * CloseProfileUserMapping (KERNEL32.@) 01799 */ 01800 BOOL WINAPI CloseProfileUserMapping(void) { 01801 FIXME("(), stub!\n"); 01802 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 01803 return FALSE; 01804 } Generated on Sun May 27 2012 04:23:53 for ReactOS by
1.7.6.1
|