// strpool.c #include #include #include #include typedef struct tagHEAP_STRING_POOLA { char* data; struct tagHEAP_STRING_POOLA* next; } HEAP_STRING_POOLA, *PHEAP_STRING_POOLA; typedef struct tagHEAP_STRING_POOLW { wchar_t* data; struct tagHEAP_STRING_POOLW* next; } HEAP_STRING_POOLW, *PHEAP_STRING_POOLW; PHEAP_STRING_POOLA heap_string_Apool = NULL; PHEAP_STRING_POOLW heap_string_Wpool = NULL; HANDLE hProcessHeap = NULL; PVOID HEAP_alloc ( DWORD len ) { return RtlAllocateHeap ( hProcessHeap, 0, len ); } VOID HEAP_free ( LPVOID memory ) { RtlFreeHeap ( hProcessHeap, 0, memory ); } LPWSTR HEAP_strdupW ( LPCWSTR src, DWORD len ) { LPWSTR dst; if ( !src ) return NULL; dst = HEAP_alloc ( (len+1) * sizeof(WCHAR) ); if ( !dst ) return NULL; memcpy ( dst, src, (len+1)*sizeof(WCHAR) ); return dst; } NTSTATUS HEAP_strcpyWtoA ( LPSTR lpszA, LPCWSTR lpszW, DWORD len ) { NTSTATUS Status = RtlUnicodeToMultiByteN ( lpszA, len, NULL, (LPWSTR)lpszW, len*sizeof(WCHAR) ); lpszA[len] = '\0'; return Status; } NTSTATUS HEAP_strcpyAtoW ( LPWSTR lpszW, LPCSTR lpszA, DWORD len ) { NTSTATUS Status = RtlMultiByteToUnicodeN ( lpszW, len*sizeof(WCHAR), NULL, (LPSTR)lpszA, len ); lpszW[len] = L'\0'; return Status; } NTSTATUS HEAP_strdupWtoA ( LPSTR* ppszA, LPCWSTR lpszW, DWORD len ) { *ppszA = NULL; if ( !lpszW ) return STATUS_SUCCESS; *ppszA = HEAP_alloc ( len + 1 ); if ( !*ppszA ) return STATUS_NO_MEMORY; return HEAP_strcpyWtoA ( *ppszA, lpszW, len ); } NTSTATUS HEAP_strdupAtoW ( LPWSTR* ppszW, LPCSTR lpszA, UINT* NewLen ) { ULONG len; *ppszW = NULL; if ( !lpszA ) return STATUS_SUCCESS; len = lstrlenA ( lpszA ); *ppszW = HEAP_alloc ( (len+1) * sizeof(WCHAR) ); if ( !*ppszW ) return STATUS_NO_MEMORY; if ( NewLen ) *NewLen = (UINT)len; return HEAP_strcpyAtoW ( *ppszW, lpszA, len ); } char* heap_string_poolA ( const wchar_t* pstrW, DWORD length ) { PHEAP_STRING_POOLA pPoolEntry = heap_string_Apool; char* pstrA = NULL; HEAP_strdupWtoA ( &pstrA, pstrW, length ); if ( !pstrA ) return NULL; while ( pPoolEntry ) { if ( !strcmp ( pPoolEntry->data, pstrA ) ) { HEAP_free ( pstrA ); return pPoolEntry->data; } pPoolEntry = pPoolEntry->next; } pPoolEntry = (PHEAP_STRING_POOLA)HEAP_alloc ( sizeof(HEAP_STRING_POOLA) ); pPoolEntry->data = pstrA; // IMHO, synchronization is *not* needed here. This data is process- // local, so the only possible contention is among threads. If a // conflict does occur, the only problem will be a small memory // leak that gets cleared up when the heap is destroyed by the // process exiting. pPoolEntry->next = heap_string_Apool; heap_string_Apool = pPoolEntry; return pPoolEntry->data; } wchar_t* heap_string_poolW ( const wchar_t* pstrWSrc, DWORD length ) { PHEAP_STRING_POOLW pPoolEntry = heap_string_Wpool; wchar_t* pstrW = NULL; pstrW = HEAP_strdupW ( (LPWSTR)pstrWSrc, length ); if ( !pstrW ) return NULL; while ( pPoolEntry ) { if ( !wcscmp (pPoolEntry->data, pstrW ) ) { HEAP_free ( pstrW ); return pPoolEntry->data; } pPoolEntry = pPoolEntry->next; } pPoolEntry = (PHEAP_STRING_POOLW)HEAP_alloc ( sizeof(HEAP_STRING_POOLW) ); pPoolEntry->data = pstrW; // IMHO, synchronization is *not* needed here. This data is process- // local, so the only possible contention is among threads. If a // conflict does occur, the only problem will be a small memory // leak that gets cleared up when the heap is destroyed by the // process exiting. pPoolEntry->next = heap_string_Wpool; heap_string_Wpool = pPoolEntry; return pPoolEntry->data; }