Various cosmetic changes.
[wine] / dlls / oleaut32 / safearray.c
1 /*************************************************************************
2  * OLE Automation
3  * SafeArray Implementation
4  *
5  * This file contains the implementation of the SafeArray interface.
6  *
7  * Copyright 1999 Sylvain St-Germain
8  */
9
10 #include <stdio.h>
11 #include <string.h>
12 #include "windef.h"
13 #include "winerror.h"
14 #include "winbase.h"
15 #include "oleauto.h"
16 #include "wine/obj_base.h"
17 #include "debugtools.h"
18
19 DEFAULT_DEBUG_CHANNEL(ole);
20
21 #define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
22
23 /* Locally used methods */
24 static INT  
25 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
26
27 static ULONG   
28 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
29
30 static BOOL  
31 isPointer(USHORT feature);
32
33 static INT   
34 getFeatures(VARTYPE vt);
35
36 static BOOL  
37 validCoordinate(LONG *coor, SAFEARRAY *psa);
38
39 static BOOL  
40 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
41
42 static BOOL  
43 validArg(SAFEARRAY *psa);
44
45 static ULONG   
46 getArraySize(SAFEARRAY *psa);
47
48 static HRESULT 
49 duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
50
51 /* Association between VARTYPE and their size.
52    A size of zero is defined for the unsupported types.  */
53
54 #define VARTYPE_NOT_SUPPORTED 0
55 static const ULONG VARTYPE_SIZE[] =
56 {
57   /* this is taken from wtypes.h.  Only [S]es are supported by the SafeArray */
58 VARTYPE_NOT_SUPPORTED,  /* VT_EMPTY    [V]   [P]    nothing                     */
59 VARTYPE_NOT_SUPPORTED,  /* VT_NULL     [V]   [P]    SQL style Nul       */
60 2,                      /* VT_I2       [V][T][P][S] 2 byte signed int */
61 4,                      /* VT_I4       [V][T][P][S] 4 byte signed int */
62 4,                      /* VT_R4       [V][T][P][S] 4 byte real */
63 8,                      /* VT_R8       [V][T][P][S] 8 byte real */
64 8,                      /* VT_CY       [V][T][P][S] currency */
65 8,                      /* VT_DATE     [V][T][P][S] date */
66 sizeof(BSTR),           /* VT_BSTR     [V][T][P][S] OLE Automation string*/
67 sizeof(LPDISPATCH),     /* VT_DISPATCH [V][T][P][S] IDispatch * */
68 4,                      /* VT_ERROR    [V][T]   [S] SCODE       */
69 4,                      /* VT_BOOL     [V][T][P][S] True=-1, False=0*/
70 sizeof(VARIANT),        /* VT_VARIANT  [V][T][P][S] VARIANT *   */
71 sizeof(LPUNKNOWN),      /* VT_UNKNOWN  [V][T]   [S] IUnknown * */
72 sizeof(DECIMAL),        /* VT_DECIMAL  [V][T]   [S] 16 byte fixed point */
73 VARTYPE_NOT_SUPPORTED,                         /* no VARTYPE here..... */
74 VARTYPE_NOT_SUPPORTED,  /* VT_I1          [T]       signed char */
75 1,                      /* VT_UI1      [V][T][P][S] unsigned char                       */
76 VARTYPE_NOT_SUPPORTED,  /* VT_UI2         [T][P]    unsigned short      */
77 VARTYPE_NOT_SUPPORTED,  /* VT_UI4         [T][P]    unsigned short      */
78 VARTYPE_NOT_SUPPORTED,  /* VT_I8          [T][P]    signed 64-bit int                   */
79 VARTYPE_NOT_SUPPORTED,  /* VT_UI8         [T][P]    unsigned 64-bit int         */
80 VARTYPE_NOT_SUPPORTED,  /* VT_INT         [T]       signed machine int          */
81 VARTYPE_NOT_SUPPORTED,  /* VT_UINT        [T]       unsigned machine int        */
82 VARTYPE_NOT_SUPPORTED,  /* VT_VOID        [T]       C style void                        */
83 VARTYPE_NOT_SUPPORTED,  /* VT_HRESULT     [T]       Standard return type        */
84 VARTYPE_NOT_SUPPORTED,  /* VT_PTR         [T]       pointer type                        */
85 VARTYPE_NOT_SUPPORTED,  /* VT_SAFEARRAY   [T]       (use VT_ARRAY in VARIANT)*/
86 VARTYPE_NOT_SUPPORTED,  /* VT_CARRAY      [T]       C style array                       */
87 VARTYPE_NOT_SUPPORTED,  /* VT_USERDEFINED [T]       user defined type                   */
88 VARTYPE_NOT_SUPPORTED,  /* VT_LPSTR       [T][P]    null terminated string      */
89 VARTYPE_NOT_SUPPORTED,  /* VT_LPWSTR      [T][P]    wide null term string               */
90 VARTYPE_NOT_SUPPORTED,  /* VT_FILETIME       [P]    FILETIME                    */
91 VARTYPE_NOT_SUPPORTED,  /* VT_BLOB           [P]    Length prefixed bytes */
92 VARTYPE_NOT_SUPPORTED,  /* VT_STREAM         [P]    Name of stream follows              */
93 VARTYPE_NOT_SUPPORTED,  /* VT_STORAGE        [P]    Name of storage follows     */
94 VARTYPE_NOT_SUPPORTED,  /* VT_STREAMED_OBJECT[P]    Stream contains an object*/
95 VARTYPE_NOT_SUPPORTED,  /* VT_STORED_OBJECT  [P]    Storage contains object*/
96 VARTYPE_NOT_SUPPORTED,  /* VT_BLOB_OBJECT    [P]    Blob contains an object*/
97 VARTYPE_NOT_SUPPORTED,  /* VT_CF             [P]    Clipboard format                    */
98 VARTYPE_NOT_SUPPORTED,  /* VT_CLSID          [P]    A Class ID                  */
99 VARTYPE_NOT_SUPPORTED,  /* VT_VECTOR         [P]    simple counted array                */
100 VARTYPE_NOT_SUPPORTED,  /* VT_ARRAY    [V]          SAFEARRAY*                  */
101 VARTYPE_NOT_SUPPORTED   /* VT_BYREF    [V]          void* for local use */
102 };
103
104 static const int LAST_VARTYPE = sizeof(VARTYPE_SIZE)/sizeof(VARTYPE_SIZE[0]);
105
106
107 /*************************************************************************
108  *              SafeArrayAllocDescriptor (OLEAUT32.36)
109  * Allocate the appropriate amount of memory for the SafeArray descriptor
110  */
111 HRESULT WINAPI SafeArrayAllocDescriptor( 
112   UINT    cDims, 
113   SAFEARRAY **ppsaOut) 
114 {
115   SAFEARRAYBOUND *sab;
116   LONG allocSize = 0;
117
118   /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
119                                              ( in SAFEARRAY struct */
120   allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
121
122   /* Allocate memory for SAFEARRAY struc */
123   if(( (*ppsaOut)=HeapAlloc( 
124         GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
125     return(E_UNEXPECTED);
126   }
127   TRACE("SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
128
129   return(S_OK);
130 }
131
132 /*************************************************************************
133  *              SafeArrayAllocDescriptorEx (OLEAUT32.429)
134  * Allocate the appropriate amount of memory for the SafeArray descriptor
135  *
136  * This is a minimal implementation just to get things moving.
137  *
138  * The MSDN documentation on this doesn't tell us much.
139  */
140 HRESULT WINAPI SafeArrayAllocDescriptorEx( 
141   VARTYPE vt,
142   UINT    cDims, 
143   SAFEARRAY **ppsaOut) 
144 {
145   if ( (vt >= LAST_VARTYPE) ||
146        ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
147     return E_UNEXPECTED;
148
149   return SafeArrayAllocDescriptor (cDims, ppsaOut);
150 }
151
152 /*************************************************************************
153  *              SafeArrayAllocData (OLEAUT32.37)
154  * Allocate the appropriate amount of data for the SafeArray data
155  */
156 HRESULT WINAPI SafeArrayAllocData(
157   SAFEARRAY *psa) 
158 {
159   ULONG  ulWholeArraySize;   /* to store the size of the whole thing */
160
161   if(! validArg(psa)) 
162     return E_INVALIDARG;
163
164   ulWholeArraySize = getArraySize(psa);
165
166   /* Allocate memory for the data itself */
167   if((psa->pvData = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
168         psa->cbElements*ulWholeArraySize)) == NULL)
169     return(E_UNEXPECTED);
170
171   TRACE("SafeArray: %lu bytes allocated for data at %p (%lu objects).\n", 
172     psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
173
174   return(S_OK);
175 }
176
177 /*************************************************************************
178  *              SafeArrayCreate (OLEAUT32.15)
179  * Create a SafeArray object by encapsulating AllocDescriptor and AllocData 
180  */
181 SAFEARRAY* WINAPI SafeArrayCreate(
182   VARTYPE        vt, 
183   UINT         cDims, 
184   SAFEARRAYBOUND *rgsabound)
185 {
186   SAFEARRAY *psa;
187   HRESULT   hRes;
188   USHORT    cDim;
189
190   /* Validate supported VARTYPE */
191   if ( (vt >= LAST_VARTYPE) ||
192        ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
193     return NULL;
194
195   /* Allocate memory for the array descriptor */
196   if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
197     return NULL;
198
199   /* setup data members... */ 
200   psa->cDims     = cDims;
201   psa->fFeatures = getFeatures(vt);
202   psa->cLocks    = 0;
203   psa->pvData    = NULL;
204   psa->cbElements= VARTYPE_SIZE[vt];
205
206   /* Invert the bounds ... */
207   for(cDim=0; cDim < psa->cDims; cDim++) {
208     psa->rgsabound[cDim].cElements = rgsabound[psa->cDims-cDim-1].cElements;
209     psa->rgsabound[cDim].lLbound   = rgsabound[psa->cDims-cDim-1].lLbound;
210   }
211
212   /* allocate memory for the data... */ 
213   if( FAILED( hRes = SafeArrayAllocData(psa))) {
214     SafeArrayDestroyDescriptor(psa); 
215     ERR("() : Failed to allocate the Safe Array data\n");
216     return NULL;
217   }
218
219   return(psa); 
220 }
221
222 /*************************************************************************
223  *              SafeArrayDestroyDescriptor (OLEAUT32.38)
224  * Frees the memory associated with the descriptor.
225  */
226 HRESULT WINAPI SafeArrayDestroyDescriptor(
227   SAFEARRAY *psa)
228 {
229   /* Check for lockness before to free... */
230   if(psa->cLocks > 0) 
231     return DISP_E_ARRAYISLOCKED;
232
233   /* The array is unlocked, then, deallocate memory */
234   if(HeapFree( GetProcessHeap(), 0, psa) == FALSE) 
235     return E_UNEXPECTED;
236   
237   return(S_OK);
238 }
239
240
241 /*************************************************************************
242  *              SafeArrayLock (OLEAUT32.21)
243  * Increment the lock counter
244  *
245  * Doc says (MSDN Library ) that psa->pvData should be made available (!= NULL)
246  * only when psa->cLocks is > 0... I don't get it since pvData is allocated 
247  * before the array is locked, therefore  
248  */
249 HRESULT WINAPI SafeArrayLock(
250   SAFEARRAY *psa)
251 {
252   if(! validArg(psa))     
253     return E_INVALIDARG;
254
255   psa->cLocks++;
256
257   return(S_OK);
258 }
259
260 /*************************************************************************
261  *              SafeArrayUnlock (OLEAUT32.22)
262  * Decrement the lock counter
263  */
264 HRESULT WINAPI SafeArrayUnlock(
265   SAFEARRAY *psa)
266 {
267   if(! validArg(psa)) 
268     return E_INVALIDARG;
269
270   if (psa->cLocks > 0) 
271     psa->cLocks--;
272
273   return(S_OK);
274 }
275
276
277 /*************************************************************************
278  *              SafeArrayPutElement (OLEAUT32.26)
279  * Set the data at the given coordinate
280  */
281 HRESULT WINAPI SafeArrayPutElement(
282   SAFEARRAY *psa, 
283   LONG      *rgIndices, 
284   void      *pv)
285 {
286   ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to 
287                                          the desired one... */
288   PVOID elementStorageAddress = NULL; /* Adress to store the data */
289
290   /* Validate the index given */
291   if(! validCoordinate(rgIndices, psa)) 
292     return DISP_E_BADINDEX;
293   if(! validArg(psa))
294     return E_INVALIDARG;
295
296   if( SafeArrayLock(psa) == S_OK) {
297
298     /* Figure out the number of items to skip */
299     stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
300   
301     /* Figure out the number of byte to skip ... */
302     elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
303   
304     if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
305
306       *((PVOID*)elementStorageAddress) = *(PVOID*)pv; 
307       IUnknown_AddRef( *(IUnknown**)pv);
308
309     } else { 
310
311       if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
312         BSTR pbstrReAllocStr = NULL;
313         if(pv &&
314            ((pbstrReAllocStr = SYSDUPSTRING( (OLECHAR*)pv )) == NULL)) {
315           SafeArrayUnlock(psa);  
316           return E_OUTOFMEMORY;
317         } else 
318           *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
319       }
320       else if(psa->fFeatures == FADF_VARIANT) {
321         HRESULT hr = VariantCopy(elementStorageAddress, pv);
322         if (FAILED(hr)) {
323           SafeArrayUnlock(psa);
324           return hr;
325         }
326       }
327       else /* duplicate the memory */
328         memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
329     }
330
331   } else {
332     ERR("SafeArray: Cannot lock array....\n");
333     return E_UNEXPECTED; /* UNDOC error condition */
334   }
335
336   TRACE("SafeArray: item put at adress %p.\n",elementStorageAddress);
337   return SafeArrayUnlock(psa);  
338 }
339
340
341 /*************************************************************************
342  *              SafeArrayGetElement (OLEAUT32.25)
343  * Return the data element corresponding the the given coordinate
344  */
345 HRESULT WINAPI SafeArrayGetElement(
346   SAFEARRAY *psa, 
347   LONG      *rgIndices, 
348   void      *pv)
349 {
350   ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to 
351                                          the desired one... */
352   PVOID elementStorageAddress = NULL; /* Adress to store the data */
353
354   if(! validArg(psa)) 
355     return E_INVALIDARG;
356   
357   if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
358     return(DISP_E_BADINDEX);
359
360   if( SafeArrayLock(psa) == S_OK) {
361
362     /* Figure out the number of items to skip */
363     stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
364   
365     /* Figure out the number of byte to skip ... */
366     elementStorageAddress = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
367   
368     if( psa->fFeatures == FADF_BSTR) {           /* reallocate the obj */
369       BSTR pbstrStoredStr = *(OLECHAR**)elementStorageAddress;
370       BSTR pbstrReturnedStr = NULL;
371       if( pbstrStoredStr &&
372           ((pbstrReturnedStr = SYSDUPSTRING( pbstrStoredStr )) == NULL) ) {
373         SafeArrayUnlock(psa);
374         return E_OUTOFMEMORY;
375       } else 
376         *((BSTR*)pv) = pbstrReturnedStr; 
377     }
378     else if( psa->fFeatures == FADF_VARIANT) {
379       HRESULT hr;
380       VariantInit(pv);
381       hr = VariantCopy(pv, elementStorageAddress);
382       if (FAILED(hr)) {
383         SafeArrayUnlock(psa);
384         return hr;
385       }
386     }
387     else if( isPointer(psa->fFeatures) )         /* simply copy the pointer */
388       *(PVOID*)pv = *((PVOID*)elementStorageAddress); 
389     else                                         /* copy the bytes */
390       memcpy(pv, elementStorageAddress, psa->cbElements );
391
392   } else {
393     ERR("SafeArray: Cannot lock array....\n");
394     return E_UNEXPECTED; /* UNDOC error condition */
395   }
396
397   return( SafeArrayUnlock(psa) );  
398 }
399
400 /*************************************************************************
401  *              SafeArrayGetUBound (OLEAUT32.19)
402  * return the UP bound for a given array dimension
403  */
404 HRESULT WINAPI SafeArrayGetUBound(
405   SAFEARRAY *psa, 
406   UINT    nDim,
407   LONG      *plUbound)
408 {
409   if(! validArg(psa))   
410     return E_INVALIDARG;
411
412   if(nDim > psa->cDims) 
413     return DISP_E_BADINDEX;
414
415   if(0 == nDim)
416     return DISP_E_BADINDEX;
417
418   *plUbound = psa->rgsabound[nDim-1].lLbound + 
419               psa->rgsabound[nDim-1].cElements - 1;
420
421   return S_OK;
422 }
423
424 /*************************************************************************
425  *              SafeArrayGetLBound (OLEAUT32.20)
426  * Return the LO bound for a given array dimension 
427  */
428 HRESULT WINAPI SafeArrayGetLBound(
429   SAFEARRAY *psa,
430   UINT    nDim, 
431   LONG      *plLbound)
432 {
433   if(! validArg(psa))   
434     return E_INVALIDARG;
435
436   if(nDim > psa->cDims) 
437     return DISP_E_BADINDEX;
438
439   if(0 == nDim)
440     return DISP_E_BADINDEX;
441   
442   *plLbound = psa->rgsabound[nDim-1].lLbound;
443   return S_OK;
444 }
445
446 /*************************************************************************
447  *              SafeArrayGetDim (OLEAUT32.17)
448  * returns the number of dimension in the array
449  */
450 UINT WINAPI SafeArrayGetDim(
451   SAFEARRAY * psa)
452
453   /*
454    * A quick test in Windows shows that the behavior here for an invalid
455    * pointer is to return 0.
456    */
457   if(! validArg(psa)) 
458     return 0;
459
460   return psa->cDims;
461 }
462
463 /*************************************************************************
464  *              SafeArrayGetElemsize (OLEAUT32.18)
465  * Return the size of the element in the array
466  */
467 UINT WINAPI SafeArrayGetElemsize(
468   SAFEARRAY * psa)
469
470   /*
471    * A quick test in Windows shows that the behavior here for an invalid
472    * pointer is to return 0.
473    */
474   if(! validArg(psa)) 
475     return 0;
476
477   return psa->cbElements;
478 }
479
480 /*************************************************************************
481  *              SafeArrayAccessData (OLEAUT32.23)
482  * increment the access count and return the data 
483  */
484 HRESULT WINAPI SafeArrayAccessData(
485   SAFEARRAY *psa, 
486   void      **ppvData)
487
488   HRESULT hRes;
489
490   if(! validArg(psa)) 
491     return E_INVALIDARG;
492
493   hRes = SafeArrayLock(psa);
494
495   switch (hRes) {
496     case S_OK: 
497       (*ppvData) = psa->pvData;
498       break;
499     case E_INVALIDARG:
500       (*ppvData) = NULL;
501       return E_INVALIDARG;
502   }
503   
504   return S_OK;
505 }
506
507
508 /*************************************************************************
509  *              SafeArrayUnaccessData (OLEAUT32.24)
510  * Decrement the access count
511  */
512 HRESULT WINAPI SafeArrayUnaccessData(
513   SAFEARRAY * psa)
514
515   if(! validArg(psa)) 
516     return E_INVALIDARG;
517
518   return(SafeArrayUnlock(psa));
519 }
520
521 /************************************************************************ 
522  *              SafeArrayPtrOfIndex (OLEAUT32.148)
523  * Return a pointer to the element at rgIndices
524  */
525 HRESULT WINAPI SafeArrayPtrOfIndex(
526   SAFEARRAY *psa, 
527   LONG      *rgIndices, 
528   void      **ppvData)
529
530   ULONG stepCountInSAData     = 0;    /* Number of array item to skip to get to 
531                                          the desired one... */
532
533   if(! validArg(psa))                   
534     return E_INVALIDARG;
535
536   if(! validCoordinate(rgIndices, psa)) 
537     return DISP_E_BADINDEX;
538
539   /* Although it is dangerous to do this without having a lock, it is not
540    * illegal.  Microsoft do warn of the danger.
541    */
542
543   /* Figure out the number of items to skip */
544   stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
545   
546   *ppvData = (char *) psa->pvData+(stepCountInSAData*psa->cbElements);
547
548   return S_OK;
549 }
550
551 /************************************************************************ 
552  *              SafeArrayDestroyData (OLEAUT32.39)
553  * Frees the memory data bloc
554  */
555 HRESULT WINAPI SafeArrayDestroyData(
556   SAFEARRAY *psa)
557
558   HRESULT  hRes;
559   ULONG    ulWholeArraySize; /* count spot in array  */
560   ULONG    ulDataIter;       /* to iterate the data space */
561
562   if(! validArg(psa)) 
563     return E_INVALIDARG;
564
565   if(psa->cLocks > 0) 
566     return DISP_E_ARRAYISLOCKED;
567
568   ulWholeArraySize = getArraySize(psa);
569
570   if(isPointer(psa->fFeatures)) {           /* release the pointers */
571     IUnknown *punk;
572
573     for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
574       punk = *(IUnknown**)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));        
575
576       if( punk != NULL) 
577         IUnknown_Release(punk);
578     }
579
580   }
581   else if(psa->fFeatures & FADF_BSTR) {  /* deallocate the obj */
582     BSTR bstr;
583
584     for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
585       bstr = *(BSTR*)((char *) psa->pvData+(ulDataIter*(psa->cbElements)));
586
587       if( bstr != NULL) 
588         SysFreeString( bstr );
589     }
590   }
591   else if(psa->fFeatures & FADF_VARIANT) {  /* deallocate the obj */
592
593     for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
594       VariantClear((VARIANT*)((char *) psa->pvData+(ulDataIter*(psa->cbElements))));
595     }
596   }
597       
598   /* check if this array is a Vector, in which case do not free the data 
599      block since it has been allocated by AllocDescriptor and therefore
600      deserve to be freed by DestroyDescriptor */
601   if(!(psa->fFeatures & FADF_CREATEVECTOR)) { /* Set when we do CreateVector */
602
603     /* free the whole chunk */
604     if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
605       return E_UNEXPECTED; /* UNDOC error condition */
606
607     psa->pvData = NULL;
608   }
609   
610   return S_OK;
611 }
612
613 /************************************************************************ 
614  *              SafeArrayCopyData (OLEAUT32.412)
615  * Copy the psaSource's data block into psaTarget if dimension and size
616  * permits it.
617  */
618 HRESULT WINAPI SafeArrayCopyData(
619   SAFEARRAY *psaSource,
620   SAFEARRAY **psaTarget)
621
622   USHORT   cDimCount;        /* looper */
623   LONG     lDelta;           /* looper */
624   IUnknown *punk;   
625   ULONG    ulWholeArraySize; /* Number of item in SA */
626   BSTR   bstr;
627
628   if(! (validArg(psaSource) && validArg(*psaTarget)) ) 
629     return E_INVALIDARG;
630
631   if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
632     return E_INVALIDARG;
633
634   ulWholeArraySize = getArraySize(psaSource); 
635
636   /* The two arrays boundaries must be of same lenght */
637   for(cDimCount=0;cDimCount < psaSource->cDims; cDimCount++)
638     if( psaSource->rgsabound[cDimCount].cElements != 
639       (*psaTarget)->rgsabound[cDimCount].cElements)
640       return E_INVALIDARG;
641
642   if( isPointer((*psaTarget)->fFeatures) ) {         /* the target contains ptr 
643                                                         that must be released */
644     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
645       punk = *(IUnknown**)
646         ((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
647
648       if( punk != NULL) 
649         IUnknown_Release(punk);
650     }
651
652   }
653   else if( (*psaTarget)->fFeatures & FADF_BSTR) {    /* the target contain BSTR
654                                                         that must be freed */ 
655     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
656       bstr = 
657         *(BSTR*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
658
659       if( bstr != NULL) 
660         SysFreeString( bstr );
661     }
662   }
663   else if( (*psaTarget)->fFeatures & FADF_VARIANT) {
664
665     for(lDelta=0;lDelta < ulWholeArraySize; lDelta++) {
666       VariantClear((VARIANT*)((char *) (*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements)));
667     }
668   }
669
670   return duplicateData(psaSource, psaTarget);
671 }
672
673 /************************************************************************ 
674  *              SafeArrayDestroy (OLEAUT32.16)
675  * Deallocates all memory reserved for the SafeArray
676  */
677 HRESULT WINAPI SafeArrayDestroy(
678   SAFEARRAY * psa)
679
680   HRESULT hRes;
681
682   if(! validArg(psa)) 
683     return E_INVALIDARG;
684
685   if(psa->cLocks > 0) 
686     return DISP_E_ARRAYISLOCKED;
687
688   if((hRes = SafeArrayDestroyData( psa )) == S_OK)
689     if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
690       return S_OK;
691
692   return E_UNEXPECTED; /* UNDOC error condition */
693 }
694
695 /************************************************************************ 
696  *              SafeArrayCopy (OLEAUT32.27)
697  * Make a dupplicate of a SafeArray
698  */
699 HRESULT WINAPI SafeArrayCopy(
700   SAFEARRAY *psa, 
701   SAFEARRAY **ppsaOut)
702
703   HRESULT hRes;
704   DWORD   dAllocSize;
705   ULONG   ulWholeArraySize; /* size of the thing */
706
707   if(! validArg(psa)) 
708     return E_INVALIDARG;
709
710   if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
711
712     /* Duplicate the SAFEARRAY struc */
713     memcpy(*ppsaOut, psa, 
714             sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
715
716     (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
717
718     /* make sure the new safe array doesn't have the FADF_CREATEVECTOR flag,
719        because the data has not been allocated with the descriptor. */
720     (*ppsaOut)->fFeatures &= ~FADF_CREATEVECTOR;  
721  
722     /* Get the allocated memory size for source and allocate it for target */ 
723     ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
724     dAllocSize = ulWholeArraySize*psa->cbElements;
725
726     (*ppsaOut)->pvData = 
727       HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dAllocSize);
728     if( (*ppsaOut)->pvData != NULL) {   /* HeapAlloc succeed */
729
730       if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
731         HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
732         (*ppsaOut)->pvData = NULL;
733         SafeArrayDestroyDescriptor(*ppsaOut);
734         return hRes;
735       }
736         
737     } else { /* failed to allocate or dupplicate... */
738       SafeArrayDestroyDescriptor(*ppsaOut);
739       return E_UNEXPECTED; /* UNDOC error condition */
740     }
741   } else { /* failed to allocate mem for descriptor */
742     return E_OUTOFMEMORY; /* UNDOC error condiftion */
743   }
744
745   return S_OK;
746 }
747
748 /************************************************************************ 
749  *              SafeArrayCreateVector (OLEAUT32.411)
750  * Creates a one dimension safearray where the data is next to the 
751  * SAFEARRAY structure.
752  */
753 SAFEARRAY* WINAPI SafeArrayCreateVector(
754   VARTYPE vt, 
755   LONG    lLbound, 
756   ULONG   cElements) 
757
758   SAFEARRAY *psa;
759
760   /* Validate supported VARTYPE */
761   if ( (vt >= LAST_VARTYPE) ||
762        ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED ) )
763     return NULL;
764
765   /* Allocate memory for the array descriptor and data contiguously  */
766   if( FAILED( psa = HeapAlloc( GetProcessHeap(), 
767                       HEAP_ZERO_MEMORY, 
768                       (sizeof(*psa) + (VARTYPE_SIZE[vt] * cElements))))) {
769     return NULL;
770   }
771                                                                                 
772   /* setup data members... */ 
773   psa->cDims      = 1; /* always and forever */
774   psa->fFeatures  = getFeatures(vt) | FADF_CREATEVECTOR;  /* undocumented flag used by Microsoft */
775   psa->cLocks     = 0;
776   psa->pvData     = (BYTE*)psa + sizeof(*psa);
777   psa->cbElements = VARTYPE_SIZE[vt];
778
779   psa->rgsabound[0].cElements = cElements;
780   psa->rgsabound[0].lLbound   = lLbound;
781
782   return(psa);                            
783
784
785 /************************************************************************ 
786  *              SafeArrayRedim (OLEAUT32.40)
787  * Changes the caracteristics of the last dimension of the SafeArray
788  */
789 HRESULT WINAPI SafeArrayRedim(
790   SAFEARRAY      *psa, 
791   SAFEARRAYBOUND *psaboundNew)
792
793   LONG   lDelta;  /* hold difference in size */
794   USHORT cDims=1; /* dims counter */
795
796   if( !validArg(psa) )                    
797     return E_INVALIDARG;
798
799   if( psa->cLocks > 0 )                    
800     return DISP_E_ARRAYISLOCKED;
801
802   if( psa->fFeatures & FADF_FIXEDSIZE )    
803     return E_INVALIDARG;
804
805   if( SafeArrayLock(psa)==E_UNEXPECTED ) 
806     return E_UNEXPECTED;/* UNDOC error condition */
807
808   /* find the delta in number of array spot to apply to the new array */
809   lDelta = psaboundNew->cElements - psa->rgsabound[0].cElements;
810   for(; cDims < psa->cDims; cDims++)
811     /* delta in number of spot implied by modifying the last dimension */
812     lDelta *= psa->rgsabound[cDims].cElements;
813
814   TRACE("elements=%ld, Lbound=%ld (delta=%ld)\n", psaboundNew->cElements, psaboundNew->lLbound, lDelta);
815
816   if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
817
818   } else /* need to enlarge (lDelta +) reduce (lDelta -) */
819     if(! resizeSafeArray(psa, lDelta)) 
820       return E_UNEXPECTED; /* UNDOC error condition */
821
822   /* the only modifyable dimension sits in [0] as the dimensions were reversed  
823      at array creation time... */
824   psa->rgsabound[0].cElements = psaboundNew->cElements;
825   psa->rgsabound[0].lLbound   = psaboundNew->lLbound;
826
827   return SafeArrayUnlock(psa);
828 }
829
830 /************************************************************************
831  * NOT WINDOWS API - SafeArray* Utility functions
832  ************************************************************************/
833
834 /************************************************************************ 
835  * Used to validate the SAFEARRAY type of arg
836  */
837 static BOOL validArg(
838   SAFEARRAY *psa) 
839 {
840   SAFEARRAYBOUND *sab;
841   LONG psaSize  = 0;
842   LONG descSize = 0;
843   LONG fullSize = 0;
844
845   /*
846    * Let's check for the null pointer just in case.
847    */
848   if (psa == NULL)
849     return FALSE;
850
851   /* Check whether the size of the chunk makes sense... That's the only thing
852      I can think of now... */
853
854   psaSize = HeapSize(GetProcessHeap(), 0, psa);
855   if (psaSize == -1)
856     /* uh, foreign heap. Better don't mess with it ! */
857     return TRUE;
858
859   /* size of the descriptor when the SA is not created with CreateVector */
860   descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
861
862   /* size of the descriptor + data when created with CreateVector */
863   fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
864
865   return((psaSize >= descSize) || (psaSize >= fullSize));
866 }
867
868 /************************************************************************ 
869  * Used to reallocate memory
870  */
871 static BOOL resizeSafeArray(
872   SAFEARRAY *psa, 
873   LONG lDelta)
874 {
875   ULONG    ulWholeArraySize;  /* use as multiplicator */
876   PVOID    pvNewBlock = NULL;  
877   IUnknown *punk;
878   BSTR   bstr;
879
880   ulWholeArraySize = getArraySize(psa);
881
882   if(lDelta < 0) {                    /* array needs to be shorthen  */
883     if( isPointer(psa->fFeatures))    /* ptr that need to be released */
884       for(;lDelta < 0; lDelta++) {
885               punk = *(IUnknown**)
886           ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
887         
888         if( punk != NULL )
889           IUnknown_Release(punk);
890             }
891
892     else if(psa->fFeatures & FADF_BSTR)  /* BSTR that need to be freed */
893       for(;lDelta < 0; lDelta++) {
894         bstr = *(BSTR*)
895           ((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
896
897         if( bstr != NULL )
898           SysFreeString( bstr );
899       }
900     else if(psa->fFeatures & FADF_VARIANT)
901       for(;lDelta < 0; lDelta++) {
902         VariantClear((VARIANT*)((char *) psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements)));
903       }
904   }
905
906   if (!(psa->fFeatures & FADF_CREATEVECTOR))
907   {
908     /* Ok now, if we are enlarging the array, we *MUST* move the whole block 
909        pointed to by pvData.   If we are shorthening the array, this move is
910        optional but we do it anyway becuase the benefit is that we are 
911        releasing to the system the unused memory */
912
913     if((pvNewBlock = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, psa->pvData, 
914        (ulWholeArraySize + lDelta) * psa->cbElements)) == NULL) 
915         return FALSE; /* TODO If we get here it means:
916                          SHRINK situation :  we've deleted the undesired
917                                              data and did not release the memory
918                          GROWING situation:  we've been unable to grow the array
919                       */
920   }
921   else
922   {
923     /* Allocate a new block, because the previous data has been allocated with 
924        the descriptor in SafeArrayCreateVector function. */
925
926     if((pvNewBlock = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
927        ulWholeArraySize * psa->cbElements)) == NULL) 
928         return FALSE;
929
930     psa->fFeatures &= ~FADF_CREATEVECTOR;
931   }
932   /* reassign to the new block of data */
933   psa->pvData = pvNewBlock;
934   return TRUE;
935 }
936
937 /************************************************************************ 
938  * Used to set the fFeatures data member of the SAFEARRAY structure. 
939  */
940 static INT getFeatures(
941   VARTYPE vt) 
942 {
943   switch(vt) {
944     case VT_BSTR:      return FADF_BSTR;
945     case VT_UNKNOWN:   return FADF_UNKNOWN;
946     case VT_DISPATCH:  return FADF_DISPATCH;
947     case VT_VARIANT:   return FADF_VARIANT;
948   }
949   return 0;
950 }
951
952 /************************************************************************ 
953  * Used to figure out if the fFeatures data member of the SAFEARRAY 
954  * structure contain any information about the type of data stored... 
955  */
956 static BOOL isPointer(
957   USHORT feature) 
958 {
959   switch(feature) {
960     case FADF_UNKNOWN:  return TRUE; /* those are pointers */
961     case FADF_DISPATCH: return TRUE;
962   }
963   return FALSE;
964 }
965
966 /************************************************************************ 
967  * Used to calculate the displacement when accessing or modifying 
968  * safearray data set.
969  *
970  *  Parameters: - LONG *coor is the desired location in the multidimension
971  *              table.  Ex for a 3 dim table: coor[] = {1,2,3};
972  *              - ULONG *mat is the format of the table.  Ex for a 3 dim
973  *              table mat[] = {4,4,4};
974  *              - USHORT dim is the number of dimension of the SafeArray
975  */
976 static ULONG calcDisplacement(
977   LONG           *coor, 
978   SAFEARRAYBOUND *mat, 
979   LONG           dim) 
980 {
981   ULONG res = 0;
982   LONG  iterDim;
983
984   for(iterDim=0; iterDim<dim; iterDim++) 
985     /* the -mat[dim] bring coor[dim] relative to 0 for calculation */
986     res += ((coor[iterDim]-mat[iterDim].lLbound) * 
987             endOfDim(coor, mat, iterDim+1, dim));
988
989   TRACE("SafeArray: calculated displacement is %lu.\n", res);
990   return(res);
991 }
992
993 /************************************************************************ 
994  * Recursivity agent for calcDisplacement method.  Used within Put and 
995  * Get methods.
996  */
997 static INT endOfDim(
998   LONG           *coor, 
999   SAFEARRAYBOUND *mat, 
1000   LONG           dim, 
1001   LONG           realDim) 
1002 {
1003   if(dim==realDim) 
1004     return 1;
1005   else 
1006     return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
1007 }
1008
1009
1010 /************************************************************************ 
1011  * Method used to validate the coordinate received in Put and Get 
1012  * methods.
1013  */
1014 static BOOL validCoordinate(
1015   LONG      *coor, 
1016   SAFEARRAY *psa) 
1017 {
1018   INT   iter=0;
1019   LONG    lUBound;
1020   LONG    lLBound;
1021   HRESULT hRes;
1022
1023   if (!psa->cDims) return FALSE;
1024   for(; iter<psa->cDims; iter++) {
1025     TRACE("coor[%d]=%ld\n", iter, coor[iter]);
1026     if((hRes = SafeArrayGetLBound(psa, (iter+1), &lLBound)) != S_OK)
1027       return FALSE;
1028     if((hRes = SafeArrayGetUBound(psa, (iter+1), &lUBound)) != S_OK)
1029       return FALSE;
1030  
1031     if(lLBound > lUBound) 
1032       return FALSE; 
1033
1034     if((coor[iter] < lLBound) || (coor[iter] > lUBound))
1035       return FALSE;
1036   }
1037   return TRUE;
1038 }  
1039
1040 /************************************************************************ 
1041  * Method used to calculate the number of cells of the SA
1042  */
1043 static ULONG getArraySize(
1044   SAFEARRAY *psa) 
1045 {
1046   USHORT cCount; 
1047   ULONG  ulWholeArraySize = 1;
1048
1049   for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
1050     ulWholeArraySize *= psa->rgsabound[cCount].cElements;
1051
1052   return ulWholeArraySize;  
1053 }
1054
1055
1056 /************************************************************************ 
1057  * Method used to handle data space dupplication for Copy32 and CopyData32
1058  */
1059 static HRESULT duplicateData(
1060   SAFEARRAY *psa, 
1061   SAFEARRAY **ppsaOut) 
1062 {
1063   ULONG    ulWholeArraySize; /* size of the thing */
1064   LONG     lDelta;
1065
1066   ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
1067   
1068   SafeArrayLock(*ppsaOut);
1069
1070   if( isPointer(psa->fFeatures) ) {  /* If datatype is object increment 
1071                                         object's reference count */
1072     IUnknown *punk;
1073
1074     for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1075       punk = *(IUnknown**)((char *) psa->pvData+(lDelta * psa->cbElements));
1076
1077       if( punk != NULL)
1078         IUnknown_AddRef(punk);
1079     }
1080
1081     /* Copy the source array data into target array */
1082     memcpy((*ppsaOut)->pvData, psa->pvData, 
1083       ulWholeArraySize*psa->cbElements);
1084
1085   }
1086   else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate 
1087                                              the BSTR in the new array */
1088     BSTR   pbstrReAllocStr = NULL;
1089
1090     for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1091       if(( pbstrReAllocStr = SYSDUPSTRING(
1092             *(BSTR*)((char *) psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
1093
1094         SafeArrayUnlock(*ppsaOut);
1095         return E_OUTOFMEMORY;
1096       }
1097
1098       *((BSTR*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements))) = 
1099         pbstrReAllocStr;
1100     }
1101
1102   }
1103   else if( psa->fFeatures & FADF_VARIANT ) {
1104
1105     for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
1106       VariantCopy((VARIANT*)((char *) (*ppsaOut)->pvData+(lDelta * psa->cbElements)),
1107                   (VARIANT*)((char *) psa->pvData+(lDelta * psa->cbElements)));
1108     }
1109
1110   }
1111   else { /* Simply copy the source array data into target array */
1112
1113     memcpy((*ppsaOut)->pvData, psa->pvData, 
1114       ulWholeArraySize*psa->cbElements);
1115   }
1116
1117   SafeArrayUnlock(*ppsaOut);
1118
1119   return S_OK;
1120 }
1121
1122
1123 /************************************************************************ 
1124  *              SafeArrayGetVarType (OLEAUT32.77)
1125  * Returns the VARTYPE stored in the given safearray
1126  */
1127 HRESULT WINAPI SafeArrayGetVarType(
1128   SAFEARRAY* psa,
1129   VARTYPE*   pvt)
1130 {
1131   HRESULT hr = E_INVALIDARG;
1132   VARTYPE vt = VT_EMPTY;
1133
1134   /* const short VARTYPE_OFFSET = -4; */
1135
1136   if (psa->fFeatures & FADF_HAVEVARTYPE)
1137   {
1138     /* VT tag @ negative offset 4 in the array descriptor */
1139     FIXME("Returning VT_BSTR instead of VT_...\n");
1140     vt = VT_BSTR;
1141   }
1142   else if (psa->fFeatures & FADF_RECORD)
1143   {
1144     vt = VT_RECORD;
1145   }
1146   else if (psa->fFeatures & FADF_BSTR)
1147   {
1148     vt = VT_BSTR;
1149   }
1150   else if (psa->fFeatures & FADF_UNKNOWN)
1151   {
1152     vt = VT_UNKNOWN;
1153   }
1154   else if (psa->fFeatures & FADF_DISPATCH)
1155   {
1156     vt = VT_DISPATCH;
1157   }
1158   else if (psa->fFeatures & FADF_VARIANT)
1159   {
1160     vt = VT_VARIANT;
1161   }
1162
1163   if (vt != VT_EMPTY)
1164   {
1165     *pvt = vt;
1166     hr = S_OK;
1167   }
1168
1169   TRACE("HRESULT = %08lx\n", hr);
1170   return hr;
1171 }