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