2003-08-15 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-objectid.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-objectid.c  DBusObjectID type
3  *
4  * Copyright (C) 2003  Red Hat Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-objectid.h"
25 #include "dbus-internals.h"
26
27 #ifdef DBUS_HAVE_INT64
28 #define VALUE(objid)         ((objid)->dbus_do_not_use_dummy1)
29 #define SERVER_MASK          DBUS_UINT64_CONSTANT (0xffff000000000000)
30 #define CLIENT_MASK          DBUS_UINT64_CONSTANT (0x0000ffff00000000)
31 #define IS_SERVER_MASK       DBUS_UINT64_CONSTANT (0x0000000080000000)
32 #define INSTANCE_MASK        DBUS_UINT64_CONSTANT (0x000000007fffffff)
33 #define SERVER_BITS(objid)   ((dbus_uint16_t) (VALUE (obj_id) >> 48))
34 #define CLIENT_BITS(objid)   ((dbus_uint16_t) ((VALUE (obj_id) & CLIENT_MASK) >> 32))
35 #define IS_SERVER_BIT(objid) ((VALUE (obj_id) & IS_SERVER_MASK) != 0)
36 #define INSTANCE_BITS(objid) ((dbus_uint32_t) (VALUE (obj_id) & INSTANCE_MASK))
37 #else
38 /* We care about the exact packing since in dbus-marshal.c we
39  * just use the DBusObjectID struct as-is.
40  */
41 #ifdef WORDS_BIGENDIAN
42 #define HIGH_VALUE(objid)    ((objid)->dbus_do_not_use_dummy2)
43 #define LOW_VALUE(objid)     ((objid)->dbus_do_not_use_dummy3)
44 #else
45 #define HIGH_VALUE(objid)    ((objid)->dbus_do_not_use_dummy3)
46 #define LOW_VALUE(objid)     ((objid)->dbus_do_not_use_dummy2)
47 #endif
48 #define SERVER_MASK          (0xffff0000)
49 #define CLIENT_MASK          (0x0000ffff)
50 #define IS_SERVER_MASK       (0x80000000)
51 #define INSTANCE_MASK        (0x7fffffff)
52 #define SERVER_BITS(objid)   ((HIGH_VALUE (objid) & SERVER_MASK) >> 16)
53 #define CLIENT_BITS(objid)   (HIGH_VALUE (objid) & CLIENT_MASK)
54 #define IS_SERVER_BIT(objid) ((LOW_VALUE (objid) & IS_SERVER_MASK) != 0)
55 #define INSTANCE_BITS(objid) (LOW_VALUE (objid) & INSTANCE_MASK)
56 #endif
57
58 /**
59  * @defgroup DBusObjectID object IDs
60  * @ingroup  DBusObjectID
61  * @brief object ID datatype
62  *
63  * Value type representing an object ID, i.e. an object in the remote
64  * application that can be communicated with.
65  *
66  * An object ID has three parts. 16 bits are provided by the server
67  * side of a connection, and used for the high 16 bits of all object
68  * IDs created by the client. 16 bits are provided by the client side
69  * and used as the next 16 bits of all object IDs created by the
70  * client. The next single bit is 1 if the object ID represents an
71  * object on the server side of the connection and 0 otherwise.  Then
72  * 31 bits are provided by the side creating an object instance and
73  * differ for each instance created (each app should make a best
74  * effort to avoid recycling the instance values).
75  *
76  * 0 is an invalid value for the server bits, the client bits,
77  * and the object instance bits. An object ID is the null ID
78  * if all 64 bits are 0.
79  * 
80  * @{
81  */
82
83 /**
84  * Checks whether two object IDs have the same value.
85  *
86  * @param a the first object ID
87  * @param b the second object ID
88  * @returns #TRUE if they are equal
89  */
90 dbus_bool_t
91 dbus_object_id_equal (const DBusObjectID *a,
92                       const DBusObjectID *b)
93 {
94 #ifdef DBUS_HAVE_INT64
95   return VALUE (a) == VALUE (b);
96 #else
97   return LOW_VALUE (a) == LOW_VALUE (b) && HIGH_VALUE (a) == HIGH_VALUE (b);
98 #endif
99 }
100
101 /**
102  * Compares two object IDs, appropriate for
103  * qsort(). Higher/lower IDs have no significance,
104  * but the comparison can be used for data structures
105  * that require ordering.
106  *
107  * @param a the first object ID
108  * @param b the second object ID
109  * @returns -1, 0, 1 as with strcmp()
110  */
111 int
112 dbus_object_id_compare (const DBusObjectID *a,
113                         const DBusObjectID *b)
114 {
115 #ifdef DBUS_HAVE_INT64
116   if (VALUE (a) > VALUE (b))
117     return 1;
118   else if (VALUE (a) < VALUE (b))
119     return -1;
120   else
121     return 0;
122 #else
123   if (HIGH_VALUE (a) > HIGH_VALUE (b))
124     return 1;
125   else if (HIGH_VALUE (a) < HIGH_VALUE (b))
126     return -1;
127   else if (LOW_VALUE (a) > LOW_VALUE (b))
128     return 1;
129   else if (LOW_VALUE (a) < LOW_VALUE (b))
130     return -1;
131   else
132     return 0;
133 #endif
134 }
135
136
137 /**
138  * An object ID contains 64 bits of data. This function
139  * returns the 16 bits that were provided by the server
140  * side of the connection.
141  *
142  * @param obj_id the object ID
143  * @returns the server bits of the ID
144  * 
145  */
146 dbus_uint16_t
147 dbus_object_id_get_server_bits (const DBusObjectID *obj_id)
148 {
149   return SERVER_BITS (obj_id);
150 }
151
152 /**
153  * An object ID contains 64 bits of data. This function
154  * returns the 16 bits that were provided by the client
155  * side of the connection.
156  *
157  * @param obj_id the object ID
158  * @returns the client bits of the ID
159  * 
160  */
161 dbus_uint16_t
162 dbus_object_id_get_client_bits (const DBusObjectID *obj_id)
163 {
164   return CLIENT_BITS (obj_id);
165 }
166
167 /**
168  * An object ID contains 64 bits of data. This function
169  * returns the bit flagging whether the object ID comes
170  * from the client or the server side of the connection.
171  *
172  * There is no secure guarantee that the bit is accurate;
173  * object ID values are simply conventional, to make
174  * collisions relatively unlikely.
175  *
176  * @param obj_id the object ID
177  * @returns the server-side bit of the ID
178  * 
179  */
180 dbus_bool_t
181 dbus_object_id_get_is_server_bit (const DBusObjectID *obj_id)
182 {
183   return IS_SERVER_BIT (obj_id);
184 }
185
186 /**
187  * An object ID contains 64 bits of data. This function
188  * returns the 31 bits that identify the object instance.
189  *
190  * @param obj_id the object ID
191  * @returns the instance bits of the ID
192  * 
193  */
194 dbus_uint32_t
195 dbus_object_id_get_instance_bits (const DBusObjectID *obj_id)
196 {
197   return INSTANCE_BITS (obj_id);
198 }
199
200 /**
201  * An object ID contains 64 bits of data. This function sets the 16
202  * bits provided by the server side of a connection.
203  *
204  * @param obj_id the object ID
205  * @param value the new value of the server bits
206  * 
207  */
208 void
209 dbus_object_id_set_server_bits (DBusObjectID       *obj_id,
210                                 dbus_uint16_t       value)
211 {
212 #ifdef DBUS_HAVE_INT64
213   VALUE (obj_id) &= ~ SERVER_MASK;
214   VALUE (obj_id) |= ((dbus_uint64_t) value) << 48;
215 #else
216   HIGH_VALUE (obj_id) &= ~ SERVER_MASK;
217   HIGH_VALUE (obj_id) |= ((dbus_uint32_t) value) << 16;
218 #endif
219 }
220
221 /**
222  * An object ID contains 64 bits of data. This function sets the 16
223  * bits provided by the client side of a connection.
224  *
225  * @param obj_id the object ID
226  * @param value the new value of the client bits
227  * 
228  */
229 void
230 dbus_object_id_set_client_bits (DBusObjectID       *obj_id,
231                                 dbus_uint16_t       value)
232 {
233 #ifdef DBUS_HAVE_INT64
234   VALUE (obj_id) &= ~ CLIENT_MASK;
235   VALUE (obj_id) |= ((dbus_uint64_t) value) << 32;
236 #else
237   HIGH_VALUE (obj_id) &= ~ CLIENT_MASK;
238   HIGH_VALUE (obj_id) |= (dbus_uint32_t) value;
239 #endif
240 }
241
242 /**
243  * An object ID contains 64 bits of data. This function sets the
244  * single bit that flags an instance as server-side or client-side.
245  *
246  * @param obj_id the object ID
247  * @param value the new value of the server-side bit
248  * 
249  */
250 void
251 dbus_object_id_set_is_server_bit (DBusObjectID       *obj_id,
252                                   dbus_bool_t         value)
253 {
254 #ifdef DBUS_HAVE_INT64
255   if (value)
256     VALUE (obj_id) |= IS_SERVER_MASK;
257   else
258     VALUE (obj_id) &= ~ IS_SERVER_MASK;
259 #else
260   if (value)
261     LOW_VALUE (obj_id) |= IS_SERVER_MASK;
262   else
263     LOW_VALUE (obj_id) &= ~ IS_SERVER_MASK;
264 #endif
265 }
266
267 /**
268  * An object ID contains 64 bits of data. This function sets the 31
269  * bits identifying the object instance.
270  *
271  * @param obj_id the object ID
272  * @param value the new value of the instance bits
273  * 
274  */
275 void
276 dbus_object_id_set_instance_bits (DBusObjectID       *obj_id,
277                                   dbus_uint32_t       value)
278 {
279 #ifdef DBUS_HAVE_INT64
280   VALUE (obj_id) &= ~ INSTANCE_MASK;
281   VALUE (obj_id) |= (dbus_uint64_t) value;
282 #else
283   LOW_VALUE (obj_id) &= ~ INSTANCE_MASK;
284   LOW_VALUE (obj_id) |= (dbus_uint32_t) value;
285 #endif
286 }
287
288 /**
289  * Set the object ID to an invalid value that cannot
290  * correspond to a valid object.
291  *
292  * @param obj_id the object ID
293  */
294 void
295 dbus_object_id_set_null (DBusObjectID *obj_id)
296 {
297   memset (obj_id, '\0', sizeof (DBusObjectID));
298 }
299
300 /**
301  * Check whether the object ID is set to a null value
302  *
303  * @param obj_id the object ID
304  * @returns #TRUE if null
305  */
306 dbus_bool_t
307 dbus_object_id_is_null (const DBusObjectID *obj_id)
308 {
309 #ifdef DBUS_HAVE_INT64
310   return VALUE (obj_id) == 0;
311 #else
312   return HIGH_VALUE (obj_id) == 0 && LOW_VALUE (obj_id) == 0;
313 #endif
314 }
315
316 #ifdef DBUS_HAVE_INT64
317 /**
318  * An object ID contains 64 bits of data. This function
319  * returns all of them as a 64-bit integer.
320  *  
321  * Use this function only if you are willing to limit portability to
322  * compilers with a 64-bit type (this includes C99 compilers and
323  * almost all other compilers).
324  *
325  * This function only exists if DBUS_HAVE_INT64 is defined.
326  *
327  * @param obj_id the object ID
328  * @returns the object ID as a 64-bit integer.
329  */
330 dbus_uint64_t
331 dbus_object_id_get_as_integer (const DBusObjectID *obj_id)
332 {
333   return VALUE (obj_id);
334 }
335
336 /**
337  * An object ID contains 64 bits of data. This function sets all of
338  * them as a 64-bit integer.
339  *  
340  * Use this function only if you are willing to limit portability to
341  * compilers with a 64-bit type (this includes C99 compilers and
342  * almost all other compilers).
343  * 
344  * This function only exists if #DBUS_HAVE_INT64 is defined.
345  *
346  * @param obj_id the object ID
347  * @param value the new value of the object ID
348  */
349 void
350 dbus_object_id_set_as_integer (DBusObjectID       *obj_id,
351                                dbus_uint64_t       value)
352 {
353   VALUE (obj_id) = value;
354 }
355 #endif /* DBUS_HAVE_INT64 */
356
357 /** @} */
358
359 #ifdef DBUS_BUILD_TESTS
360 #include "dbus-test.h"
361 #include <stdio.h>
362
363 /**
364  * Test for object ID routines.
365  *
366  * @returns #TRUE on success
367  */
368 dbus_bool_t
369 _dbus_object_id_test (void)
370 {
371   DBusObjectID tmp;
372   DBusObjectID tmp2;
373
374   /* Check basic get/set */
375   
376   dbus_object_id_set_server_bits (&tmp, 340);
377   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340);
378
379   dbus_object_id_set_client_bits (&tmp, 1492);
380   _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492);
381   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340);
382
383   dbus_object_id_set_is_server_bit (&tmp, TRUE);
384   _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492);
385   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340);
386   _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE);
387
388   dbus_object_id_set_instance_bits (&tmp, 2001);
389   _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 1492);
390   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 340);
391   _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE);
392   _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == 2001);
393
394   /* check equality check */
395   tmp2 = tmp;
396   _dbus_assert (dbus_object_id_equal (&tmp, &tmp2));
397
398   /* check get/set as integer */
399 #ifdef DBUS_HAVE_INT64
400   _dbus_assert (dbus_object_id_get_as_integer (&tmp) ==
401                 ((DBUS_UINT64_CONSTANT (340) << 48) |
402                  (DBUS_UINT64_CONSTANT (1492) << 32) |
403                  (DBUS_UINT64_CONSTANT (1) << 31) |
404                  (DBUS_UINT64_CONSTANT (2001))));
405
406   dbus_object_id_set_as_integer (&tmp, _DBUS_UINT64_MAX);
407   _dbus_assert (dbus_object_id_get_as_integer (&tmp) ==
408                 _DBUS_UINT64_MAX);
409   _dbus_assert (dbus_object_id_get_server_bits (&tmp) ==
410                 0xffff);
411   _dbus_assert (dbus_object_id_get_client_bits (&tmp) ==
412                 0xffff);
413   _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) ==
414                 TRUE);
415   _dbus_assert (dbus_object_id_get_instance_bits (&tmp) ==
416                 0x7fffffff);
417
418   dbus_object_id_set_as_integer (&tmp, 1);
419   dbus_object_id_set_as_integer (&tmp2, 2);
420   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1);
421   dbus_object_id_set_as_integer (&tmp2, 0);
422   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1);
423   dbus_object_id_set_as_integer (&tmp2, 1);
424   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0);
425 #endif
426
427   /* Check comparison */
428   tmp2 = tmp;
429   
430   dbus_object_id_set_server_bits (&tmp, 1);
431   dbus_object_id_set_server_bits (&tmp2, 2);
432   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1);
433   dbus_object_id_set_server_bits (&tmp2, 0);
434   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1);
435   dbus_object_id_set_server_bits (&tmp2, 1);
436   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0);
437
438   dbus_object_id_set_client_bits (&tmp, 1);
439   
440   dbus_object_id_set_client_bits (&tmp2, 2);
441   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == -1);
442   dbus_object_id_set_client_bits (&tmp2, 0);
443   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 1);
444   dbus_object_id_set_client_bits (&tmp2, 1);
445   _dbus_assert (dbus_object_id_compare (&tmp, &tmp2) == 0);
446
447   /* Check get/set again with high-limit numbers */  
448   
449   dbus_object_id_set_server_bits (&tmp, 0xf0f0);
450   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0);
451
452   dbus_object_id_set_client_bits (&tmp, 0xf00f);
453   _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f);
454   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0);
455
456   dbus_object_id_set_is_server_bit (&tmp, TRUE);
457   _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f);
458   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0);
459   _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE);
460
461   dbus_object_id_set_instance_bits (&tmp, 0x7fffffff);
462   _dbus_assert (dbus_object_id_get_client_bits (&tmp) == 0xf00f);
463   _dbus_assert (dbus_object_id_get_server_bits (&tmp) == 0xf0f0);
464   _dbus_assert (dbus_object_id_get_is_server_bit (&tmp) == TRUE);
465   _dbus_assert (dbus_object_id_get_instance_bits (&tmp) == 0x7fffffff);
466   
467   return TRUE;
468 }
469
470 #endif /* DBUS_BUILD_TESTS */