atom.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*
  2. * Server-side atom management
  3. *
  4. * Copyright (C) 1999, 2000 Alexandre Julliard
  5. * Copyright (C) 2000 Turchanov Sergei
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. #include "config.h"
  22. #include "wine/port.h"
  23. #include <assert.h>
  24. #include <stdlib.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include "unicode.h"
  28. #include "request.h"
  29. #include "object.h"
  30. #include "process.h"
  31. #define HASH_SIZE 37
  32. #define MIN_HASH_SIZE 4
  33. #define MAX_HASH_SIZE 0x200
  34. #define MAX_ATOM_LEN 255
  35. #define MIN_STR_ATOM 0xc000
  36. #define MAX_ATOMS 0x4000
  37. struct atom_entry
  38. {
  39. struct atom_entry *next; /* hash table list */
  40. struct atom_entry *prev; /* hash table list */
  41. int count; /* reference count */
  42. int hash; /* string hash */
  43. atom_t atom; /* atom handle */
  44. WCHAR str[1]; /* atom string */
  45. };
  46. struct atom_table
  47. {
  48. struct object obj; /* object header */
  49. int count; /* count of atom handles */
  50. int last; /* last handle in-use */
  51. struct atom_entry **handles; /* atom handles */
  52. int entries_count; /* humber of hash entries */
  53. struct atom_entry **entries; /* hash table entries */
  54. };
  55. static void atom_table_dump( struct object *obj, int verbose );
  56. static void atom_table_destroy( struct object *obj );
  57. static const struct object_ops atom_table_ops =
  58. {
  59. sizeof(struct atom_table), /* size */
  60. atom_table_dump, /* dump */
  61. no_add_queue, /* add_queue */
  62. NULL, /* remove_queue */
  63. NULL, /* signaled */
  64. NULL, /* satified */
  65. no_get_fd, /* get_fd */
  66. atom_table_destroy /* destroy */
  67. };
  68. static struct atom_table *global_table;
  69. /* copy an atom name from the request to a temporary area */
  70. static const WCHAR *copy_request_name(void)
  71. {
  72. static WCHAR buffer[MAX_ATOM_LEN+1];
  73. const WCHAR *str = get_req_data();
  74. size_t len = get_req_data_size();
  75. if (len > MAX_ATOM_LEN*sizeof(WCHAR))
  76. {
  77. set_error( STATUS_INVALID_PARAMETER );
  78. return NULL;
  79. }
  80. memcpy( buffer, str, len );
  81. buffer[len / sizeof(WCHAR)] = 0;
  82. return buffer;
  83. }
  84. /* create an atom table */
  85. static struct atom_table *create_table(int entries_count)
  86. {
  87. struct atom_table *table;
  88. if ((table = alloc_object( &atom_table_ops )))
  89. {
  90. if ((entries_count < MIN_HASH_SIZE) ||
  91. (entries_count > MAX_HASH_SIZE)) entries_count = HASH_SIZE;
  92. table->entries_count = entries_count;
  93. if (!(table->entries = malloc( sizeof(*table->entries) * table->entries_count )))
  94. {
  95. set_error( STATUS_NO_MEMORY );
  96. goto fail;
  97. }
  98. memset( table->entries, 0, sizeof(*table->entries) * table->entries_count );
  99. table->count = 64;
  100. table->last = -1;
  101. if ((table->handles = mem_alloc( sizeof(*table->handles) * table->count )))
  102. return table;
  103. fail:
  104. release_object( table );
  105. table = NULL;
  106. }
  107. return table;
  108. }
  109. /* retrieve an entry pointer from its atom */
  110. static struct atom_entry *get_atom_entry( struct atom_table *table, atom_t atom )
  111. {
  112. struct atom_entry *entry = NULL;
  113. if (table && (atom >= MIN_STR_ATOM) && (atom <= MIN_STR_ATOM + table->last))
  114. entry = table->handles[atom - MIN_STR_ATOM];
  115. if (!entry) set_error( STATUS_INVALID_HANDLE );
  116. return entry;
  117. }
  118. /* add an atom entry in the table and return its handle */
  119. static atom_t add_atom_entry( struct atom_table *table, struct atom_entry *entry )
  120. {
  121. int i;
  122. for (i = 0; i <= table->last; i++)
  123. if (!table->handles[i]) goto found;
  124. if (i == table->count)
  125. {
  126. struct atom_entry **new_table = NULL;
  127. int new_size = table->count + table->count / 2;
  128. if (new_size > MAX_ATOMS) new_size = MAX_ATOMS;
  129. if (new_size > table->count)
  130. new_table = realloc( table->handles, sizeof(*table->handles) * new_size );
  131. if (!new_table)
  132. {
  133. set_error( STATUS_NO_MEMORY );
  134. return 0;
  135. }
  136. table->count = new_size;
  137. table->handles = new_table;
  138. }
  139. table->last = i;
  140. found:
  141. table->handles[i] = entry;
  142. entry->atom = i + MIN_STR_ATOM;
  143. return entry->atom;
  144. }
  145. /* compute the hash code for a string */
  146. static int atom_hash( struct atom_table *table, const WCHAR *str )
  147. {
  148. int i;
  149. WCHAR hash = 0;
  150. for (i = 0; str[i]; i++) hash ^= toupperW(str[i]) + i;
  151. return hash % table->entries_count;
  152. }
  153. /* dump an atom table */
  154. static void atom_table_dump( struct object *obj, int verbose )
  155. {
  156. int i;
  157. struct atom_table *table = (struct atom_table *)obj;
  158. assert( obj->ops == &atom_table_ops );
  159. fprintf( stderr, "Atom table size=%d entries=%d\n",
  160. table->last + 1, table->entries_count );
  161. if (!verbose) return;
  162. for (i = 0; i <= table->last; i++)
  163. {
  164. struct atom_entry *entry = table->handles[i];
  165. if (!entry) continue;
  166. fprintf( stderr, " %04x: ref=%d hash=%d \"", entry->atom, entry->count, entry->hash );
  167. dump_strW( entry->str, strlenW(entry->str), stderr, "\"\"");
  168. fprintf( stderr, "\"\n" );
  169. }
  170. }
  171. /* destroy the atom table */
  172. static void atom_table_destroy( struct object *obj )
  173. {
  174. int i;
  175. struct atom_table *table = (struct atom_table *)obj;
  176. assert( obj->ops == &atom_table_ops );
  177. if (table->handles)
  178. {
  179. for (i = 0; i <= table->last; i++) free( table->handles[i] );
  180. free( table->handles );
  181. }
  182. if (table->entries) free( table->entries );
  183. }
  184. /* find an atom entry in its hash list */
  185. static struct atom_entry *find_atom_entry( struct atom_table *table, const WCHAR *str, int hash )
  186. {
  187. struct atom_entry *entry = table->entries[hash];
  188. while (entry)
  189. {
  190. if (!strcmpiW( entry->str, str )) break;
  191. entry = entry->next;
  192. }
  193. return entry;
  194. }
  195. /* close the atom table; used on server exit */
  196. void close_atom_table(void)
  197. {
  198. if (global_table) release_object( global_table );
  199. }
  200. /* add an atom to the table */
  201. static atom_t add_atom( struct atom_table *table, const WCHAR *str )
  202. {
  203. struct atom_entry *entry;
  204. int hash = atom_hash( table, str );
  205. atom_t atom = 0;
  206. if (!*str)
  207. {
  208. set_error( STATUS_OBJECT_NAME_INVALID );
  209. return 0;
  210. }
  211. if ((entry = find_atom_entry( table, str, hash ))) /* exists already */
  212. {
  213. entry->count++;
  214. return entry->atom;
  215. }
  216. if ((entry = mem_alloc( sizeof(*entry) + strlenW(str) * sizeof(WCHAR) )))
  217. {
  218. if ((atom = add_atom_entry( table, entry )))
  219. {
  220. entry->prev = NULL;
  221. if ((entry->next = table->entries[hash])) entry->next->prev = entry;
  222. table->entries[hash] = entry;
  223. entry->count = 1;
  224. entry->hash = hash;
  225. strcpyW( entry->str, str );
  226. }
  227. else free( entry );
  228. }
  229. else set_error( STATUS_NO_MEMORY );
  230. return atom;
  231. }
  232. /* delete an atom from the table */
  233. static void delete_atom( struct atom_table *table, atom_t atom )
  234. {
  235. struct atom_entry *entry = get_atom_entry( table, atom );
  236. if (entry && !--entry->count)
  237. {
  238. if (entry->next) entry->next->prev = entry->prev;
  239. if (entry->prev) entry->prev->next = entry->next;
  240. else table->entries[entry->hash] = entry->next;
  241. table->handles[atom - MIN_STR_ATOM] = NULL;
  242. free( entry );
  243. }
  244. }
  245. /* find an atom in the table */
  246. static atom_t find_atom( struct atom_table *table, const WCHAR *str )
  247. {
  248. struct atom_entry *entry;
  249. if (table && ((entry = find_atom_entry( table, str, atom_hash(table, str) ))))
  250. return entry->atom;
  251. if (!*str) set_error( STATUS_OBJECT_NAME_INVALID );
  252. else set_error( STATUS_OBJECT_NAME_NOT_FOUND );
  253. return 0;
  254. }
  255. /* increment the ref count of a global atom; used for window properties */
  256. int grab_global_atom( atom_t atom )
  257. {
  258. if (atom >= MIN_STR_ATOM)
  259. {
  260. struct atom_entry *entry = get_atom_entry( global_table, atom );
  261. if (entry) entry->count++;
  262. return (entry != NULL);
  263. }
  264. else return 1;
  265. }
  266. /* decrement the ref count of a global atom; used for window properties */
  267. void release_global_atom( atom_t atom )
  268. {
  269. if (atom >= MIN_STR_ATOM) delete_atom( global_table, atom );
  270. }
  271. /* add a global atom */
  272. DECL_HANDLER(add_atom)
  273. {
  274. struct atom_table **table_ptr = req->local ? &current->process->atom_table : &global_table;
  275. if (!*table_ptr) *table_ptr = create_table(0);
  276. if (*table_ptr)
  277. {
  278. const WCHAR *name = copy_request_name();
  279. if (name) reply->atom = add_atom( *table_ptr, name );
  280. }
  281. }
  282. /* delete a global atom */
  283. DECL_HANDLER(delete_atom)
  284. {
  285. delete_atom( req->local ? current->process->atom_table : global_table, req->atom );
  286. }
  287. /* find a global atom */
  288. DECL_HANDLER(find_atom)
  289. {
  290. const WCHAR *name = copy_request_name();
  291. if (name)
  292. reply->atom = find_atom( req->local ? current->process->atom_table : global_table, name );
  293. }
  294. /* get global atom name */
  295. DECL_HANDLER(get_atom_name)
  296. {
  297. struct atom_entry *entry;
  298. size_t len = 0;
  299. reply->count = -1;
  300. if ((entry = get_atom_entry( req->local ? current->process->atom_table : global_table,
  301. req->atom )))
  302. {
  303. reply->count = entry->count;
  304. len = strlenW( entry->str ) * sizeof(WCHAR);
  305. if (len <= get_reply_max_size()) set_reply_data( entry->str, len );
  306. else set_error( STATUS_BUFFER_OVERFLOW );
  307. }
  308. }
  309. /* init the process atom table */
  310. DECL_HANDLER(init_atom_table)
  311. {
  312. if (!current->process->atom_table)
  313. current->process->atom_table = create_table( req->entries );
  314. }