Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtSvc / DtUtil1 / DndBuff.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: DndBuff.c /main/5 1996/06/21 17:30:55 ageorge $ */
24 /*********************************************************************
25  *
26  *      File:           DndBuff.c
27  *
28  *      Description:    Implementation of the Buffer Transfer routines
29  *                      FOR the DND Convenience API.
30  *
31  *********************************************************************
32  *
33  *
34  *      RESTRICTED CONFIDENTIAL INFORMATION:
35  *      
36  *      The information in this document is subject to special
37  *      restrictions in a confidential disclosure agreement bertween
38  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
39  *      document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
40  *      Sun's specific written approval.  This documment and all copies
41  *      and derivative works thereof must be returned or destroyed at
42  *      Sun's request.
43  *
44  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
45  *
46  * (c) Copyright 1993, 1994 Hewlett-Packard Company
47  * (c) Copyright 1993, 1994 International Business Machines Corp.
48  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
49  * (c) Copyright 1993, 1994 Novell, Inc.
50  * 
51  */
52
53 #include <stdlib.h>
54 #include <X11/Intrinsic.h>
55 #include <Xm/AtomMgr.h>
56 #include <Xm/DragC.h>
57 #include <Xm/DropSMgr.h>
58 #include <Xm/DropTrans.h>
59 #include "Dnd.h"
60 #include "DndP.h"
61 #include "DtSvcLock.h"
62
63 /* 
64  * Buffer Transfer Protocol Function Prototypes
65  */
66
67 static void     dndBuffGetTargets(Boolean, Boolean, Atom**, Cardinal*);
68 static void     dndBuffGetAvailTargets(DtDragInfo*, Atom**, Cardinal*);
69 static void     dndBuffGetExportTargets(DtDragInfo*, Atom**, Cardinal*);
70 static void     dndBuffGetImportTargets(DtDropInfo*, Atom**, Cardinal*);
71 static void     dndBuffConvertInit(DtDragInfo*);
72 static Boolean  dndBuffConvert(Widget, DtDragInfo*, Atom*, Atom*,
73                         Atom*, XtPointer*, unsigned long*, int*, 
74                         XSelectionRequestEvent*);
75 static void     dndBuffConvertFinish(DtDragInfo*);
76 static void     dndBuffTransferTargets(DtDropInfo*,
77                         Atom*, Cardinal, Atom**, Cardinal*);
78 static void     dndBuffTransfer(Widget, DtDropInfo*, Atom*, Atom*, Atom*,
79                         XtPointer, unsigned long*, int*);
80 static void     dndBuffTransferFinish(DtDropInfo*);
81
82 /* 
83  * Buffer Transfer Support Functions
84  */
85
86 static void     dndBufferDataToSelectionValue(DtDndBuffer *, Cardinal,
87                         XtPointer *, unsigned long *, Boolean);
88 static void     dndBufferLengthsToSelectionValue(DtDndBuffer *, Cardinal,
89                         XtPointer *, unsigned long *);
90 static void     dndBufferNamesToSelectionValue(DtDndBuffer *, Cardinal,
91                         XtPointer *, unsigned long *);
92 static void     dndTextSelectionValueToBuffer(Display *, 
93                         Atom *, XtPointer, unsigned long *, int *, String,
94                         XtPointer *, unsigned long *,
95                         DtDndBuffer **, Cardinal *);
96 static void     dndSelectionValueToBuffer(XtPointer, unsigned long,
97                         XtPointer, unsigned long, XtPointer, unsigned long,
98                         DtDndBuffer **, Cardinal *);
99
100 /* 
101  * Buffer Transfer Selection Targets
102  */
103
104 static Atom     XA_DT_BUFFER_DATA;
105 static Atom     XA_DT_BUFFER_LENGTHS;
106 static Atom     XA_DT_BUFFER_NAMES;
107
108 /* 
109  * Buffer Transfer Protocol Methods
110  */
111
112 static DtDndMethods dndBuffTransferProtocol = {
113         "DtDndBufferTransfer",                  /* name */
114         (DtDndProtocol)DtDND_BUFFER_TRANSFER,   /* protocol */
115         DtDND_DRAG_SOURCE_DATA,                 /* sourceType */
116         dndBuffGetAvailTargets,                 /* getAvailTargets */
117         dndBuffGetExportTargets,                /* getExportTargets */
118         dndBuffGetImportTargets,                /* getImportTargets */
119         dndBuffConvertInit,                     /* convertInit */
120         dndBuffConvert,                         /* convert */
121         dndBuffConvertFinish,                   /* convertFinish */
122         dndBuffTransferTargets,                 /* transferTargets */
123         dndBuffTransfer,                        /* transfer */
124         dndBuffTransferFinish,                  /* transferFinish */
125 };
126
127 typedef struct _TransferState {
128         XtPointer       dataValue;
129         unsigned long   dataLength;
130         XtPointer       lengthsValue;
131         unsigned long   lengthsLength;
132         XtPointer       namesValue;
133         unsigned long   namesLength;
134         String          dataLabel;
135         Atom            textTarget;
136 } TransferState;
137
138 /*
139  * Buffer transfer protocol initialization
140  */
141 DtDndMethods *
142 _DtDndBuffTransferProtocolInitialize(
143         Display *       dpy)
144 {
145         _DtSvcProcessLock();
146         if (XA_DT_BUFFER_DATA == 0) {
147                 XA_DT_BUFFER_DATA       = DtGetAtom(dpy,"_DT_BUFFER_DATA");
148                 XA_DT_BUFFER_LENGTHS    = DtGetAtom(dpy,"_DT_BUFFER_LENGTHS");
149                 XA_DT_BUFFER_NAMES      = DtGetAtom(dpy,"_DT_BUFFER_NAMES");
150         }
151         _DtSvcProcessUnlock();
152         return &dndBuffTransferProtocol;
153 }
154
155 /*
156  * Returns export/import targets for buffer transfers
157  */
158 static void
159 dndBuffGetTargets(
160         Boolean         includeText,
161         Boolean         owCompat,
162         Atom **         targets,
163         Cardinal *      numTargets)
164 {
165         int             ii = 0;
166
167         *numTargets = 3 + (includeText ? 2 : 0) + (owCompat ? 1 : 0);
168
169         *targets = (Atom *)XtMalloc(*numTargets * sizeof(Atom));
170
171         (*targets)[ii++]        = XA_DT_BUFFER_DATA;
172         (*targets)[ii++]        = XA_DT_BUFFER_LENGTHS;
173         (*targets)[ii++]        = XA_DT_BUFFER_NAMES;
174
175         if (includeText) {
176                 (*targets)[ii++] = XA_TEXT;
177                 (*targets)[ii++] = XA_STRING;
178         }
179
180         if (owCompat) {
181                 (*targets)[ii++] = XA_SUN_DATA_LABEL;
182         }
183 }
184
185 /*
186  * Returns available targets for buffer transfers
187  */
188 static void
189 dndBuffGetAvailTargets(
190         DtDragInfo *    dtDragInfo,
191         Atom **         availTargets,
192         Cardinal *      numAvailTargets)
193 {
194         dndBuffGetTargets(True, True, availTargets, numAvailTargets);
195 }
196
197 /*
198  * Returns export targets for buffer transfers
199  */
200 static void
201 dndBuffGetExportTargets(
202         DtDragInfo *    dtDragInfo,
203         Atom **         exportTargets,
204         Cardinal *      numExportTargets)
205 {
206         dndBuffGetTargets(dtDragInfo->bufferIsText, True,
207                         exportTargets, numExportTargets);
208 }
209
210 /*
211  * Returns import targets for buffer transfers
212  */
213 static void
214 dndBuffGetImportTargets(
215         DtDropInfo *    dtDropInfo,
216         Atom **         importTargets,
217         Cardinal *      numImportTargets)
218 {
219         dndBuffGetTargets(dtDropInfo->textIsBuffer, True,
220                         importTargets, numImportTargets);
221 }
222
223 /*
224  * Initialize protocol specific part of drag data
225  */
226 static void
227 dndBuffConvertInit(
228         DtDragInfo *    dtDragInfo)
229 {
230         DtDndContext *  dragData = dtDragInfo->dragData;
231
232         dragData->data.buffers = (DtDndBuffer *)
233                 XtCalloc(dragData->numItems, sizeof(DtDndBuffer));
234 }
235
236 /*
237  * Convert the buffers into selection data
238  */
239 static Boolean
240 dndBuffConvert(
241         Widget          dragContext,
242         DtDragInfo *    dtDragInfo,
243         Atom *          selection,
244         Atom *          target,  
245         Atom *          returnType,
246         XtPointer *     returnValue,
247         unsigned long * returnLength,
248         int *           returnFormat,
249         XSelectionRequestEvent * selectionRequestEvent)
250 {
251         DtDndContext *  dragData = dtDragInfo->dragData;
252
253         /*
254          * TEXT or STRING
255          *      Convert the buffer data to a text selection
256          */
257         if (*target == XA_TEXT || *target == XA_STRING) {
258                 *returnType     = XA_STRING;
259                 *returnFormat   = 8;
260                 dndBufferDataToSelectionValue(
261                         dragData->data.buffers, dragData->numItems,
262                         returnValue, returnLength, True);
263         /*
264          * _SUN_DATA_LABEL
265          *      Convert the first buffer name to a selection
266          */
267         } else if (*target == XA_SUN_DATA_LABEL) {
268                 *returnType     = XA_STRING;
269                 *returnFormat   = 8;
270                 *returnValue    = XtNewString(dragData->data.buffers[0].name);
271                 *returnLength   = strlen(*returnValue)+1;
272         /*
273          * _DT_BUFFER_DATA
274          *      Convert the buffer data to a selection
275          */
276         } else if (*target == XA_DT_BUFFER_DATA) {
277                 *returnType     = XA_DT_BUFFER_DATA;
278                 *returnFormat   = 8;
279                 dndBufferDataToSelectionValue(
280                         dragData->data.buffers, dragData->numItems,
281                         returnValue, returnLength, False);
282         /*
283          * _DT_BUFFER_LENGTHS
284          *      Convert the buffer lengths to a selection
285          */
286         } else if (*target == XA_DT_BUFFER_LENGTHS) {
287                 *returnType     = XA_INTEGER;
288                 *returnFormat   = 32;
289                 dndBufferLengthsToSelectionValue(
290                         dragData->data.buffers, dragData->numItems,
291                         returnValue, returnLength);
292         /*
293          * _DT_BUFFER_NAMES
294          *      Convert the buffer names to a selection
295          */
296         } else if (*target == XA_DT_BUFFER_NAMES) {
297                 *returnType     = XA_STRING;
298                 *returnFormat   = 8;
299                 dndBufferNamesToSelectionValue(
300                         dragData->data.buffers, dragData->numItems,
301                         returnValue, returnLength);
302         } else {
303                 return False;
304         }
305
306         return True;
307 }
308
309 /*
310  * Clean up from the convert init proc
311  */
312 static void
313 dndBuffConvertFinish(
314         DtDragInfo *    dtDragInfo)
315 {
316         DtDndContext *  dragData = dtDragInfo->dragData;
317
318         if (dragData->data.buffers) {
319                 XtFree((char *)dragData->data.buffers);
320                 dragData->data.buffers = NULL;
321         }
322 }
323
324 /*
325  * Returns the transfer targets selected from the export targets
326  * Prefer buffers over TEXT/STRING
327  */
328 static void
329 dndBuffTransferTargets(
330         DtDropInfo *    dtDropInfo,
331         Atom *          exportTargets,
332         Cardinal        numExportTargets,
333         Atom **         transferTargets,
334         Cardinal *      numTransferTargets)
335 {
336         Boolean         foundData, foundLengths, foundNames, 
337                         foundDataLabel, foundText, foundString;
338         int             ii;
339         TransferState * xferState; 
340
341         xferState = (TransferState *)XtCalloc(1,sizeof(TransferState));
342         dtDropInfo->transferInfo->clientData = (XtPointer)xferState;
343
344
345         foundData = foundLengths = foundNames = False;
346         foundDataLabel = foundText = foundString = False;
347
348         for (ii = 0; ii < numExportTargets; ii++) {
349                 if (exportTargets[ii] == XA_DT_BUFFER_DATA) {
350                         foundData = True;
351                 } else if (exportTargets[ii] == XA_DT_BUFFER_LENGTHS) {
352                         foundLengths = True;
353                 } else if (exportTargets[ii] == XA_DT_BUFFER_NAMES) {
354                         foundNames = True;
355                 } else if (exportTargets[ii] == XA_SUN_DATA_LABEL) {
356                         foundDataLabel = True;
357                 } else if (exportTargets[ii] == XA_TEXT) {
358                         foundText = True;
359                 } else if (exportTargets[ii] == XA_STRING) {
360                         foundString = True;
361                 }
362         }
363
364         *numTransferTargets = 2;        /* max number of transfer targets */
365    
366         *transferTargets = (Atom *)XtMalloc(*numTransferTargets * sizeof(Atom));
367
368         ii = 0;
369
370         if (foundData && foundLengths && foundNames) {
371                 *numTransferTargets = 2;
372                 (*transferTargets)[ii++] = XA_DT_BUFFER_NAMES;
373                 (*transferTargets)[ii++] = XA_DT_BUFFER_LENGTHS;
374         } else if (foundDataLabel && (foundText || foundString)) {
375                 *numTransferTargets = 2;
376                 (*transferTargets)[ii++] = XA_SUN_DATA_LABEL;
377                 (*transferTargets)[ii++] = foundText ? XA_TEXT : XA_STRING;
378                 xferState->textTarget     = foundText ? XA_TEXT : XA_STRING;
379         } else if (foundText || foundString) {
380                 *numTransferTargets = 1;
381                 (*transferTargets)[ii++] = foundText ? XA_TEXT : XA_STRING;
382         } else {
383                 *numTransferTargets     = 0;
384                 *transferTargets        = NULL;
385                 return;
386         }
387 }
388
389 /*
390  * Transfer the selection data into buffers
391  */
392 static void
393 dndBuffTransfer(
394         Widget          dropTransfer,
395         DtDropInfo *    dtDropInfo,
396         Atom *          selection,
397         Atom *          target,
398         Atom *          type,
399         XtPointer       value,
400         unsigned long * length,
401         int *           format)
402 {
403         Display *       display  = XtDisplayOfObject(dropTransfer);
404         DtDndContext *  dropData = dtDropInfo->dropData;
405         TransferState * xferState = 
406                         (TransferState *)dtDropInfo->transferInfo->clientData;
407
408         /*
409          * Ignore if we've already transferred
410          */
411         if (dropData->data.buffers) {
412                 XtFree(value);
413                 return;
414         }
415
416         /*
417          * TEXT or STRING
418          *
419          * Convert the text selection into buffers
420          */
421         if (*target == XA_TEXT || *target == XA_STRING) {
422
423                 dndTextSelectionValueToBuffer(display, 
424                         type, value, length, format, xferState->dataLabel,
425                         &(xferState->dataValue), &(xferState->dataLength),
426                         &(dropData->data.buffers), &(dropData->numItems));
427
428         /*
429          * _SUN_DATA_LABEL
430          *
431          * Save the buffer name selection for later conversion
432          * Request the text data transfer
433          */
434         } else if (*target == XA_SUN_DATA_LABEL &&
435                    *type   == XA_STRING &&
436                    *format == 8) {
437
438                 xferState->dataLabel    = (String)value;
439    
440                 _DtDndTransferAdd(dropTransfer, dtDropInfo,
441                                   &(xferState->textTarget), 1);
442         /*
443          * _DT_BUFFER_DATA
444          *
445          * Save the buffer data selection for later conversion
446          */
447         } else if (*target == XA_DT_BUFFER_DATA &&
448                    *type   == XA_DT_BUFFER_DATA &&
449                    *format == 8) {
450
451                 xferState->dataValue    = value;
452                 xferState->dataLength   = *length;
453    
454                 dndSelectionValueToBuffer(
455                         xferState->dataValue, xferState->dataLength,
456                         xferState->lengthsValue, xferState->lengthsLength,
457                         xferState->namesValue, xferState->namesLength,
458                         &(dropData->data.buffers), &(dropData->numItems));
459    
460
461         /*
462          * _DT_BUFFER_LENGTHS
463          *
464          * Save the buffer lengths selection for later conversion
465          * Request the buffer data transfer
466          */
467         } else if (*target == XA_DT_BUFFER_LENGTHS &&
468                    *type   == XA_INTEGER &&
469                    *format == 32) {
470
471                 xferState->lengthsValue  = value;
472                 xferState->lengthsLength = *length;
473    
474                 _DtDndTransferAdd(dropTransfer, dtDropInfo,
475                                   &XA_DT_BUFFER_DATA, 1);
476         /*
477          * _DT_BUFFER_NAMES
478          *
479          * Save the buffer names selection for later conversion
480          */
481         } else if (*target == XA_DT_BUFFER_NAMES &&
482                    *type   == XA_STRING &&
483                    *format == 8) {
484
485                 xferState->namesValue   = value;
486                 xferState->namesLength  = *length;
487
488         /*
489          * Ignore transfers we don't understand
490          */
491         } else {
492                 XtFree(value);
493                 return;
494         }
495 }
496
497 /*
498  * Clean up from the transfer proc
499  */
500 static void
501 dndBuffTransferFinish(
502         DtDropInfo *    dtDropInfo)
503 {
504         DtDndContext *  dropData = dtDropInfo->dropData;
505         TransferState * xferState = 
506                         (TransferState *)dtDropInfo->transferInfo->clientData;
507
508         dtDropInfo->transferInfo->clientData = NULL;
509
510         if (xferState->dataValue)
511                 XtFree(xferState->dataValue);
512         if (xferState->lengthsValue)
513                 XtFree(xferState->lengthsValue);
514         if (xferState->namesValue)
515                 XtFree(xferState->namesValue);
516         if (xferState->dataLabel)
517                 XtFree(xferState->dataLabel);
518         XtFree((char *)xferState);
519         XtFree((char *)dropData->data.buffers);
520 }
521
522 /*
523  * Convert buffer data into a single chunk of memory
524  */
525 static void
526 dndBufferDataToSelectionValue(
527         DtDndBuffer *   buffers,
528         Cardinal        numBuffers,
529         XtPointer *     returnValue,
530         unsigned long * returnLength,
531         Boolean         isText)
532 {
533         int              ii;
534         char            *bufferPtr;
535
536         *returnLength = 0;
537
538         for (ii = 0; ii < numBuffers; ii++) {
539                 *returnLength += buffers[ii].size;
540                 if (isText) {
541                         *returnLength += 1;
542                 }
543         }
544
545         *returnValue = (XtPointer) XtMalloc(*returnLength);
546
547         bufferPtr = (XtPointer)*returnValue;
548
549         for (ii = 0; ii < numBuffers; ii++) {
550                 memcpy(bufferPtr, buffers[ii].bp, buffers[ii].size);
551                 bufferPtr += buffers[ii].size;
552                 if (isText) {
553                         *bufferPtr = '\0';
554                         bufferPtr++;
555                 }
556         }
557
558         if (isText) {
559                 *returnLength -= 1;
560         }
561 }
562
563 /*
564  * Convert buffer lengths into a list of integers
565  */
566 static void
567 dndBufferLengthsToSelectionValue(
568         DtDndBuffer *   buffers,
569         Cardinal        numBuffers,
570         XtPointer *     returnValue,
571         unsigned long * returnLength)
572 {
573         int             ii;
574         unsigned long * lengths;
575
576         *returnLength = numBuffers;
577
578         *returnValue = (XtPointer) XtMalloc(*returnLength * sizeof(long));
579
580         lengths = (unsigned long *)*returnValue;
581  
582         for (ii = 0; ii < numBuffers; ii++) {
583                 lengths[ii] = buffers[ii].size;
584         }
585 }
586
587 /*
588  * Convert buffer names into a single chunk of memory
589  */
590 static void
591 dndBufferNamesToSelectionValue(
592         DtDndBuffer *   buffers,
593         Cardinal        numBuffers,
594         XtPointer *     returnValue,
595         unsigned long * returnLength)
596 {
597         int             ii, len;
598         char *          namePtr;
599
600         *returnLength = 0;
601
602         for (ii = 0; ii < numBuffers; ii++) {
603                 if (buffers[ii].name != NULL) {
604                         *returnLength += strlen(buffers[ii].name) + 1;
605                 } else {
606                         *returnLength += 1;
607                 }
608         }
609
610         *returnValue = (XtPointer) XtMalloc(*returnLength);
611
612         namePtr = (char *)*returnValue;
613
614         for (ii = 0; ii < numBuffers; ii++) {
615                 if (buffers[ii].name == NULL) {
616                         *namePtr = '\0';
617                         namePtr++;
618                 } else {
619                         len = strlen(buffers[ii].name) + 1;
620                         memcpy(namePtr, buffers[ii].name, len);
621                         namePtr += len;
622                 }
623         }
624 }
625
626 /*
627  * Split text selection data into multiple buffers
628  */
629 static void
630 dndTextSelectionValueToBuffer(
631         Display *       display,
632         Atom *          type,
633         XtPointer       value,
634         unsigned long * length,
635         int *           format,
636         String          dataLabel,
637         XtPointer *     returnValue,
638         unsigned long * returnLength,
639         DtDndBuffer **  buffers,
640         Cardinal *      numBuffers)
641 {
642         XTextProperty   textProp;
643         char **         text;
644         char *          bufPtr;
645         int             ii, status, textCount, textLen;
646
647         textProp.value          = (unsigned char *)value;
648         textProp.encoding       = *type;
649         textProp.format         = *format;
650         textProp.nitems         = *length;
651
652         status = XmbTextPropertyToTextList(display, &textProp, 
653                         &text, &textCount);
654
655         if (status != Success) {
656                 *numBuffers     = 1;
657                 (*buffers)      = (DtDndBuffer *)XtMalloc(sizeof(DtDndBuffer));
658
659                 (*buffers)[0].bp        = value;
660                 (*buffers)[0].size      = *length;
661                 (*buffers)[0].name      = dataLabel ? dataLabel : (String)NULL;
662
663                 *returnValue            = value;
664                 *returnLength           = *length;
665
666                 return;
667         }
668
669         *numBuffers = textCount;
670
671         (*buffers) = (DtDndBuffer *)XtMalloc(*numBuffers * sizeof(DtDndBuffer));
672
673         textLen = 0;
674         for (ii = 0; ii < *numBuffers; ii++) {
675                 (*buffers)[ii].size     = strlen(text[ii]);
676                 (*buffers)[ii].name     = (String)NULL;
677                 textLen += (*buffers)[ii].size+1;
678         }
679
680         (*returnValue)  = XtMalloc(textLen * sizeof(char));
681         (*returnLength) = textLen;
682
683         bufPtr = (*returnValue);
684         for (ii = 0; ii < *numBuffers; ii++) {
685                 (*buffers)[ii].bp       = bufPtr;
686                 memcpy(bufPtr,text[ii],(*buffers)[ii].size+1);
687                 bufPtr += (*buffers)[ii].size+1;
688         }
689
690         if (dataLabel)
691                 (*buffers)[0].name      = dataLabel;
692
693         XtFree(value);
694         XFreeStringList(text);
695 }
696
697 /*
698  * Split data/lengths/names selection data into multiple buffers
699  */
700 static void
701 dndSelectionValueToBuffer(
702         XtPointer       dataValue,
703         unsigned long   dataLength,
704         XtPointer       lengthsValue,
705         unsigned long   lengthsLength,
706         XtPointer       namesValue,
707         unsigned long   namesLength,
708         DtDndBuffer **  buffers,
709         Cardinal *      numBuffers)
710 {
711         int             ii;
712         char *          bufPtr;
713         char *          namePtr;
714         unsigned long * lenList;
715
716         if (lengthsLength == 0 || lengthsValue == NULL) {
717
718                 *numBuffers = 1;
719
720                 (*buffers) = (DtDndBuffer *)XtMalloc(sizeof(DtDndBuffer));
721
722                 (*buffers)[0].bp        = dataValue;
723                 (*buffers)[0].size      = dataLength;
724                 (*buffers)[0].name      = (String)NULL;
725
726                 return;
727         }
728
729         *numBuffers = lengthsLength;
730
731         (*buffers) = (DtDndBuffer *)XtMalloc(*numBuffers * sizeof(DtDndBuffer));
732
733         lenList = (unsigned long *)lengthsValue;
734         bufPtr  = dataValue;
735         namePtr = namesValue;
736
737         for (ii = 0; ii < *numBuffers; ii++) {
738                 (*buffers)[ii].bp       = bufPtr;
739                 (*buffers)[ii].size     = lenList[ii];
740                 (*buffers)[ii].name     = namePtr;
741                 bufPtr += lenList[ii];
742                 namePtr = strchr(namePtr, '\0');
743                 namePtr++;
744         }
745 }