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