| /* | |
| * Atom table functions - 16 bit variant | |
| * | |
| * Copyright 1993, 1994, 1995 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 | |
| */ | |
| /* | |
| * Warning: The code assumes that LocalAlloc() returns a block aligned | |
| * on a 4-bytes boundary (because of the shifting done in | |
| * HANDLETOATOM). If this is not the case, the allocation code will | |
| * have to be changed. | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <stdlib.h> | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winerror.h" | |
| #include "wine/server.h" | |
| #include "wine/unicode.h" | |
| #include "wine/winbase16.h" | |
| #include "kernel_private.h" | |
| #include "stackframe.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(atom); | |
| #define DEFAULT_ATOMTABLE_SIZE 37 | |
| #define MAX_ATOM_LEN 255 | |
| #define ATOMTOHANDLE(atom) ((HANDLE16)(atom) << 2) | |
| #define HANDLETOATOM(handle) ((ATOM)(0xc000 | ((handle) >> 2))) | |
| typedef struct | |
| { | |
| HANDLE16 next; | |
| WORD refCount; | |
| BYTE length; | |
| BYTE str[1]; | |
| } ATOMENTRY; | |
| typedef struct | |
| { | |
| WORD size; | |
| HANDLE16 entries[1]; | |
| } ATOMTABLE; | |
| /*********************************************************************** | |
| * ATOM_GetTable | |
| * | |
| * Return a pointer to the atom table of a given segment, creating | |
| * it if necessary. | |
| * | |
| * RETURNS | |
| * Pointer to table: Success | |
| * NULL: Failure | |
| */ | |
| static ATOMTABLE *ATOM_GetTable( BOOL create /* [in] Create */ ) | |
| { | |
| INSTANCEDATA *ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) ); | |
| if (ptr->atomtable) | |
| { | |
| ATOMTABLE *table = (ATOMTABLE *)((char *)ptr + ptr->atomtable); | |
| if (table->size) return table; | |
| } | |
| if (!create) return NULL; | |
| if (!InitAtomTable16( 0 )) return NULL; | |
| /* Reload ptr in case it moved in linear memory */ | |
| ptr = MapSL( MAKESEGPTR( CURRENT_DS, 0 ) ); | |
| return (ATOMTABLE *)((char *)ptr + ptr->atomtable); | |
| } | |
| /*********************************************************************** | |
| * ATOM_Hash | |
| * RETURNS | |
| * The hash value for the input string | |
| */ | |
| static WORD ATOM_Hash( | |
| WORD entries, /* [in] Total number of entries */ | |
| LPCSTR str, /* [in] Pointer to string to hash */ | |
| WORD len /* [in] Length of string */ | |
| ) { | |
| WORD i, hash = 0; | |
| TRACE("%x, %s, %x\n", entries, str, len); | |
| for (i = 0; i < len; i++) hash ^= toupper(str[i]) + i; | |
| return hash % entries; | |
| } | |
| /*********************************************************************** | |
| * ATOM_IsIntAtomA | |
| */ | |
| static BOOL ATOM_IsIntAtomA(LPCSTR atomstr,WORD *atomid) | |
| { | |
| UINT atom = 0; | |
| if (!HIWORD(atomstr)) atom = LOWORD(atomstr); | |
| else | |
| { | |
| if (*atomstr++ != '#') return FALSE; | |
| while (*atomstr >= '0' && *atomstr <= '9') | |
| { | |
| atom = atom * 10 + *atomstr - '0'; | |
| atomstr++; | |
| } | |
| if (*atomstr) return FALSE; | |
| } | |
| if (atom >= MAXINTATOM) | |
| { | |
| SetLastError( ERROR_INVALID_PARAMETER ); | |
| atom = 0; | |
| } | |
| *atomid = atom; | |
| return TRUE; | |
| } | |
| /*********************************************************************** | |
| * ATOM_MakePtr | |
| * | |
| * Make an ATOMENTRY pointer from a handle (obtained from GetAtomHandle()). | |
| */ | |
| static inline ATOMENTRY *ATOM_MakePtr( HANDLE16 handle /* [in] Handle */ ) | |
| { | |
| return MapSL( MAKESEGPTR( CURRENT_DS, handle ) ); | |
| } | |
| /*********************************************************************** | |
| * InitAtomTable (KERNEL.68) | |
| */ | |
| WORD WINAPI InitAtomTable16( WORD entries ) | |
| { | |
| int i; | |
| HANDLE16 handle; | |
| ATOMTABLE *table; | |
| /* Allocate the table */ | |
| if (!entries) entries = DEFAULT_ATOMTABLE_SIZE; /* sanity check */ | |
| handle = LocalAlloc16( LMEM_FIXED, sizeof(ATOMTABLE) + (entries-1) * sizeof(HANDLE16) ); | |
| if (!handle) return 0; | |
| table = MapSL( MAKESEGPTR( CURRENT_DS, handle ) ); | |
| table->size = entries; | |
| for (i = 0; i < entries; i++) table->entries[i] = 0; | |
| /* Store a pointer to the table in the instance data */ | |
| ((INSTANCEDATA *)MapSL( MAKESEGPTR( CURRENT_DS, 0 )))->atomtable = handle; | |
| return handle; | |
| } | |
| /*********************************************************************** | |
| * GetAtomHandle (KERNEL.73) | |
| */ | |
| HANDLE16 WINAPI GetAtomHandle16( ATOM atom ) | |
| { | |
| if (atom < MAXINTATOM) return 0; | |
| return ATOMTOHANDLE( atom ); | |
| } | |
| /*********************************************************************** | |
| * AddAtom (KERNEL.70) | |
| * | |
| * Windows DWORD aligns the atom entry size. | |
| * The remaining unused string space created by the alignment | |
| * gets padded with '\0's in a certain way to ensure | |
| * that at least one trailing '\0' remains. | |
| * | |
| * RETURNS | |
| * Atom: Success | |
| * 0: Failure | |
| */ | |
| ATOM WINAPI AddAtom16( LPCSTR str ) | |
| { | |
| char buffer[MAX_ATOM_LEN+1]; | |
| WORD hash; | |
| HANDLE16 entry; | |
| ATOMENTRY * entryPtr; | |
| ATOMTABLE * table; | |
| int len, ae_len; | |
| WORD iatom; | |
| if (ATOM_IsIntAtomA( str, &iatom )) return iatom; | |
| TRACE("%s\n",debugstr_a(buffer)); | |
| /* Make a copy of the string to be sure it doesn't move in linear memory. */ | |
| lstrcpynA( buffer, str, sizeof(buffer) ); | |
| len = strlen( buffer ); | |
| if (!(table = ATOM_GetTable( TRUE ))) return 0; | |
| hash = ATOM_Hash( table->size, buffer, len ); | |
| entry = table->entries[hash]; | |
| while (entry) | |
| { | |
| entryPtr = ATOM_MakePtr( entry ); | |
| if ((entryPtr->length == len) && | |
| (!strncasecmp( entryPtr->str, buffer, len ))) | |
| { | |
| entryPtr->refCount++; | |
| TRACE("-- existing 0x%x\n", entry); | |
| return HANDLETOATOM( entry ); | |
| } | |
| entry = entryPtr->next; | |
| } | |
| ae_len = (sizeof(ATOMENTRY)+len+3) & ~3; | |
| entry = LocalAlloc16( LMEM_FIXED, ae_len ); | |
| if (!entry) return 0; | |
| /* Reload the table ptr in case it moved in linear memory */ | |
| table = ATOM_GetTable( FALSE ); | |
| entryPtr = ATOM_MakePtr( entry ); | |
| entryPtr->next = table->entries[hash]; | |
| entryPtr->refCount = 1; | |
| entryPtr->length = len; | |
| /* Some applications _need_ the '\0' padding provided by this strncpy */ | |
| strncpy( entryPtr->str, buffer, ae_len - sizeof(ATOMENTRY) + 1 ); | |
| entryPtr->str[ae_len - sizeof(ATOMENTRY)] = '\0'; | |
| table->entries[hash] = entry; | |
| TRACE("-- new 0x%x\n", entry); | |
| return HANDLETOATOM( entry ); | |
| } | |
| /*********************************************************************** | |
| * DeleteAtom (KERNEL.71) | |
| */ | |
| ATOM WINAPI DeleteAtom16( ATOM atom ) | |
| { | |
| ATOMENTRY * entryPtr; | |
| ATOMTABLE * table; | |
| HANDLE16 entry, *prevEntry; | |
| WORD hash; | |
| if (atom < MAXINTATOM) return 0; /* Integer atom */ | |
| TRACE("0x%x\n",atom); | |
| if (!(table = ATOM_GetTable( FALSE ))) return 0; | |
| entry = ATOMTOHANDLE( atom ); | |
| entryPtr = ATOM_MakePtr( entry ); | |
| /* Find previous atom */ | |
| hash = ATOM_Hash( table->size, entryPtr->str, entryPtr->length ); | |
| prevEntry = &table->entries[hash]; | |
| while (*prevEntry && *prevEntry != entry) | |
| { | |
| ATOMENTRY * prevEntryPtr = ATOM_MakePtr( *prevEntry ); | |
| prevEntry = &prevEntryPtr->next; | |
| } | |
| if (!*prevEntry) return atom; | |
| /* Delete atom */ | |
| if (--entryPtr->refCount == 0) | |
| { | |
| *prevEntry = entryPtr->next; | |
| LocalFree16( entry ); | |
| } | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * FindAtom (KERNEL.69) | |
| */ | |
| ATOM WINAPI FindAtom16( LPCSTR str ) | |
| { | |
| ATOMTABLE * table; | |
| WORD hash,iatom; | |
| HANDLE16 entry; | |
| int len; | |
| TRACE("%s\n",debugstr_a(str)); | |
| if (ATOM_IsIntAtomA( str, &iatom )) return iatom; | |
| if ((len = strlen( str )) > 255) len = 255; | |
| if (!(table = ATOM_GetTable( FALSE ))) return 0; | |
| hash = ATOM_Hash( table->size, str, len ); | |
| entry = table->entries[hash]; | |
| while (entry) | |
| { | |
| ATOMENTRY * entryPtr = ATOM_MakePtr( entry ); | |
| if ((entryPtr->length == len) && | |
| (!strncasecmp( entryPtr->str, str, len ))) | |
| { | |
| TRACE("-- found %x\n", entry); | |
| return HANDLETOATOM( entry ); | |
| } | |
| entry = entryPtr->next; | |
| } | |
| TRACE("-- not found\n"); | |
| return 0; | |
| } | |
| /*********************************************************************** | |
| * GetAtomName (KERNEL.72) | |
| */ | |
| UINT16 WINAPI GetAtomName16( ATOM atom, LPSTR buffer, INT16 count ) | |
| { | |
| ATOMENTRY * entryPtr; | |
| HANDLE16 entry; | |
| char * strPtr; | |
| INT len; | |
| char text[8]; | |
| TRACE("%x\n",atom); | |
| if (!count) return 0; | |
| if (atom < MAXINTATOM) | |
| { | |
| sprintf( text, "#%d", atom ); | |
| len = strlen(text); | |
| strPtr = text; | |
| } | |
| else | |
| { | |
| if (!ATOM_GetTable( FALSE )) return 0; | |
| entry = ATOMTOHANDLE( atom ); | |
| entryPtr = ATOM_MakePtr( entry ); | |
| len = entryPtr->length; | |
| strPtr = entryPtr->str; | |
| } | |
| if (len >= count) len = count-1; | |
| memcpy( buffer, strPtr, len ); | |
| buffer[len] = '\0'; | |
| return len; | |
| } |