| /* |
| * Setupapi string table functions |
| * |
| * Copyright 2005 Eric Kohl |
| * |
| * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include "config.h" |
| #include "wine/port.h" |
| |
| #include <stdarg.h> |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "winreg.h" |
| #include "setupapi.h" |
| |
| #include "wine/debug.h" |
| |
| |
| #define TABLE_DEFAULT_SIZE 256 |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(setupapi); |
| |
| typedef struct _TABLE_SLOT |
| { |
| LPWSTR pString; |
| LPVOID pData; |
| DWORD dwSize; |
| } TABLE_SLOT, *PTABLE_SLOT; |
| |
| typedef struct _STRING_TABLE |
| { |
| PTABLE_SLOT pSlots; |
| DWORD dwUsedSlots; |
| DWORD dwMaxSlots; |
| DWORD dwMaxDataSize; |
| } STRING_TABLE, *PSTRING_TABLE; |
| |
| |
| /************************************************************************** |
| * StringTableInitialize [SETUPAPI.@] |
| * |
| * Creates a new string table and initializes it. |
| * |
| * PARAMS |
| * None |
| * |
| * RETURNS |
| * Success: Handle to the string table |
| * Failure: NULL |
| */ |
| HSTRING_TABLE WINAPI |
| StringTableInitialize(VOID) |
| { |
| PSTRING_TABLE pStringTable; |
| |
| TRACE("\n"); |
| |
| pStringTable = MyMalloc(sizeof(STRING_TABLE)); |
| if (pStringTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| return NULL; |
| } |
| |
| memset(pStringTable, 0, sizeof(STRING_TABLE)); |
| |
| pStringTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE); |
| if (pStringTable->pSlots == NULL) |
| { |
| MyFree(pStringTable->pSlots); |
| return NULL; |
| } |
| |
| memset(pStringTable->pSlots, 0, sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE); |
| |
| pStringTable->dwUsedSlots = 0; |
| pStringTable->dwMaxSlots = TABLE_DEFAULT_SIZE; |
| pStringTable->dwMaxDataSize = 0; |
| |
| TRACE("Done\n"); |
| |
| return (HSTRING_TABLE)pStringTable; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableInitializeEx [SETUPAPI.@] |
| * |
| * Creates a new string table and initializes it. |
| * |
| * PARAMS |
| * dwMaxExtraDataSize [I] Maximum extra data size |
| * dwReserved [I] Unused |
| * |
| * RETURNS |
| * Success: Handle to the string table |
| * Failure: NULL |
| */ |
| HSTRING_TABLE WINAPI |
| StringTableInitializeEx(DWORD dwMaxExtraDataSize, |
| DWORD dwReserved) |
| { |
| PSTRING_TABLE pStringTable; |
| |
| TRACE("\n"); |
| |
| pStringTable = MyMalloc(sizeof(STRING_TABLE)); |
| if (pStringTable == NULL) return NULL; |
| |
| memset(pStringTable, 0, sizeof(STRING_TABLE)); |
| |
| pStringTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE); |
| if (pStringTable->pSlots == NULL) |
| { |
| MyFree(pStringTable->pSlots); |
| return NULL; |
| } |
| |
| memset(pStringTable->pSlots, 0, sizeof(TABLE_SLOT) * TABLE_DEFAULT_SIZE); |
| |
| pStringTable->dwUsedSlots = 0; |
| pStringTable->dwMaxSlots = TABLE_DEFAULT_SIZE; |
| pStringTable->dwMaxDataSize = dwMaxExtraDataSize; |
| |
| TRACE("Done\n"); |
| |
| return (HSTRING_TABLE)pStringTable; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableDestroy [SETUPAPI.@] |
| * |
| * Destroys a string table. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table to be destroyed |
| * |
| * RETURNS |
| * None |
| */ |
| VOID WINAPI |
| StringTableDestroy(HSTRING_TABLE hStringTable) |
| { |
| PSTRING_TABLE pStringTable; |
| DWORD i; |
| |
| TRACE("%p\n", hStringTable); |
| |
| pStringTable = (PSTRING_TABLE)hStringTable; |
| if (pStringTable == NULL) |
| return; |
| |
| if (pStringTable->pSlots != NULL) |
| { |
| for (i = 0; i < pStringTable->dwMaxSlots; i++) |
| { |
| MyFree(pStringTable->pSlots[i].pString); |
| pStringTable->pSlots[i].pString = NULL; |
| |
| MyFree(pStringTable->pSlots[i].pData); |
| pStringTable->pSlots[i].pData = NULL; |
| pStringTable->pSlots[i].dwSize = 0; |
| } |
| |
| MyFree(pStringTable->pSlots); |
| } |
| |
| MyFree(pStringTable); |
| } |
| |
| |
| /************************************************************************** |
| * StringTableAddString [SETUPAPI.@] |
| * |
| * Adds a new string to the string table. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * lpString [I] String to be added to the string table |
| * dwFlags [I] Flags |
| * 1: case sensitive compare |
| * |
| * RETURNS |
| * Success: String ID |
| * Failure: -1 |
| * |
| * NOTES |
| * If the given string already exists in the string table it will not |
| * be added again. The ID of the existing string will be returned in |
| * this case. |
| */ |
| DWORD WINAPI |
| StringTableAddString(HSTRING_TABLE hStringTable, |
| LPWSTR lpString, |
| DWORD dwFlags) |
| { |
| PSTRING_TABLE pStringTable; |
| DWORD i; |
| |
| TRACE("%p %s %x\n", hStringTable, debugstr_w(lpString), dwFlags); |
| |
| pStringTable = (PSTRING_TABLE)hStringTable; |
| if (pStringTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| return (DWORD)-1; |
| } |
| |
| /* Search for existing string in the string table */ |
| for (i = 0; i < pStringTable->dwMaxSlots; i++) |
| { |
| if (pStringTable->pSlots[i].pString != NULL) |
| { |
| if (dwFlags & 1) |
| { |
| if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString)) |
| { |
| return i + 1; |
| } |
| } |
| else |
| { |
| if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString)) |
| { |
| return i + 1; |
| } |
| } |
| } |
| } |
| |
| /* Check for filled slot table */ |
| if (pStringTable->dwUsedSlots == pStringTable->dwMaxSlots) |
| { |
| FIXME("Resize the string table!\n"); |
| return (DWORD)-1; |
| } |
| |
| /* Search for an empty slot */ |
| for (i = 0; i < pStringTable->dwMaxSlots; i++) |
| { |
| if (pStringTable->pSlots[i].pString == NULL) |
| { |
| pStringTable->pSlots[i].pString = MyMalloc((lstrlenW(lpString) + 1) * sizeof(WCHAR)); |
| if (pStringTable->pSlots[i].pString == NULL) |
| { |
| TRACE("Couldn't allocate memory for a new string!\n"); |
| return (DWORD)-1; |
| } |
| |
| lstrcpyW(pStringTable->pSlots[i].pString, lpString); |
| |
| pStringTable->dwUsedSlots++; |
| |
| return i + 1; |
| } |
| } |
| |
| TRACE("Couldn't find an empty slot!\n"); |
| |
| return (DWORD)-1; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableAddStringEx [SETUPAPI.@] |
| * |
| * Adds a new string plus extra data to the string table. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * lpString [I] String to be added to the string table |
| * dwFlags [I] Flags |
| * 1: case sensitive compare |
| * lpExtraData [I] Pointer to the extra data |
| * dwExtraDataSize [I] Size of the extra data |
| * |
| * RETURNS |
| * Success: String ID |
| * Failure: -1 |
| * |
| * NOTES |
| * If the given string already exists in the string table it will not |
| * be added again. The ID of the existing string will be returned in |
| * this case. |
| */ |
| DWORD WINAPI |
| StringTableAddStringEx(HSTRING_TABLE hStringTable, |
| LPWSTR lpString, |
| DWORD dwFlags, |
| LPVOID lpExtraData, |
| DWORD dwExtraDataSize) |
| { |
| FIXME("\n"); |
| return (DWORD)-1; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableDuplicate [SETUPAPI.@] |
| * |
| * Duplicates a given string table. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * |
| * RETURNS |
| * Success: Handle to the duplicated string table |
| * Failure: NULL |
| * |
| */ |
| HSTRING_TABLE WINAPI |
| StringTableDuplicate(HSTRING_TABLE hStringTable) |
| { |
| PSTRING_TABLE pSourceTable; |
| PSTRING_TABLE pDestinationTable; |
| DWORD i; |
| DWORD length; |
| |
| TRACE("%p\n", hStringTable); |
| |
| pSourceTable = (PSTRING_TABLE)hStringTable; |
| if (pSourceTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| return (HSTRING_TABLE)NULL; |
| } |
| |
| pDestinationTable = MyMalloc(sizeof(STRING_TABLE)); |
| if (pDestinationTable == NULL) |
| { |
| ERR("Cound not allocate a new string table!\n"); |
| return (HSTRING_TABLE)NULL; |
| } |
| |
| memset(pDestinationTable, 0, sizeof(STRING_TABLE)); |
| |
| pDestinationTable->pSlots = MyMalloc(sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots); |
| if (pDestinationTable->pSlots == NULL) |
| { |
| MyFree(pDestinationTable); |
| return (HSTRING_TABLE)NULL; |
| } |
| |
| memset(pDestinationTable->pSlots, 0, sizeof(TABLE_SLOT) * pSourceTable->dwMaxSlots); |
| |
| pDestinationTable->dwUsedSlots = 0; |
| pDestinationTable->dwMaxSlots = pSourceTable->dwMaxSlots; |
| |
| for (i = 0; i < pSourceTable->dwMaxSlots; i++) |
| { |
| if (pSourceTable->pSlots[i].pString != NULL) |
| { |
| length = (lstrlenW(pSourceTable->pSlots[i].pString) + 1) * sizeof(WCHAR); |
| pDestinationTable->pSlots[i].pString = MyMalloc(length); |
| if (pDestinationTable->pSlots[i].pString != NULL) |
| { |
| memcpy(pDestinationTable->pSlots[i].pString, |
| pSourceTable->pSlots[i].pString, |
| length); |
| pDestinationTable->dwUsedSlots++; |
| } |
| |
| if (pSourceTable->pSlots[i].pData != NULL) |
| { |
| length = pSourceTable->pSlots[i].dwSize; |
| pDestinationTable->pSlots[i].pData = MyMalloc(length); |
| if (pDestinationTable->pSlots[i].pData) |
| { |
| memcpy(pDestinationTable->pSlots[i].pData, |
| pSourceTable->pSlots[i].pData, |
| length); |
| pDestinationTable->pSlots[i].dwSize = length; |
| } |
| } |
| } |
| } |
| |
| return (HSTRING_TABLE)pDestinationTable; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableGetExtraData [SETUPAPI.@] |
| * |
| * Retrieves extra data from a given string table entry. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * dwId [I] String ID |
| * lpExtraData [I] Pointer a buffer that receives the extra data |
| * dwExtraDataSize [I] Size of the buffer |
| * |
| * RETURNS |
| * Success: TRUE |
| * Failure: FALSE |
| */ |
| BOOL WINAPI |
| StringTableGetExtraData(HSTRING_TABLE hStringTable, |
| DWORD dwId, |
| LPVOID lpExtraData, |
| DWORD dwExtraDataSize) |
| { |
| PSTRING_TABLE pStringTable; |
| |
| TRACE("%p %x %p %u\n", |
| hStringTable, dwId, lpExtraData, dwExtraDataSize); |
| |
| pStringTable = (PSTRING_TABLE)hStringTable; |
| if (pStringTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| return FALSE; |
| } |
| |
| if (dwId == 0 || dwId > pStringTable->dwMaxSlots) |
| { |
| ERR("Invalid Slot id!\n"); |
| return FALSE; |
| } |
| |
| if (pStringTable->pSlots[dwId - 1].dwSize < dwExtraDataSize) |
| { |
| ERR("Data size is too large!\n"); |
| return FALSE; |
| } |
| |
| memcpy(lpExtraData, |
| pStringTable->pSlots[dwId - 1].pData, |
| dwExtraDataSize); |
| |
| return TRUE; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableLookUpString [SETUPAPI.@] |
| * |
| * Searches a string table for a given string. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * lpString [I] String to be searched for |
| * dwFlags [I] Flags |
| * 1: case sensitive compare |
| * |
| * RETURNS |
| * Success: String ID |
| * Failure: -1 |
| */ |
| DWORD WINAPI |
| StringTableLookUpString(HSTRING_TABLE hStringTable, |
| LPWSTR lpString, |
| DWORD dwFlags) |
| { |
| PSTRING_TABLE pStringTable; |
| DWORD i; |
| |
| TRACE("%p %s %x\n", hStringTable, debugstr_w(lpString), dwFlags); |
| |
| pStringTable = (PSTRING_TABLE)hStringTable; |
| if (pStringTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| return (DWORD)-1; |
| } |
| |
| /* Search for existing string in the string table */ |
| for (i = 0; i < pStringTable->dwMaxSlots; i++) |
| { |
| if (pStringTable->pSlots[i].pString != NULL) |
| { |
| if (dwFlags & 1) |
| { |
| if (!lstrcmpW(pStringTable->pSlots[i].pString, lpString)) |
| return i + 1; |
| } |
| else |
| { |
| if (!lstrcmpiW(pStringTable->pSlots[i].pString, lpString)) |
| return i + 1; |
| } |
| } |
| } |
| |
| return (DWORD)-1; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableLookUpStringEx [SETUPAPI.@] |
| * |
| * Searches a string table and extra data for a given string. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * lpString [I] String to be searched for |
| * dwFlags [I] Flags |
| * 1: case sensitive compare |
| * lpExtraData [O] Pointer to the buffer that receives the extra data |
| * lpReserved [I/O] Unused |
| * |
| * RETURNS |
| * Success: String ID |
| * Failure: -1 |
| */ |
| DWORD WINAPI |
| StringTableLookUpStringEx(HSTRING_TABLE hStringTable, |
| LPWSTR lpString, |
| DWORD dwFlags, |
| LPVOID lpExtraData, |
| LPDWORD lpReserved) |
| { |
| FIXME("\n"); |
| return (DWORD)-1; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableSetExtraData [SETUPAPI.@] |
| * |
| * Sets extra data for a given string table entry. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * dwId [I] String ID |
| * lpExtraData [I] Pointer to the extra data |
| * dwExtraDataSize [I] Size of the extra data |
| * |
| * RETURNS |
| * Success: TRUE |
| * Failure: FALSE |
| */ |
| BOOL WINAPI |
| StringTableSetExtraData(HSTRING_TABLE hStringTable, |
| DWORD dwId, |
| LPVOID lpExtraData, |
| DWORD dwExtraDataSize) |
| { |
| PSTRING_TABLE pStringTable; |
| |
| TRACE("%p %x %p %u\n", |
| hStringTable, dwId, lpExtraData, dwExtraDataSize); |
| |
| pStringTable = (PSTRING_TABLE)hStringTable; |
| if (pStringTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| return FALSE; |
| } |
| |
| if (dwId == 0 || dwId > pStringTable->dwMaxSlots) |
| { |
| ERR("Invalid Slot id!\n"); |
| return FALSE; |
| } |
| |
| if (pStringTable->dwMaxDataSize < dwExtraDataSize) |
| { |
| ERR("Data size is too large!\n"); |
| return FALSE; |
| } |
| |
| pStringTable->pSlots[dwId - 1].pData = MyMalloc(dwExtraDataSize); |
| if (pStringTable->pSlots[dwId - 1].pData == NULL) |
| { |
| ERR("\n"); |
| return FALSE; |
| } |
| |
| memcpy(pStringTable->pSlots[dwId - 1].pData, |
| lpExtraData, |
| dwExtraDataSize); |
| pStringTable->pSlots[dwId - 1].dwSize = dwExtraDataSize; |
| |
| return TRUE; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableStringFromId [SETUPAPI.@] |
| * |
| * Returns a pointer to a string for the given string ID. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table. |
| * dwId [I] String ID |
| * |
| * RETURNS |
| * Success: Pointer to the string |
| * Failure: NULL |
| */ |
| LPWSTR WINAPI |
| StringTableStringFromId(HSTRING_TABLE hStringTable, |
| DWORD dwId) |
| { |
| PSTRING_TABLE pStringTable; |
| static WCHAR empty[] = {0}; |
| |
| TRACE("%p %x\n", hStringTable, dwId); |
| |
| pStringTable = (PSTRING_TABLE)hStringTable; |
| if (pStringTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| return NULL; |
| } |
| |
| if (dwId == 0 || dwId > pStringTable->dwMaxSlots) |
| return empty; |
| |
| return pStringTable->pSlots[dwId - 1].pString; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableStringFromIdEx [SETUPAPI.@] |
| * |
| * Returns a string for the given string ID. |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * dwId [I] String ID |
| * lpBuffer [I] Pointer to string buffer |
| * lpBufferSize [I/O] Pointer to the size of the string buffer |
| * |
| * RETURNS |
| * Success: TRUE |
| * Failure: FALSE |
| */ |
| BOOL WINAPI |
| StringTableStringFromIdEx(HSTRING_TABLE hStringTable, |
| DWORD dwId, |
| LPWSTR lpBuffer, |
| LPDWORD lpBufferLength) |
| { |
| PSTRING_TABLE pStringTable; |
| DWORD dwLength; |
| BOOL bResult = FALSE; |
| |
| TRACE("%p %x %p %p\n", hStringTable, dwId, lpBuffer, lpBufferLength); |
| |
| pStringTable = (PSTRING_TABLE)hStringTable; |
| if (pStringTable == NULL) |
| { |
| ERR("Invalid hStringTable!\n"); |
| *lpBufferLength = 0; |
| return FALSE; |
| } |
| |
| if (dwId == 0 || dwId > pStringTable->dwMaxSlots || |
| pStringTable->pSlots[dwId - 1].pString == NULL) |
| { |
| WARN("Invalid string ID!\n"); |
| *lpBufferLength = 0; |
| return FALSE; |
| } |
| |
| dwLength = (lstrlenW(pStringTable->pSlots[dwId - 1].pString) + 1) * sizeof(WCHAR); |
| if (dwLength <= *lpBufferLength) |
| { |
| lstrcpyW(lpBuffer, pStringTable->pSlots[dwId - 1].pString); |
| bResult = TRUE; |
| } |
| |
| *lpBufferLength = dwLength; |
| |
| return bResult; |
| } |
| |
| |
| /************************************************************************** |
| * StringTableTrim [SETUPAPI.@] |
| * |
| * ... |
| * |
| * PARAMS |
| * hStringTable [I] Handle to the string table |
| * |
| * RETURNS |
| * None |
| */ |
| VOID WINAPI |
| StringTableTrim(HSTRING_TABLE hStringTable) |
| { |
| FIXME("%p\n", hStringTable); |
| } |