📄 profile.c
字号:
/*
* Profile functions
*
* Copyright 1993 Miguel de Icaza
* Copyright 1996 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <k32.h>
#define NDEBUG
#include "../include/debug.h"
static const char bom_utf8[] = {0xEF,0xBB,0xBF};
typedef enum
{
ENCODING_ANSI = 1,
ENCODING_UTF8,
ENCODING_UTF16LE,
ENCODING_UTF16BE
} ENCODING;
typedef struct tagPROFILEKEY
{
WCHAR *value;
struct tagPROFILEKEY *next;
WCHAR name[1];
} PROFILEKEY;
typedef struct tagPROFILESECTION
{
struct tagPROFILEKEY *key;
struct tagPROFILESECTION *next;
WCHAR name[1];
} PROFILESECTION;
typedef struct
{
BOOL changed;
PROFILESECTION *section;
WCHAR *filename;
FILETIME LastWriteTime;
ENCODING encoding;
} PROFILE;
#define N_CACHED_PROFILES 10
/* Cached profile files */
static PROFILE *MRUProfile[N_CACHED_PROFILES]={NULL};
#define CurProfile (MRUProfile[0])
/* Check for comments in profile */
#define IS_ENTRY_COMMENT(str) ((str)[0] == ';')
static const WCHAR emptystringW[] = {0};
static RTL_CRITICAL_SECTION PROFILE_CritSect;
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &PROFILE_CritSect,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, 0, 0
};
static RTL_CRITICAL_SECTION PROFILE_CritSect = { &critsect_debug, -1, 0, 0, 0, 0 };
static const char hex[16] = "0123456789ABCDEF";
static __inline WCHAR *memchrW( const WCHAR *ptr, WCHAR ch, size_t n )
{
const WCHAR *end;
for (end = ptr + n; ptr < end; ptr++)
if (*ptr == ch)
return (WCHAR *)ptr;
return NULL;
}
static __inline WCHAR *memrchrW( const WCHAR *ptr, WCHAR ch, size_t n )
{
const WCHAR *end, *ret = NULL;
for (end = ptr + n; ptr < end; ptr++)
if (*ptr == ch)
ret = ptr;
return (WCHAR *)ret;
}
/***********************************************************************
* PROFILE_CopyEntry
*
* Copy the content of an entry into a buffer, removing quotes, and possibly
* translating environment variables.
*/
static void PROFILE_CopyEntry( LPWSTR buffer, LPCWSTR value, int len,
BOOL strip_quote )
{
WCHAR quote = '\0';
if (!buffer) return;
if (strip_quote && ((*value == '\'') || (*value == '\"')))
{
if (value[1] && (value[wcslen(value)-1] == *value))
quote = *value++;
}
lstrcpynW( buffer, value, len );
if (quote && (len >= (int)wcslen(value))) buffer[wcslen(buffer)-1] = '\0';
}
/* byte-swaps shorts in-place in a buffer. len is in WCHARs */
static __inline void PROFILE_ByteSwapShortBuffer(WCHAR * buffer, int len)
{
int i;
USHORT * shortbuffer = (USHORT *)buffer;
for (i = 0; i < len; i++)
shortbuffer[i] = RtlUshortByteSwap(shortbuffer[i]);
}
/* writes any necessary encoding marker to the file */
static __inline void PROFILE_WriteMarker(HANDLE hFile, ENCODING encoding)
{
DWORD dwBytesWritten;
DWORD bom;
switch (encoding)
{
case ENCODING_ANSI:
break;
case ENCODING_UTF8:
WriteFile(hFile, bom_utf8, sizeof(bom_utf8), &dwBytesWritten, NULL);
break;
case ENCODING_UTF16LE:
bom = 0xFEFF;
WriteFile(hFile, &bom, sizeof(bom), &dwBytesWritten, NULL);
break;
case ENCODING_UTF16BE:
bom = 0xFFFE;
WriteFile(hFile, &bom, sizeof(bom), &dwBytesWritten, NULL);
break;
}
}
static void PROFILE_WriteLine( HANDLE hFile, WCHAR * szLine, int len, ENCODING encoding)
{
char * write_buffer;
int write_buffer_len;
DWORD dwBytesWritten;
DPRINT("writing: %.*S\n", len, szLine);
switch (encoding)
{
case ENCODING_ANSI:
write_buffer_len = WideCharToMultiByte(CP_ACP, 0, szLine, len, NULL, 0, NULL, NULL);
write_buffer = HeapAlloc(GetProcessHeap(), 0, write_buffer_len);
if (!write_buffer) return;
len = WideCharToMultiByte(CP_ACP, 0, szLine, len, write_buffer, write_buffer_len, NULL, NULL);
WriteFile(hFile, write_buffer, len, &dwBytesWritten, NULL);
HeapFree(GetProcessHeap(), 0, write_buffer);
break;
case ENCODING_UTF8:
write_buffer_len = WideCharToMultiByte(CP_UTF8, 0, szLine, len, NULL, 0, NULL, NULL);
write_buffer = HeapAlloc(GetProcessHeap(), 0, write_buffer_len);
if (!write_buffer) return;
len = WideCharToMultiByte(CP_UTF8, 0, szLine, len, write_buffer, write_buffer_len, NULL, NULL);
WriteFile(hFile, write_buffer, len, &dwBytesWritten, NULL);
HeapFree(GetProcessHeap(), 0, write_buffer);
break;
case ENCODING_UTF16LE:
WriteFile(hFile, szLine, len * sizeof(WCHAR), &dwBytesWritten, NULL);
break;
case ENCODING_UTF16BE:
PROFILE_ByteSwapShortBuffer(szLine, len);
WriteFile(hFile, szLine, len * sizeof(WCHAR), &dwBytesWritten, NULL);
break;
default:
DPRINT1("encoding type %d not implemented\n", encoding);
}
}
/***********************************************************************
* PROFILE_Save
*
* Save a profile tree to a file.
*/
static void PROFILE_Save( HANDLE hFile, const PROFILESECTION *section, ENCODING encoding )
{
PROFILEKEY *key;
WCHAR *buffer, *p;
PROFILE_WriteMarker(hFile, encoding);
for ( ; section; section = section->next)
{
int len = 0;
if (section->name[0]) len += wcslen(section->name) + 6;
for (key = section->key; key; key = key->next)
{
len += wcslen(key->name) + 2;
if (key->value) len += wcslen(key->value) + 1;
}
buffer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!buffer) return;
p = buffer;
if (section->name[0])
{
*p++ = '\r';
*p++ = '\n';
*p++ = '[';
wcscpy( p, section->name );
p += wcslen(p);
*p++ = ']';
*p++ = '\r';
*p++ = '\n';
}
for (key = section->key; key; key = key->next)
{
wcscpy( p, key->name );
p += wcslen(p);
if (key->value)
{
*p++ = '=';
wcscpy( p, key->value );
p += wcslen(p);
}
*p++ = '\r';
*p++ = '\n';
}
PROFILE_WriteLine( hFile, buffer, len, encoding );
HeapFree(GetProcessHeap(), 0, buffer);
}
}
/***********************************************************************
* PROFILE_Free
*
* Free a profile tree.
*/
static void PROFILE_Free( PROFILESECTION *section )
{
PROFILESECTION *next_section;
PROFILEKEY *key, *next_key;
for ( ; section; section = next_section)
{
for (key = section->key; key; key = next_key)
{
next_key = key->next;
HeapFree( GetProcessHeap(), 0, key->value );
HeapFree( GetProcessHeap(), 0, key );
}
next_section = section->next;
HeapFree( GetProcessHeap(), 0, section );
}
}
/* returns 1 if a character white space else 0 */
static __inline int PROFILE_isspaceW(WCHAR c)
{
if (iswspace(c))
return 1;
if (c=='\r' || c==0x1a)
return 1;
/* CR and ^Z (DOS EOF) are spaces too (found on CD-ROMs) */
return 0;
}
static __inline ENCODING PROFILE_DetectTextEncoding(const void * buffer, int * len)
{
DWORD flags = IS_TEXT_UNICODE_SIGNATURE |
IS_TEXT_UNICODE_REVERSE_SIGNATURE |
IS_TEXT_UNICODE_ODD_LENGTH;
if (*len >= (int)sizeof(bom_utf8) && !memcmp(buffer, bom_utf8, sizeof(bom_utf8)))
{
*len = sizeof(bom_utf8);
return ENCODING_UTF8;
}
RtlIsTextUnicode((void *)buffer, *len, &flags);
if (flags & IS_TEXT_UNICODE_SIGNATURE)
{
*len = sizeof(WCHAR);
return ENCODING_UTF16LE;
}
if (flags & IS_TEXT_UNICODE_REVERSE_SIGNATURE)
{
*len = sizeof(WCHAR);
return ENCODING_UTF16BE;
}
*len = 0;
return ENCODING_ANSI;
}
/***********************************************************************
* PROFILE_Load
*
* Load a profile tree from a file.
*/
static PROFILESECTION *PROFILE_Load(HANDLE hFile, ENCODING * pEncoding)
{
void *pBuffer;
WCHAR * szFile;
const WCHAR *szLineStart, *szLineEnd;
const WCHAR *szValueStart, *szEnd, *next_line;
int line = 0, len;
PROFILESECTION *section, *first_section;
PROFILESECTION **next_section;
PROFILEKEY *key, *prev_key, **next_key;
DWORD dwFileSize;
DPRINT("%p\n", hFile);
dwFileSize = GetFileSize(hFile, NULL);
if (dwFileSize == INVALID_FILE_SIZE)
return NULL;
pBuffer = HeapAlloc(GetProcessHeap(), 0 , dwFileSize);
if (!pBuffer)
return NULL;
if (!ReadFile(hFile, pBuffer, dwFileSize, &dwFileSize, NULL))
{
HeapFree(GetProcessHeap(), 0, pBuffer);
DPRINT("Error %ld reading file\n", GetLastError());
return NULL;
}
len = dwFileSize;
*pEncoding = PROFILE_DetectTextEncoding(pBuffer, &len);
/* len is set to the number of bytes in the character marker.
* we want to skip these bytes */
pBuffer = (char *)pBuffer + len;
dwFileSize -= len;
switch (*pEncoding)
{
case ENCODING_ANSI:
DPRINT("ANSI encoding\n");
len = MultiByteToWideChar(CP_ACP, 0, (char *)pBuffer, dwFileSize, NULL, 0);
szFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!szFile)
{
HeapFree(GetProcessHeap(), 0, pBuffer);
return NULL;
}
MultiByteToWideChar(CP_ACP, 0, (char *)pBuffer, dwFileSize, szFile, len);
szEnd = szFile + len;
break;
case ENCODING_UTF8:
DPRINT("UTF8 encoding\n");
len = MultiByteToWideChar(CP_UTF8, 0, (char *)pBuffer, dwFileSize, NULL, 0);
szFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
if (!szFile)
{
HeapFree(GetProcessHeap(), 0, pBuffer);
return NULL;
}
MultiByteToWideChar(CP_UTF8, 0, (char *)pBuffer, dwFileSize, szFile, len);
szEnd = szFile + len;
break;
case ENCODING_UTF16LE:
DPRINT("UTF16 Little Endian encoding\n");
szFile = (WCHAR *)pBuffer + 1;
szEnd = (WCHAR *)((char *)pBuffer + dwFileSize);
break;
case ENCODING_UTF16BE:
DPRINT("UTF16 Big Endian encoding\n");
szFile = (WCHAR *)pBuffer + 1;
szEnd = (WCHAR *)((char *)pBuffer + dwFileSize);
PROFILE_ByteSwapShortBuffer(szFile, dwFileSize / sizeof(WCHAR));
break;
default:
DPRINT("encoding type %d not implemented\n", *pEncoding);
HeapFree(GetProcessHeap(), 0, pBuffer);
return NULL;
}
first_section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) );
if (first_section == NULL)
{
if (szFile != pBuffer)
HeapFree(GetProcessHeap(), 0, szFile);
HeapFree(GetProcessHeap(), 0, pBuffer);
return NULL;
}
first_section->name[0] = 0;
first_section->key = NULL;
first_section->next = NULL;
next_section = &first_section->next;
next_key = &first_section->key;
prev_key = NULL;
next_line = szFile;
while (next_line < szEnd)
{
szLineStart = next_line;
next_line = memchrW(szLineStart, '\n', szEnd - szLineStart);
if (!next_line) next_line = szEnd;
else next_line++;
szLineEnd = next_line;
line++;
/* get rid of white space */
while (szLineStart < szLineEnd && PROFILE_isspaceW(*szLineStart)) szLineStart++;
while ((szLineEnd > szLineStart) && ((szLineEnd[-1] == '\n') || PROFILE_isspaceW(szLineEnd[-1]))) szLineEnd--;
if (szLineStart >= szLineEnd)
continue;
if (*szLineStart == '[') /* section start */
{
const WCHAR * szSectionEnd;
if (!(szSectionEnd = memrchrW( szLineStart, ']', szLineEnd - szLineStart )))
{
DPRINT("Invalid section header at line %d: %.*S\n",
line, (int)(szLineEnd - szLineStart), szLineStart);
}
else
{
szLineStart++;
len = (int)(szSectionEnd - szLineStart);
/* no need to allocate +1 for NULL terminating character as
* already included in structure */
if (!(section = HeapAlloc( GetProcessHeap(), 0, sizeof(*section) + len * sizeof(WCHAR) )))
break;
memcpy(section->name, szLineStart, len * sizeof(WCHAR));
section->name[len] = '\0';
section->key = NULL;
section->next = NULL;
*next_section = section;
next_section = §ion->next;
next_key = §ion->key;
prev_key = NULL;
DPRINT("New section: %S\n", section->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -