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