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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32
33 #include "unicode.h"
34 #include "request.h"
35 #include "object.h"
36 #include "process.h"
37 #include "handle.h"
38 #include "user.h"
39 #include "winuser.h"
40 #include "winternl.h"
41
42 #define HASH_SIZE 37
43 #define MIN_HASH_SIZE 4
44 #define MAX_HASH_SIZE 0x200
45
46 #define MAX_ATOM_LEN 255
47 #define MIN_STR_ATOM 0xc000
48 #define MAX_ATOMS 0x4000
49
50 struct atom_entry
51 {
52 struct atom_entry *next; /* hash table list */
53 struct atom_entry *prev; /* hash table list */
54 int count; /* reference count */
55 short pinned; /* whether the atom is pinned or not */
56 atom_t atom; /* atom handle */
57 unsigned short hash; /* string hash */
58 unsigned short len; /* string len */
59 WCHAR str[1]; /* atom string */
60 };
61
62 struct atom_table
63 {
64 struct object obj; /* object header */
65 int count; /* count of atom handles */
66 int last; /* last handle in-use */
67 struct atom_entry **handles; /* atom handles */
68 int entries_count; /* number of hash entries */
69 struct atom_entry **entries; /* hash table entries */
70 };
71
72 static void atom_table_dump( struct object *obj, int verbose );
73 static void atom_table_destroy( struct object *obj );
74
75 static const struct object_ops atom_table_ops =
76 {
77 sizeof(struct atom_table), /* size */
78 atom_table_dump, /* dump */
79 no_get_type, /* get_type */
80 no_add_queue, /* add_queue */
81 NULL, /* remove_queue */
82 NULL, /* signaled */
83 NULL, /* satisfied */
84 no_signal, /* signal */
85 no_get_fd, /* get_fd */
86 no_map_access, /* map_access */
87 default_get_sd, /* get_sd */
88 default_set_sd, /* set_sd */
89 no_lookup_name, /* lookup_name */
90 no_open_file, /* open_file */
91 no_close_handle, /* close_handle */
92 atom_table_destroy /* destroy */
93 };
94
95 static struct atom_table *global_table;
96
97 /* create an atom table */
98 static struct atom_table *create_table(int entries_count)
99 {
100 struct atom_table *table;
101
102 if ((table = alloc_object( &atom_table_ops )))
103 {
104 if ((entries_count < MIN_HASH_SIZE) ||
105 (entries_count > MAX_HASH_SIZE)) entries_count = HASH_SIZE;
106 table->entries_count = entries_count;
107 if (!(table->entries = malloc( sizeof(*table->entries) * table->entries_count )))
108 {
109 set_error( STATUS_NO_MEMORY );
110 goto fail;
111 }
112 memset( table->entries, 0, sizeof(*table->entries) * table->entries_count );
113 table->count = 64;
114 table->last = -1;
115 if ((table->handles = mem_alloc( sizeof(*table->handles) * table->count )))
116 return table;
117 fail:
118 release_object( table );
119 table = NULL;
120 }
121 return table;
122 }
123
124 /* retrieve an entry pointer from its atom */
125 static struct atom_entry *get_atom_entry( struct atom_table *table, atom_t atom )
126 {
127 struct atom_entry *entry = NULL;
128 if (table && (atom >= MIN_STR_ATOM) && (atom <= MIN_STR_ATOM + table->last))
129 entry = table->handles[atom - MIN_STR_ATOM];
130 if (!entry) set_error( STATUS_INVALID_HANDLE );
131 return entry;
132 }
133
134 /* add an atom entry in the table and return its handle */
135 static atom_t add_atom_entry( struct atom_table *table, struct atom_entry *entry )
136 {
137 int i;
138 for (i = 0; i <= table->last; i++)
139 if (!table->handles[i]) goto found;
140 if (i == table->count)
141 {
142 struct atom_entry **new_table = NULL;
143 int new_size = table->count + table->count / 2;
144 if (new_size > MAX_ATOMS) new_size = MAX_ATOMS;
145 if (new_size > table->count)
146 new_table = realloc( table->handles, sizeof(*table->handles) * new_size );
147 if (!new_table)
148 {
149 set_error( STATUS_NO_MEMORY );
150 return 0;
151 }
152 table->count = new_size;
153 table->handles = new_table;
154 }
155 table->last = i;
156 found:
157 table->handles[i] = entry;
158 entry->atom = i + MIN_STR_ATOM;
159 return entry->atom;
160 }
161
162 /* compute the hash code for a string */
163 static unsigned short atom_hash( struct atom_table *table, const WCHAR *str, data_size_t len )
164 {
165 unsigned int i;
166 unsigned short hash = 0;
167 for (i = 0; i < len; i++) hash ^= toupperW(str[i]) + i;
168 return hash % table->entries_count;
169 }
170
171 /* dump an atom table */
172 static void atom_table_dump( struct object *obj, int verbose )
173 {
174 int i;
175 struct atom_table *table = (struct atom_table *)obj;
176 assert( obj->ops == &atom_table_ops );
177
178 fprintf( stderr, "Atom table size=%d entries=%d\n",
179 table->last + 1, table->entries_count );
180 if (!verbose) return;
181 for (i = 0; i <= table->last; i++)
182 {
183 struct atom_entry *entry = table->handles[i];
184 if (!entry) continue;
185 fprintf( stderr, " %04x: ref=%d pinned=%c hash=%d \"",
186 entry->atom, entry->count, entry->pinned ? 'Y' : 'N', entry->hash );
187 dump_strW( entry->str, entry->len, stderr, "\"\"");
188 fprintf( stderr, "\"\n" );
189 }
190 }
191
192 /* destroy the atom table */
193 static void atom_table_destroy( struct object *obj )
194 {
195 int i;
196 struct atom_table *table = (struct atom_table *)obj;
197 assert( obj->ops == &atom_table_ops );
198 if (table->handles)
199 {
200 for (i = 0; i <= table->last; i++) free( table->handles[i] );
201 free( table->handles );
202 }
203 free( table->entries );
204 }
205
206 /* find an atom entry in its hash list */
207 static struct atom_entry *find_atom_entry( struct atom_table *table, const WCHAR *str,
208 data_size_t len, unsigned short hash )
209 {
210 struct atom_entry *entry = table->entries[hash];
211 while (entry)
212 {
213 if (entry->len == len && !memicmpW( entry->str, str, len )) break;
214 entry = entry->next;
215 }
216 return entry;
217 }
218
219 /* add an atom to the table */
220 static atom_t add_atom( struct atom_table *table, const WCHAR *str, data_size_t len )
221 {
222 struct atom_entry *entry;
223 unsigned short hash = atom_hash( table, str, len );
224 atom_t atom = 0;
225
226 if (!len)
227 {
228 set_error( STATUS_OBJECT_NAME_INVALID );
229 return 0;
230 }
231 if (len > MAX_ATOM_LEN)
232 {
233 set_error( STATUS_INVALID_PARAMETER );
234 return 0;
235 }
236 if ((entry = find_atom_entry( table, str, len, hash ))) /* exists already */
237 {
238 entry->count++;
239 return entry->atom;
240 }
241
242 if ((entry = mem_alloc( sizeof(*entry) + (len - 1) * sizeof(WCHAR) )))
243 {
244 if ((atom = add_atom_entry( table, entry )))
245 {
246 entry->prev = NULL;
247 if ((entry->next = table->entries[hash])) entry->next->prev = entry;
248 table->entries[hash] = entry;
249 entry->count = 1;
250 entry->pinned = 0;
251 entry->hash = hash;
252 entry->len = len;
253 memcpy( entry->str, str, len * sizeof(WCHAR) );
254 }
255 else free( entry );
256 }
257 else set_error( STATUS_NO_MEMORY );
258 return atom;
259 }
260
261 /* delete an atom from the table */
262 static void delete_atom( struct atom_table *table, atom_t atom, int if_pinned )
263 {
264 struct atom_entry *entry = get_atom_entry( table, atom );
265 if (!entry) return;
266 if (entry->pinned && !if_pinned) set_error( STATUS_WAS_LOCKED );
267 else if (!--entry->count)
268 {
269 if (entry->next) entry->next->prev = entry->prev;
270 if (entry->prev) entry->prev->next = entry->next;
271 else table->entries[entry->hash] = entry->next;
272 table->handles[atom - MIN_STR_ATOM] = NULL;
273 free( entry );
274 }
275 }
276
277 /* find an atom in the table */
278 static atom_t find_atom( struct atom_table *table, const WCHAR *str, data_size_t len )
279 {
280 struct atom_entry *entry;
281
282 if (!len)
283 {
284 set_error( STATUS_OBJECT_NAME_INVALID );
285 return 0;
286 }
287 if (len > MAX_ATOM_LEN)
288 {
289 set_error( STATUS_INVALID_PARAMETER );
290 return 0;
291 }
292 if (table && (entry = find_atom_entry( table, str, len, atom_hash(table, str, len) )))
293 return entry->atom;
294 set_error( STATUS_OBJECT_NAME_NOT_FOUND );
295 return 0;
296 }
297
298 static struct atom_table *get_global_table( struct winstation *winstation, int create )
299 {
300 struct atom_table *table = winstation ? winstation->atom_table : global_table;
301 if (!table)
302 {
303 if (create)
304 {
305 table = create_table( HASH_SIZE );
306 if (winstation) winstation->atom_table = table;
307 else
308 {
309 global_table = table;
310 make_object_static( &global_table->obj );
311 }
312 }
313 else set_error( STATUS_OBJECT_NAME_NOT_FOUND );
314 }
315 return table;
316 }
317
318 static struct atom_table *get_table( obj_handle_t h, int create )
319 {
320 struct atom_table *table = NULL;
321
322 if (h)
323 {
324 table = (struct atom_table *)get_handle_obj( current->process, h, 0, &atom_table_ops );
325 }
326 else
327 {
328 table = get_global_table( NULL, 1 );
329 if (table) grab_object( table );
330 }
331 return table;
332 }
333
334 /* add an atom in the global table; used for window properties */
335 atom_t add_global_atom( struct winstation *winstation, const WCHAR *str, data_size_t len )
336 {
337 struct atom_table *global_table = get_global_table( winstation, 1 );
338 if (!global_table) return 0;
339 return add_atom( global_table, str, len );
340 }
341
342 /* find an atom in the global table; used for window properties */
343 atom_t find_global_atom( struct winstation *winstation, const WCHAR *str, data_size_t len )
344 {
345 struct atom_table *global_table = get_global_table( winstation, 0 );
346 struct atom_entry *entry;
347
348 if (!len || len > MAX_ATOM_LEN || !global_table) return 0;
349 if ((entry = find_atom_entry( global_table, str, len, atom_hash(global_table, str, len) )))
350 return entry->atom;
351 return 0;
352 }
353
354 /* increment the ref count of a global atom; used for window properties */
355 int grab_global_atom( struct winstation *winstation, atom_t atom )
356 {
357 if (atom >= MIN_STR_ATOM)
358 {
359 struct atom_table *global_table = get_global_table( winstation, 0 );
360 if (global_table)
361 {
362 struct atom_entry *entry = get_atom_entry( global_table, atom );
363 if (entry) entry->count++;
364 return (entry != NULL);
365 }
366 else return 0;
367 }
368 else return 1;
369 }
370
371 /* decrement the ref count of a global atom; used for window properties */
372 void release_global_atom( struct winstation *winstation, atom_t atom )
373 {
374 if (atom >= MIN_STR_ATOM)
375 {
376 struct atom_table *global_table = get_global_table( winstation, 0 );
377 if (global_table) delete_atom( global_table, atom, 1 );
378 }
379 }
380
381 /* add a global atom */
382 DECL_HANDLER(add_atom)
383 {
384 struct atom_table *table = get_table( req->table, 1 );
385 if (table)
386 {
387 reply->atom = add_atom( table, get_req_data(), get_req_data_size() / sizeof(WCHAR) );
388 release_object( table );
389 }
390 }
391
392 /* delete a global atom */
393 DECL_HANDLER(delete_atom)
394 {
395 struct atom_table *table = get_table( req->table, 0 );
396 if (table)
397 {
398 delete_atom( table, req->atom, 0 );
399 release_object( table );
400 }
401 }
402
403 /* find a global atom */
404 DECL_HANDLER(find_atom)
405 {
406 struct atom_table *table = get_table( req->table, 0 );
407 if (table)
408 {
409 reply->atom = find_atom( table, get_req_data(), get_req_data_size() / sizeof(WCHAR) );
410 release_object( table );
411 }
412 }
413
414 /* get global atom name */
415 DECL_HANDLER(get_atom_information)
416 {
417 struct atom_table *table = get_table( req->table, 0 );
418 if (table)
419 {
420 struct atom_entry *entry;
421
422 if ((entry = get_atom_entry( table, req->atom )))
423 {
424 data_size_t len = entry->len * sizeof(WCHAR);
425 if (get_reply_max_size())
426 set_reply_data( entry->str, min( len, get_reply_max_size()));
427 reply->count = entry->count;
428 reply->pinned = entry->pinned;
429 reply->total = len;
430 }
431 else reply->count = -1;
432 release_object( table );
433 }
434 }
435
436 /* set global atom name */
437 DECL_HANDLER(set_atom_information)
438 {
439 struct atom_table *table = get_table( req->table, 0 );
440 if (table)
441 {
442 struct atom_entry *entry;
443
444 if ((entry = get_atom_entry( table, req->atom )))
445 {
446 if (req->pinned) entry->pinned = 1;
447 }
448 release_object( table );
449 }
450 }
451
452 /* init a (local) atom table */
453 DECL_HANDLER(init_atom_table)
454 {
455 struct atom_table* table = create_table( req->entries );
456
457 if (table)
458 {
459 reply->table = alloc_handle( current->process, table, 0, 0 );
460 release_object( table );
461 }
462 }
463
464 /* set global atom name */
465 DECL_HANDLER(empty_atom_table)
466 {
467 struct atom_table *table = get_table( req->table, 1 );
468 if (table)
469 {
470 int i;
471 struct atom_entry *entry;
472
473 for (i = 0; i <= table->last; i++)
474 {
475 entry = table->handles[i];
476 if (entry && (!entry->pinned || req->if_pinned))
477 {
478 if (entry->next) entry->next->prev = entry->prev;
479 if (entry->prev) entry->prev->next = entry->next;
480 else table->entries[entry->hash] = entry->next;
481 table->handles[i] = NULL;
482 free( entry );
483 }
484 }
485 release_object( table );
486 }
487 }
488
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.