rrproperty.c revision 4642e01f
1/*
2 * Copyright © 2006 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#include "randrstr.h"
24#include "propertyst.h"
25#include "swaprep.h"
26
27static int
28DeliverPropertyEvent(WindowPtr pWin, void *value)
29{
30    xRROutputPropertyNotifyEvent *event = value;
31    RREventPtr *pHead, pRREvent;
32    ClientPtr client;
33
34    pHead = LookupIDByType(pWin->drawable.id, RREventType);
35    if (!pHead)
36	return WT_WALKCHILDREN;
37
38    for (pRREvent = *pHead; pRREvent; pRREvent = pRREvent->next)
39    {
40	client = pRREvent->client;
41	if (client == serverClient || client->clientGone)
42	    continue;
43
44	if (!(pRREvent->mask & RROutputPropertyNotifyMask))
45	    continue;
46
47	event->sequenceNumber = client->sequence;
48	event->window = pRREvent->window->drawable.id;
49	if (client->swapped) {
50	    int n;
51	    swaps(&event->sequenceNumber, n);
52	    swapl(&event->window, n);
53	}
54	WriteEventsToClient(pRREvent->client, 1, (xEvent *)event);
55    }
56
57    return WT_WALKCHILDREN;
58}
59
60static void RRDeliverPropertyEvent(ScreenPtr pScreen, xEvent *event)
61{
62    if (!(dispatchException & (DE_RESET | DE_TERMINATE)))
63	WalkTree(pScreen, DeliverPropertyEvent, event);
64}
65
66void
67RRDeleteAllOutputProperties (RROutputPtr output)
68{
69    RRPropertyPtr prop, next;
70    xRROutputPropertyNotifyEvent    event;
71
72    for (prop = output->properties; prop; prop = next)
73    {
74	next = prop->next;
75	event.type = RREventBase + RRNotify;
76	event.subCode = RRNotify_OutputProperty;
77	event.output = output->id;
78	event.state = PropertyDelete;
79	event.atom = prop->propertyName;
80	event.timestamp = currentTime.milliseconds;
81	RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
82	if (prop->current.data)
83	    xfree(prop->current.data);
84	if (prop->pending.data)
85	    xfree(prop->pending.data);
86	xfree(prop);
87    }
88}
89
90static void
91RRInitOutputPropertyValue (RRPropertyValuePtr property_value)
92{
93    property_value->type = None;
94    property_value->format = 0;
95    property_value->size = 0;
96    property_value->data = NULL;
97}
98
99static RRPropertyPtr
100RRCreateOutputProperty (Atom property)
101{
102    RRPropertyPtr   prop;
103
104    prop = (RRPropertyPtr)xalloc(sizeof(RRPropertyRec));
105    if (!prop)
106	return NULL;
107    prop->next = NULL;
108    prop->propertyName = property;
109    prop->is_pending = FALSE;
110    prop->range = FALSE;
111    prop->immutable = FALSE;
112    prop->num_valid = 0;
113    prop->valid_values = NULL;
114    RRInitOutputPropertyValue (&prop->current);
115    RRInitOutputPropertyValue (&prop->pending);
116    return prop;
117}
118
119static void
120RRDestroyOutputProperty (RRPropertyPtr prop)
121{
122    if (prop->valid_values)
123	xfree (prop->valid_values);
124    if (prop->current.data)
125	xfree(prop->current.data);
126    if (prop->pending.data)
127	xfree(prop->pending.data);
128    xfree(prop);
129}
130
131void
132RRDeleteOutputProperty (RROutputPtr output, Atom property)
133{
134    RRPropertyPtr	prop, *prev;
135    xRROutputPropertyNotifyEvent    event;
136
137    for (prev = &output->properties; (prop = *prev); prev = &(prop->next))
138	if (prop->propertyName == property)
139	    break;
140    if (prop)
141    {
142	*prev = prop->next;
143	event.type = RREventBase + RRNotify;
144	event.subCode = RRNotify_OutputProperty;
145	event.output = output->id;
146	event.state = PropertyDelete;
147	event.atom = prop->propertyName;
148	event.timestamp = currentTime.milliseconds;
149	RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
150	RRDestroyOutputProperty (prop);
151    }
152}
153
154int
155RRChangeOutputProperty (RROutputPtr output, Atom property, Atom type,
156			int format, int mode, unsigned long len,
157			pointer value, Bool sendevent, Bool pending)
158{
159    RRPropertyPtr		    prop;
160    xRROutputPropertyNotifyEvent    event;
161    rrScrPrivPtr		    pScrPriv = rrGetScrPriv(output->pScreen);
162    int				    size_in_bytes;
163    int				    total_size;
164    unsigned long		    total_len;
165    RRPropertyValuePtr		    prop_value;
166    RRPropertyValueRec		    new_value;
167    Bool			    add = FALSE;
168
169    size_in_bytes = format >> 3;
170
171    /* first see if property already exists */
172    prop = RRQueryOutputProperty (output, property);
173    if (!prop)   /* just add to list */
174    {
175	prop = RRCreateOutputProperty (property);
176	if (!prop)
177	    return(BadAlloc);
178	add = TRUE;
179	mode = PropModeReplace;
180    }
181    if (pending && prop->is_pending)
182	prop_value = &prop->pending;
183    else
184	prop_value = &prop->current;
185
186    /* To append or prepend to a property the request format and type
187     must match those of the already defined property.  The
188     existing format and type are irrelevant when using the mode
189     "PropModeReplace" since they will be written over. */
190
191    if ((format != prop_value->format) && (mode != PropModeReplace))
192	return(BadMatch);
193    if ((prop_value->type != type) && (mode != PropModeReplace))
194	return(BadMatch);
195    new_value = *prop_value;
196    if (mode == PropModeReplace)
197	total_len = len;
198    else
199	total_len = prop_value->size + len;
200
201    if (mode == PropModeReplace || len > 0)
202    {
203	pointer	    new_data = NULL, old_data = NULL;
204
205	total_size = total_len * size_in_bytes;
206	new_value.data = (pointer)xalloc (total_size);
207	if (!new_value.data && total_size)
208	{
209	    if (add)
210		RRDestroyOutputProperty (prop);
211	    return BadAlloc;
212	}
213	new_value.size = len;
214	new_value.type = type;
215	new_value.format = format;
216
217	switch (mode) {
218	case PropModeReplace:
219	    new_data = new_value.data;
220	    old_data = NULL;
221	    break;
222	case PropModeAppend:
223	    new_data = (pointer) (((char *) new_value.data) +
224				  (prop_value->size * size_in_bytes));
225	    old_data = new_value.data;
226	    break;
227	case PropModePrepend:
228	    new_data = new_value.data;
229	    old_data = (pointer) (((char *) new_value.data) +
230				  (prop_value->size * size_in_bytes));
231	    break;
232	}
233	if (new_data)
234	    memcpy ((char *) new_data, (char *) value, len * size_in_bytes);
235	if (old_data)
236	    memcpy ((char *) old_data, (char *) prop_value->data,
237		    prop_value->size * size_in_bytes);
238
239	if (pending && pScrPriv->rrOutputSetProperty &&
240	    !pScrPriv->rrOutputSetProperty(output->pScreen, output,
241					   prop->propertyName, &new_value))
242	{
243	    if (new_value.data)
244		xfree (new_value.data);
245	    return (BadValue);
246	}
247	if (prop_value->data)
248	    xfree (prop_value->data);
249	*prop_value = new_value;
250    }
251
252    else if (len == 0)
253    {
254	/* do nothing */
255    }
256
257    if (add)
258    {
259	prop->next = output->properties;
260	output->properties = prop;
261    }
262
263    if (pending && prop->is_pending)
264	output->pendingProperties = TRUE;
265
266    if (sendevent)
267    {
268	event.type = RREventBase + RRNotify;
269	event.subCode = RRNotify_OutputProperty;
270	event.output = output->id;
271	event.state = PropertyNewValue;
272	event.atom = prop->propertyName;
273	event.timestamp = currentTime.milliseconds;
274	RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
275    }
276    return(Success);
277}
278
279Bool
280RRPostPendingProperties (RROutputPtr output)
281{
282    RRPropertyValuePtr	pending_value;
283    RRPropertyValuePtr	current_value;
284    RRPropertyPtr	property;
285    Bool		ret = TRUE;
286
287    if (!output->pendingProperties)
288	return TRUE;
289
290    output->pendingProperties = FALSE;
291    for (property = output->properties; property; property = property->next)
292    {
293	/* Skip non-pending properties */
294	if (!property->is_pending)
295	    continue;
296
297	pending_value = &property->pending;
298	current_value = &property->current;
299
300	/*
301	 * If the pending and current values are equal, don't mark it
302	 * as changed (which would deliver an event)
303	 */
304	if (pending_value->type == current_value->type &&
305	    pending_value->format == current_value->format &&
306	    pending_value->size == current_value->size &&
307	    !memcmp (pending_value->data, current_value->data,
308		     pending_value->size))
309	    continue;
310
311	if (RRChangeOutputProperty (output, property->propertyName,
312				    pending_value->type, pending_value->format,
313				    PropModeReplace, pending_value->size,
314				    pending_value->data, TRUE,
315				    FALSE) != Success)
316	    ret = FALSE;
317    }
318    return ret;
319}
320
321RRPropertyPtr
322RRQueryOutputProperty (RROutputPtr output, Atom property)
323{
324    RRPropertyPtr   prop;
325
326    for (prop = output->properties; prop; prop = prop->next)
327	if (prop->propertyName == property)
328	    return prop;
329    return NULL;
330}
331
332RRPropertyValuePtr
333RRGetOutputProperty (RROutputPtr output, Atom property, Bool pending)
334{
335    RRPropertyPtr   prop = RRQueryOutputProperty (output, property);
336    rrScrPrivPtr    pScrPriv = rrGetScrPriv(output->pScreen);
337
338    if (!prop)
339	return NULL;
340    if (pending && prop->is_pending)
341	return &prop->pending;
342    else {
343#if RANDR_13_INTERFACE
344	/* If we can, try to update the property value first */
345	if (pScrPriv->rrOutputGetProperty)
346	    pScrPriv->rrOutputGetProperty(output->pScreen, output,
347					  prop->propertyName);
348#endif
349	return &prop->current;
350    }
351}
352
353int
354RRConfigureOutputProperty (RROutputPtr output, Atom property,
355			   Bool pending, Bool range, Bool immutable,
356			   int num_values, INT32 *values)
357{
358    RRPropertyPtr   prop = RRQueryOutputProperty (output, property);
359    Bool	    add = FALSE;
360    INT32	    *new_values;
361
362    if (!prop)
363    {
364        prop = RRCreateOutputProperty (property);
365	if (!prop)
366	    return(BadAlloc);
367	add = TRUE;
368    } else if (prop->immutable && !immutable)
369	return(BadAccess);
370
371    /*
372     * ranges must have even number of values
373     */
374    if (range && (num_values & 1))
375	return BadMatch;
376
377    new_values = xalloc (num_values * sizeof (INT32));
378    if (!new_values && num_values)
379	return BadAlloc;
380    if (num_values)
381	memcpy (new_values, values, num_values * sizeof (INT32));
382
383    /*
384     * Property moving from pending to non-pending
385     * loses any pending values
386     */
387    if (prop->is_pending && !pending)
388    {
389	if (prop->pending.data)
390	    xfree (prop->pending.data);
391	RRInitOutputPropertyValue (&prop->pending);
392    }
393
394    prop->is_pending = pending;
395    prop->range = range;
396    prop->immutable = immutable;
397    prop->num_valid = num_values;
398    if (prop->valid_values)
399	xfree (prop->valid_values);
400    prop->valid_values = new_values;
401
402    if (add) {
403	prop->next = output->properties;
404	output->properties = prop;
405    }
406
407    return Success;
408}
409
410int
411ProcRRListOutputProperties (ClientPtr client)
412{
413    REQUEST(xRRListOutputPropertiesReq);
414    Atom			    *pAtoms = NULL, *temppAtoms;
415    xRRListOutputPropertiesReply    rep;
416    int				    numProps = 0;
417    RROutputPtr			    output;
418    RRPropertyPtr			    prop;
419
420    REQUEST_SIZE_MATCH(xRRListOutputPropertiesReq);
421
422    output = LookupOutput (client, stuff->output, DixReadAccess);
423
424    if (!output)
425        return RRErrorBase + BadRROutput;
426
427    for (prop = output->properties; prop; prop = prop->next)
428	numProps++;
429    if (numProps)
430        if(!(pAtoms = (Atom *)xalloc(numProps * sizeof(Atom))))
431            return(BadAlloc);
432
433    rep.type = X_Reply;
434    rep.length = (numProps * sizeof(Atom)) >> 2;
435    rep.sequenceNumber = client->sequence;
436    rep.nAtoms = numProps;
437    if (client->swapped)
438    {
439	int n;
440	swaps (&rep.sequenceNumber, n);
441	swapl (&rep.length, n);
442	swaps (&rep.nAtoms, n);
443    }
444    temppAtoms = pAtoms;
445    for (prop = output->properties; prop; prop = prop->next)
446	*temppAtoms++ = prop->propertyName;
447
448    WriteToClient(client, sizeof(xRRListOutputPropertiesReply), (char*)&rep);
449    if (numProps)
450    {
451        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
452        WriteSwappedDataToClient(client, numProps * sizeof(Atom), pAtoms);
453        xfree(pAtoms);
454    }
455    return(client->noClientException);
456}
457
458int
459ProcRRQueryOutputProperty (ClientPtr client)
460{
461    REQUEST(xRRQueryOutputPropertyReq);
462    xRRQueryOutputPropertyReply	    rep;
463    RROutputPtr			    output;
464    RRPropertyPtr		    prop;
465    char *extra = NULL;
466
467    REQUEST_SIZE_MATCH(xRRQueryOutputPropertyReq);
468
469    output = LookupOutput (client, stuff->output, DixReadAccess);
470
471    if (!output)
472        return RRErrorBase + BadRROutput;
473
474    prop = RRQueryOutputProperty (output, stuff->property);
475    if (!prop)
476	return BadName;
477
478    if (prop->num_valid) {
479	extra = xalloc(prop->num_valid * sizeof(INT32));
480	if (!extra)
481	    return BadAlloc;
482    }
483    rep.type = X_Reply;
484    rep.length = prop->num_valid;
485    rep.sequenceNumber = client->sequence;
486    rep.pending = prop->is_pending;
487    rep.range = prop->range;
488    rep.immutable = prop->immutable;
489    if (client->swapped)
490    {
491	int n;
492	swaps (&rep.sequenceNumber, n);
493	swapl (&rep.length, n);
494    }
495    WriteToClient (client, sizeof (xRRQueryOutputPropertyReply), (char*)&rep);
496    if (prop->num_valid)
497    {
498        memcpy(extra, prop->valid_values, prop->num_valid * sizeof(INT32));
499        client->pSwapReplyFunc = (ReplySwapPtr)Swap32Write;
500        WriteSwappedDataToClient(client, prop->num_valid * sizeof(INT32),
501				 extra);
502        xfree(extra);
503    }
504    return(client->noClientException);
505}
506
507int
508ProcRRConfigureOutputProperty (ClientPtr client)
509{
510    REQUEST(xRRConfigureOutputPropertyReq);
511    RROutputPtr				output;
512    int					num_valid;
513
514    REQUEST_AT_LEAST_SIZE(xRRConfigureOutputPropertyReq);
515
516    output = LookupOutput (client, stuff->output, DixReadAccess);
517
518    if (!output)
519        return RRErrorBase + BadRROutput;
520
521    num_valid = stuff->length - (sizeof (xRRConfigureOutputPropertyReq) >> 2);
522    return RRConfigureOutputProperty (output, stuff->property,
523				      stuff->pending, stuff->range,
524				      FALSE, num_valid,
525				      (INT32 *) (stuff + 1));
526}
527
528int
529ProcRRChangeOutputProperty (ClientPtr client)
530{
531    REQUEST(xRRChangeOutputPropertyReq);
532    RROutputPtr	    output;
533    char	    format, mode;
534    unsigned long   len;
535    int		    sizeInBytes;
536    int		    totalSize;
537    int		    err;
538
539    REQUEST_AT_LEAST_SIZE(xRRChangeOutputPropertyReq);
540    UpdateCurrentTime();
541    format = stuff->format;
542    mode = stuff->mode;
543    if ((mode != PropModeReplace) && (mode != PropModeAppend) &&
544	(mode != PropModePrepend))
545    {
546	client->errorValue = mode;
547	return BadValue;
548    }
549    if ((format != 8) && (format != 16) && (format != 32))
550    {
551	client->errorValue = format;
552        return BadValue;
553    }
554    len = stuff->nUnits;
555    if (len > ((0xffffffff - sizeof(xChangePropertyReq)) >> 2))
556	return BadLength;
557    sizeInBytes = format>>3;
558    totalSize = len * sizeInBytes;
559    REQUEST_FIXED_SIZE(xRRChangeOutputPropertyReq, totalSize);
560
561    output = LookupOutput (client, stuff->output, DixWriteAccess);
562    if (!output)
563	return RRErrorBase + BadRROutput;
564
565    if (!ValidAtom(stuff->property))
566    {
567	client->errorValue = stuff->property;
568	return(BadAtom);
569    }
570    if (!ValidAtom(stuff->type))
571    {
572	client->errorValue = stuff->type;
573	return(BadAtom);
574    }
575
576    err = RRChangeOutputProperty(output, stuff->property,
577				 stuff->type, (int)format,
578				 (int)mode, len, (pointer)&stuff[1], TRUE, TRUE);
579    if (err != Success)
580	return err;
581    else
582	return client->noClientException;
583}
584
585int
586ProcRRDeleteOutputProperty (ClientPtr client)
587{
588    REQUEST(xRRDeleteOutputPropertyReq);
589    RROutputPtr	output;
590
591    REQUEST_SIZE_MATCH(xRRDeleteOutputPropertyReq);
592    UpdateCurrentTime();
593    output = LookupOutput (client, stuff->output, DixWriteAccess);
594    if (!output)
595        return RRErrorBase + BadRROutput;
596
597    if (!ValidAtom(stuff->property))
598    {
599	client->errorValue = stuff->property;
600	return (BadAtom);
601    }
602
603
604    RRDeleteOutputProperty(output, stuff->property);
605    return client->noClientException;
606}
607
608int
609ProcRRGetOutputProperty (ClientPtr client)
610{
611    REQUEST(xRRGetOutputPropertyReq);
612    RRPropertyPtr		prop, *prev;
613    RRPropertyValuePtr		prop_value;
614    unsigned long		n, len, ind;
615    RROutputPtr			output;
616    xRRGetOutputPropertyReply	reply;
617    char			*extra = NULL;
618
619    REQUEST_SIZE_MATCH(xRRGetOutputPropertyReq);
620    if (stuff->delete)
621	UpdateCurrentTime();
622    output = LookupOutput (client, stuff->output,
623			   stuff->delete ? DixWriteAccess :
624			   DixReadAccess);
625    if (!output)
626	return RRErrorBase + BadRROutput;
627
628    if (!ValidAtom(stuff->property))
629    {
630	client->errorValue = stuff->property;
631	return(BadAtom);
632    }
633    if ((stuff->delete != xTrue) && (stuff->delete != xFalse))
634    {
635	client->errorValue = stuff->delete;
636	return(BadValue);
637    }
638    if ((stuff->type != AnyPropertyType) && !ValidAtom(stuff->type))
639    {
640	client->errorValue = stuff->type;
641	return(BadAtom);
642    }
643
644    for (prev = &output->properties; (prop = *prev); prev = &prop->next)
645	if (prop->propertyName == stuff->property)
646	    break;
647
648    reply.type = X_Reply;
649    reply.sequenceNumber = client->sequence;
650    if (!prop)
651    {
652	reply.nItems = 0;
653	reply.length = 0;
654	reply.bytesAfter = 0;
655	reply.propertyType = None;
656	reply.format = 0;
657	if (client->swapped) {
658	    int n;
659
660	    swaps(&reply.sequenceNumber, n);
661	    swapl(&reply.length, n);
662	    swapl(&reply.propertyType, n);
663	    swapl(&reply.bytesAfter, n);
664	    swapl(&reply.nItems, n);
665	}
666	WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
667	return(client->noClientException);
668    }
669
670    if (prop->immutable && stuff->delete)
671	return BadAccess;
672
673    prop_value = RRGetOutputProperty(output, stuff->property, stuff->pending);
674    if (!prop_value)
675	return BadAtom;
676
677    /* If the request type and actual type don't match. Return the
678    property information, but not the data. */
679
680    if (((stuff->type != prop_value->type) &&
681	 (stuff->type != AnyPropertyType))
682       )
683    {
684	reply.bytesAfter = prop_value->size;
685	reply.format = prop_value->format;
686	reply.length = 0;
687	reply.nItems = 0;
688	reply.propertyType = prop_value->type;
689	if (client->swapped) {
690	    int n;
691
692	    swaps(&reply.sequenceNumber, n);
693	    swapl(&reply.length, n);
694	    swapl(&reply.propertyType, n);
695	    swapl(&reply.bytesAfter, n);
696	    swapl(&reply.nItems, n);
697	}
698	WriteToClient(client, sizeof(xRRGetOutputPropertyReply), &reply);
699	return(client->noClientException);
700    }
701
702/*
703 *  Return type, format, value to client
704 */
705    n = (prop_value->format/8) * prop_value->size; /* size (bytes) of prop */
706    ind = stuff->longOffset << 2;
707
708   /* If longOffset is invalid such that it causes "len" to
709	    be negative, it's a value error. */
710
711    if (n < ind)
712    {
713	client->errorValue = stuff->longOffset;
714	return BadValue;
715    }
716
717    len = min(n - ind, 4 * stuff->longLength);
718
719    if (len) {
720	extra = xalloc(len);
721	if (!extra)
722	    return BadAlloc;
723    }
724    reply.bytesAfter = n - (ind + len);
725    reply.format = prop_value->format;
726    reply.length = (len + 3) >> 2;
727    if (prop_value->format)
728	reply.nItems = len / (prop_value->format / 8);
729    else
730	reply.nItems = 0;
731    reply.propertyType = prop_value->type;
732
733    if (stuff->delete && (reply.bytesAfter == 0))
734    {
735	xRROutputPropertyNotifyEvent    event;
736
737	event.type = RREventBase + RRNotify;
738	event.subCode = RRNotify_OutputProperty;
739	event.output = output->id;
740	event.state = PropertyDelete;
741	event.atom = prop->propertyName;
742	event.timestamp = currentTime.milliseconds;
743	RRDeliverPropertyEvent (output->pScreen, (xEvent *)&event);
744    }
745
746    if (client->swapped) {
747	int n;
748
749	swaps(&reply.sequenceNumber, n);
750	swapl(&reply.length, n);
751	swapl(&reply.propertyType, n);
752	swapl(&reply.bytesAfter, n);
753	swapl(&reply.nItems, n);
754    }
755    WriteToClient(client, sizeof(xGenericReply), &reply);
756    if (len)
757    {
758	memcpy(extra, (char *)prop_value->data + ind, len);
759	switch (reply.format) {
760	case 32: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap32Write; break;
761	case 16: client->pSwapReplyFunc = (ReplySwapPtr)CopySwap16Write; break;
762	default: client->pSwapReplyFunc = (ReplySwapPtr)WriteToClient; break;
763	}
764	WriteSwappedDataToClient(client, len,
765				 extra);
766	xfree(extra);
767    }
768
769    if (stuff->delete && (reply.bytesAfter == 0))
770    { /* delete the Property */
771	*prev = prop->next;
772	RRDestroyOutputProperty (prop);
773    }
774    return(client->noClientException);
775}
776
777