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