Release 990226.
[wine/multimedia.git] / ole / safearray.c
blob1f45159afe315bdaf4c04f8a38038c7703923e90
1 /*************************************************************************
2 * OLE Automation
3 * SafeArray Implementation
5 * This file contains the implementation of the SafeArray interface.
7 * Copyright 1999 Sylvain St-Germain
8 */
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"
20 /* Localy used methods */
21 static INT
22 endOfDim(LONG *coor, SAFEARRAYBOUND *mat, LONG dim, LONG realDim);
24 static ULONG
25 calcDisplacement(LONG *coor, SAFEARRAYBOUND *mat, LONG dim);
27 static BOOL
28 isPointer(USHORT feature);
30 static INT
31 getFeatures(VARTYPE vt);
33 static BOOL
34 validCoordinate(LONG *coor, SAFEARRAY *psa);
36 static BOOL
37 resizeSafeArray(SAFEARRAY *psa, LONG lDelta);
39 static BOOL
40 validArg(SAFEARRAY *psa);
42 static ULONG
43 getArraySize(SAFEARRAY *psa);
45 static HRESULT
46 duplicateData(SAFEARRAY *psa, SAFEARRAY **ppsaOut);
48 /* Association between VARTYPE and their size.
49 A size of zero is defined for the unsupported types. */
51 #define VARTYPE_NOT_SUPPORTED 0
52 static ULONG VARTYPE_SIZE[43] =
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 */
100 /*************************************************************************
101 * Allocate the appropriate amount of memory for the SafeArray descriptor
103 HRESULT WINAPI SafeArrayAllocDescriptor(
104 UINT cDims,
105 SAFEARRAY **ppsaOut)
107 SAFEARRAYBOUND *sab;
108 LONG allocSize = 0;
110 /* SAFEARRAY + SAFEARRAYBOUND * (cDims -1) ( -1 because there is already one
111 ( in SAFEARRAY struct */
112 allocSize = sizeof(**ppsaOut) + (sizeof(*sab) * (cDims-1));
114 /* Allocate memory for SAFEARRAY struc */
115 if(( (*ppsaOut)=HeapAlloc(
116 GetProcessHeap(), HEAP_ZERO_MEMORY, allocSize)) == NULL){
117 return(E_UNEXPECTED);
119 TRACE(ole,"SafeArray: %lu bytes allocated for descriptor.\n", allocSize);
121 return(S_OK);
124 /*************************************************************************
125 * Allocate the appropriate amount of data for the SafeArray data
127 HRESULT WINAPI SafeArrayAllocData(
128 SAFEARRAY *psa)
130 ULONG ulWholeArraySize; /* to store the size of the whole thing */
132 if(! validArg(psa))
133 return E_INVALIDARG;
135 ulWholeArraySize = getArraySize(psa);
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);
142 TRACE(ole, "SafeArray: %lu bytes allocated for data at %p (%lu objects).\n",
143 psa->cbElements*ulWholeArraySize, psa->pvData, ulWholeArraySize);
145 return(S_OK);
148 /*************************************************************************
149 * Create a SafeArray object by encapsulating AllocDescriptor and AllocData
151 SAFEARRAY* WINAPI SafeArrayCreate(
152 VARTYPE vt,
153 UINT cDims,
154 SAFEARRAYBOUND *rgsabound)
156 SAFEARRAY *psa;
157 HRESULT hRes;
158 USHORT cDim;
160 /* Validate supported VARTYPE */
161 if ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED )
162 return NULL;
164 /* Allocate memory for the array descriptor */
165 if( FAILED( hRes = SafeArrayAllocDescriptor(cDims, &psa)))
166 return NULL;
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];
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;
181 /* allocate memory for the data... */
182 if( FAILED( hRes = SafeArrayAllocData(psa))) {
183 SafeArrayDestroyDescriptor(psa);
184 return NULL;
187 return(psa);
190 /*************************************************************************
191 * Frees the memory associated with the descriptor.
193 HRESULT WINAPI SafeArrayDestroyDescriptor(
194 SAFEARRAY *psa)
196 /* Check for lockness before to free... */
197 if(psa->cLocks > 0)
198 return DISP_E_ARRAYISLOCKED;
200 /* The array is unlocked, then, deallocate memory */
201 if(HeapFree( GetProcessHeap(), 0, psa) == FALSE)
202 return E_UNEXPECTED;
204 return(S_OK);
208 /*************************************************************************
209 * Increment the lock counter
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
215 HRESULT WINAPI SafeArrayLock(
216 SAFEARRAY *psa)
218 if(! validArg(psa))
219 return E_INVALIDARG;
221 psa->cLocks++;
223 return(S_OK);
226 /*************************************************************************
227 * Decrement the lock counter
229 HRESULT WINAPI SafeArrayUnlock(
230 SAFEARRAY *psa)
232 if(! validArg(psa))
233 return E_INVALIDARG;
235 if (psa->cLocks > 0)
236 psa->cLocks--;
238 return(S_OK);
242 /*************************************************************************
243 * Set the data at the given coordinate
245 HRESULT WINAPI SafeArrayPutElement(
246 SAFEARRAY *psa,
247 LONG *rgIndices,
248 void *pv)
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 BSTR pbstrReAllocStr = NULL; /* BSTR reallocated */
255 /* Validate the index given */
256 if(! validCoordinate(rgIndices, psa))
257 return DISP_E_BADINDEX;
258 if(! validArg(psa))
259 return E_INVALIDARG;
261 if( SafeArrayLock(psa) == S_OK) {
263 /* Figure out the number of items to skip */
264 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
266 /* Figure out the number of byte to skip ... */
267 elementStorageAddress = psa->pvData+(stepCountInSAData*psa->cbElements);
269 if(isPointer(psa->fFeatures)) { /* increment ref count for this pointer */
271 *((VOID**)elementStorageAddress) = *(VOID**)pv;
272 IUnknown_AddRef( *(IUnknown**)pv);
274 } else {
276 if(psa->fFeatures == FADF_BSTR) { /* Create a new object */
278 if((pbstrReAllocStr = SysAllocString( (OLECHAR*)pv )) == NULL) {
279 SafeArrayUnlock(psa);
280 return E_OUTOFMEMORY;
281 } else
282 *((BSTR*)elementStorageAddress) = pbstrReAllocStr;
284 } else /* dupplicate the memory */
285 memcpy(elementStorageAddress, pv, SafeArrayGetElemsize(psa) );
288 } else {
289 ERR(ole, "SafeArray: Cannot lock array....\n");
290 return E_UNEXPECTED; /* UNDOC error condition */
293 TRACE(ole,"SafeArray: item put at adress %p.\n",elementStorageAddress);
294 return SafeArrayUnlock(psa);
298 /*************************************************************************
299 * Return the data element corresponding the the given coordinate
301 HRESULT WINAPI SafeArrayGetElement(
302 SAFEARRAY *psa,
303 LONG *rgIndices,
304 void *pv)
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 BSTR pbstrReturnedStr = NULL; /* BSTR reallocated */
311 if(! validArg(psa))
312 return E_INVALIDARG;
314 if(! validCoordinate(rgIndices, psa)) /* Validate the index given */
315 return(DISP_E_BADINDEX);
317 if( SafeArrayLock(psa) == S_OK) {
319 /* Figure out the number of items to skip */
320 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
322 /* Figure out the number of byte to skip ... */
323 elementStorageAddress = psa->pvData+(stepCountInSAData*psa->cbElements);
325 if( psa->fFeatures == FADF_BSTR) { /* reallocate the obj */
326 if( (pbstrReturnedStr =
327 SysAllocString( *(OLECHAR**)elementStorageAddress )) == NULL) {
328 SafeArrayUnlock(psa);
329 return E_OUTOFMEMORY;
330 } else
331 *((BSTR*)pv) = pbstrReturnedStr;
333 } else if( isPointer(psa->fFeatures) ) /* simply copy the pointer */
334 pv = *((PVOID*)elementStorageAddress);
335 else /* copy the bytes */
336 memcpy(pv, elementStorageAddress, SafeArrayGetElemsize(psa) );
338 } else {
339 ERR(ole, "SafeArray: Cannot lock array....\n");
340 return E_UNEXPECTED; /* UNDOC error condition */
343 return( SafeArrayUnlock(psa) );
346 /*************************************************************************
347 * return the UP bound for a given array dimension
349 HRESULT WINAPI SafeArrayGetUBound(
350 SAFEARRAY *psa,
351 UINT nDim,
352 LONG *plUbound)
354 if(! validArg(psa))
355 return E_INVALIDARG;
357 if(nDim > psa->cDims)
358 return DISP_E_BADINDEX;
360 *plUbound = psa->rgsabound[nDim].lLbound +
361 psa->rgsabound[nDim].cElements - 1;
363 return S_OK;
366 /*************************************************************************
367 * Return the LO bound for a given array dimension
369 HRESULT WINAPI SafeArrayGetLBound(
370 SAFEARRAY *psa,
371 UINT nDim,
372 LONG *plLbound)
374 if(! validArg(psa))
375 return E_INVALIDARG;
377 if(nDim > psa->cDims)
378 return DISP_E_BADINDEX;
380 *plLbound = psa->rgsabound[nDim].lLbound;
381 return S_OK;
384 /*************************************************************************
385 * returns the number of dimension in the array
387 UINT WINAPI SafeArrayGetDim(
388 SAFEARRAY * psa)
390 return psa->cDims;
393 /*************************************************************************
394 * Return the size of the element in the array
396 UINT WINAPI SafeArrayGetElemsize(
397 SAFEARRAY * psa)
399 return psa->cbElements;
402 /*************************************************************************
403 * increment the access count and return the data
405 HRESULT WINAPI SafeArrayAccessData(
406 SAFEARRAY *psa,
407 void **ppvData)
409 HRESULT hRes;
411 if(! validArg(psa))
412 return E_INVALIDARG;
414 hRes = SafeArrayLock(psa);
416 switch (hRes) {
417 case S_OK:
418 (*ppvData) = psa->pvData;
419 break;
420 case E_INVALIDARG:
421 (*ppvData) = NULL;
422 return E_INVALIDARG;
425 return S_OK;
429 /*************************************************************************
430 * Decrement the access count
432 HRESULT WINAPI SafeArrayUnaccessData(
433 SAFEARRAY * psa)
435 if(! validArg(psa))
436 return E_INVALIDARG;
438 return(SafeArrayUnlock(psa));
441 /************************************************************************
442 * Return a pointer to the element at rgIndices
444 HRESULT WINAPI SafeArrayPtrOfIndex(
445 SAFEARRAY *psa,
446 LONG *rgIndices,
447 void **ppvData)
449 ULONG stepCountInSAData = 0; /* Number of array item to skip to get to
450 the desired one... */
452 if(! validArg(psa))
453 return E_INVALIDARG;
455 if(! validCoordinate(rgIndices, psa))
456 return DISP_E_BADINDEX;
458 /* Figure out the number of items to skip */
459 stepCountInSAData = calcDisplacement(rgIndices, psa->rgsabound, psa->cDims);
461 *ppvData = psa->pvData+(stepCountInSAData*psa->cbElements);
463 return S_OK;
466 /************************************************************************
467 * Frees the memory data bloc
469 HRESULT WINAPI SafeArrayDestroyData(
470 SAFEARRAY *psa)
472 HRESULT hRes;
473 ULONG ulWholeArraySize; /* count spot in array */
474 ULONG ulDataIter; /* to iterate the data space */
475 IUnknown *punk;
476 BSTR bstr;
478 if(! validArg(psa))
479 return E_INVALIDARG;
481 if(psa->cLocks > 0)
482 return DISP_E_ARRAYISLOCKED;
484 ulWholeArraySize = getArraySize(psa);
486 if(isPointer(psa->fFeatures)) { /* release the pointers */
488 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
489 punk = *(IUnknown**)(psa->pvData+(ulDataIter*(psa->cbElements)));
491 if( punk != NULL)
492 IUnknown_Release(punk);
495 } else if(psa->fFeatures & FADF_BSTR) { /* deallocate the obj */
497 for(ulDataIter=0; ulDataIter < ulWholeArraySize; ulDataIter++) {
498 bstr = *(BSTR*)(psa->pvData+(ulDataIter*(psa->cbElements)));
500 if( bstr != NULL)
501 SysFreeString( bstr );
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 */
510 /* free the whole chunk */
511 if((hRes = HeapFree( GetProcessHeap(), 0, psa->pvData)) == 0) /*falied*/
512 return E_UNEXPECTED; /* UNDOC error condition */
514 psa->pvData = NULL;
517 return S_OK;
520 /************************************************************************
521 * Copy the psaSource's data block into psaTarget if dimension and size
522 * permits it.
524 HRESULT WINAPI SafeArrayCopyData(
525 SAFEARRAY *psaSource,
526 SAFEARRAY **psaTarget)
528 USHORT cDimCount; /* looper */
529 LONG lDelta; /* looper */
530 IUnknown *punk;
531 ULONG ulWholeArraySize; /* Number of item in SA */
532 BSTR bstr;
534 if(! (validArg(psaSource) && validArg(*psaTarget)) )
535 return E_INVALIDARG;
537 if(SafeArrayGetDim(psaSource) != SafeArrayGetDim(*psaTarget))
538 return E_INVALIDARG;
540 ulWholeArraySize = getArraySize(psaSource);
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;
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));
554 if( punk != NULL)
555 IUnknown_Release(punk);
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 *(BSTR*)((*psaTarget)->pvData + (lDelta * (*psaTarget)->cbElements));
564 if( bstr != NULL)
565 SysFreeString( bstr );
569 return duplicateData(psaSource, psaTarget);
572 /************************************************************************
573 * Deallocates all memory reserved for the SafeArray
575 HRESULT WINAPI SafeArrayDestroy(
576 SAFEARRAY * psa)
578 HRESULT hRes;
580 if(! validArg(psa))
581 return E_INVALIDARG;
583 if(psa->cLocks > 0)
584 return DISP_E_ARRAYISLOCKED;
586 if((hRes = SafeArrayDestroyData( psa )) == S_OK)
587 if((hRes = SafeArrayDestroyDescriptor( psa )) == S_OK)
588 return S_OK;
590 return E_UNEXPECTED; /* UNDOC error condition */
593 /************************************************************************
594 * Make a dupplicate of a SafeArray
596 HRESULT WINAPI SafeArrayCopy(
597 SAFEARRAY *psa,
598 SAFEARRAY **ppsaOut)
600 HRESULT hRes;
601 DWORD dAllocSize;
603 if(! validArg(psa))
604 return E_INVALIDARG;
606 if((hRes=SafeArrayAllocDescriptor(psa->cDims, ppsaOut)) == S_OK){
608 /* Duplicate the SAFEARRAY struc */
609 memcpy(*ppsaOut, psa,
610 sizeof(*psa)+(sizeof(*(psa->rgsabound))*(psa->cDims-1)));
612 (*ppsaOut)->pvData = NULL; /* do not point to the same data area */
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);
619 if( (*ppsaOut)->pvData != NULL) { /* HeapAlloc succeed */
621 if( (hRes=duplicateData(psa, ppsaOut)) != S_OK) { /* E_OUTOFMEMORY */
622 HeapFree(GetProcessHeap(), 0, (*ppsaOut)->pvData);
623 (*ppsaOut)->pvData = NULL;
624 SafeArrayDestroyDescriptor(*ppsaOut);
625 return hRes;
628 } else { /* failed to allocate or dupplicate... */
629 SafeArrayDestroyDescriptor(*ppsaOut);
630 return E_UNEXPECTED; /* UNDOC error condition */
632 } else { /* failed to allocate mem for descriptor */
633 return E_OUTOFMEMORY; /* UNDOC error condiftion */
636 return S_OK;
639 /************************************************************************
640 * Creates a one dimension safearray where the data is next to the
641 * SAFEARRAY structure.
643 SAFEARRAY* WINAPI SafeArrayCreateVector(
644 VARTYPE vt,
645 LONG lLbound,
646 ULONG cElements)
648 SAFEARRAY *psa;
650 /* Validate supported VARTYPE */
651 if ( VARTYPE_SIZE[vt] == VARTYPE_NOT_SUPPORTED )
652 return NULL;
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;
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];
668 psa->rgsabound[0].cElements = cElements;
669 psa->rgsabound[0].lLbound = lLbound;
671 return(psa);
674 /************************************************************************
675 * Changes the caracteristics of the last dimension of the SafeArray
677 HRESULT WINAPI SafeArrayRedim(
678 SAFEARRAY *psa,
679 SAFEARRAYBOUND *psaboundNew)
681 LONG lDelta; /* hold difference in size */
682 USHORT cDims=1; /* dims counter */
684 if( !validArg(psa) )
685 return E_INVALIDARG;
687 if( psa->cLocks > 0 )
688 return DISP_E_ARRAYISLOCKED;
690 if( psa->fFeatures & FADF_FIXEDSIZE )
691 return E_INVALIDARG;
693 if( SafeArrayLock(psa)==E_UNEXPECTED )
694 return E_UNEXPECTED;/* UNDOC error condition */
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;
702 if (lDelta == 0) { ;/* same size, maybe a change of lLbound, just set it */
704 } else /* need to enlarge (lDelta +) reduce (lDelta -) */
705 if(! resizeSafeArray(psa, lDelta))
706 return E_UNEXPECTED; /* UNDOC error condition */
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;
713 return SafeArrayUnlock(psa);
716 /************************************************************************
717 * NOT WINDOWS API - SafeArray* Utility functions
718 ************************************************************************/
720 /************************************************************************
721 * Used to validate the SAFEARRAY type of arg
723 static BOOL validArg(
724 SAFEARRAY *psa)
726 SAFEARRAYBOUND *sab;
727 LONG psaSize = 0;
728 LONG descSize = 0;
729 LONG fullSize = 0;
731 /* Check whether the size of the chunk make sens... That's the only thing
732 I can think of now... */
734 psaSize = HeapSize(GetProcessHeap(), 0, psa);
736 /* size of the descriptor when the SA is not created with CreateVector */
737 descSize = sizeof(*psa) + (sizeof(*sab) * (psa->cDims-1));
739 /* size of the descriptor + data when created with CreateVector */
740 fullSize = sizeof(*psa) + (psa->cbElements * psa->rgsabound[0].cElements);
742 return((psaSize == descSize) | (psaSize == fullSize));
745 /************************************************************************
746 * Used to reallocate memory
748 static BOOL resizeSafeArray(
749 SAFEARRAY *psa,
750 LONG lDelta)
752 ULONG ulWholeArraySize; /* use as multiplicator */
753 PVOID pvNewBlock = NULL;
754 IUnknown *punk;
755 BSTR bstr;
757 ulWholeArraySize = getArraySize(psa);
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));
765 if( punk != NULL )
766 IUnknown_Release(punk);
769 else if(psa->fFeatures & FADF_BSTR) /* BSTR that need to be freed */
770 for(;lDelta < 0; lDelta++) {
771 bstr = *(BSTR*)
772 (psa->pvData+((ulWholeArraySize+lDelta)*psa->cbElements));
774 if( bstr != NULL )
775 SysFreeString( bstr );
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 */
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
792 /* reassign to the new block of data */
793 psa->pvData = pvNewBlock;
794 return TRUE;
797 /************************************************************************
798 * Used to set the fFeatures data member of the SAFEARRAY structure.
800 static INT getFeatures(
801 VARTYPE vt)
803 switch(vt) {
804 case VT_UNKNOWN: return FADF_UNKNOWN;
805 case VT_DISPATCH: return FADF_DISPATCH;
806 case VT_BSTR: return FADF_BSTR;
808 return 0;
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...
815 static BOOL isPointer(
816 USHORT feature)
818 switch(feature) {
819 case FADF_UNKNOWN: return TRUE; /* those are pointers */
820 case FADF_DISPATCH: return TRUE;
822 return FALSE;
825 /************************************************************************
826 * Used to calculate the displacement when accessing or modifying
827 * safearray data set.
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
835 static ULONG calcDisplacement(
836 LONG *coor,
837 SAFEARRAYBOUND *mat,
838 LONG dim)
840 ULONG res = 0;
841 LONG iterDim;
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));
848 TRACE(ole, "SafeArray: calculated displacement is %lu.\n", res);
849 return(res);
852 /************************************************************************
853 * Recursivity agent for calcDisplacement method. Used within Put and
854 * Get methods.
856 static INT endOfDim(
857 LONG *coor,
858 SAFEARRAYBOUND *mat,
859 LONG dim,
860 LONG realDim)
862 if(dim==realDim)
863 return 1;
864 else
865 return (endOfDim(coor, mat, dim+1, realDim) * mat[dim].cElements);
869 /************************************************************************
870 * Method used to validate the coordinate received in Put and Get
871 * methods.
873 static BOOL validCoordinate(
874 LONG *coor,
875 SAFEARRAY *psa)
877 INT iter=0;
878 LONG lUBound;
879 LONG lLBound;
880 HRESULT hRes;
882 for(; iter<psa->cDims; iter++) {
883 if((hRes = SafeArrayGetLBound(psa, iter, &lLBound)) != S_OK)
884 return FALSE;
885 if((hRes = SafeArrayGetUBound(psa, iter, &lUBound)) != S_OK)
886 return FALSE;
888 if(lLBound == lUBound)
889 return FALSE;
891 if((coor[iter] >= lLBound) && (coor[iter] <= lUBound))
892 return TRUE;
893 else
894 return FALSE;
896 return FALSE;
899 /************************************************************************
900 * Method used to calculate the number of cells of the SA
902 static ULONG getArraySize(
903 SAFEARRAY *psa)
905 USHORT cCount;
906 ULONG ulWholeArraySize = 1;
908 for(cCount=0; cCount < psa->cDims; cCount++) /* foreach dimensions... */
909 ulWholeArraySize *= psa->rgsabound[cCount].cElements;
911 return ulWholeArraySize;
915 /************************************************************************
916 * Method used to handle data space dupplication for Copy32 and CopyData32
918 static HRESULT duplicateData(
919 SAFEARRAY *psa,
920 SAFEARRAY **ppsaOut)
922 ULONG ulWholeArraySize; /* size of the thing */
923 LONG lDelta;
924 IUnknown *punk;
925 BSTR pbstrReAllocStr = NULL; /* BSTR reallocated */
927 ulWholeArraySize = getArraySize(psa); /* Number of item in SA */
929 SafeArrayLock(*ppsaOut);
931 if( isPointer(psa->fFeatures) ) { /* If datatype is object increment
932 object's reference count */
934 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
935 punk = *(IUnknown**)(psa->pvData+(lDelta * psa->cbElements));
937 if( punk != NULL)
938 IUnknown_AddRef(punk);
941 /* Copy the source array data into target array */
942 memcpy((*ppsaOut)->pvData, psa->pvData,
943 ulWholeArraySize*psa->cbElements);
945 } else if( psa->fFeatures & FADF_BSTR ) { /* if datatype is BSTR allocate
946 the BSTR in the new array */
948 for(lDelta=0; lDelta < ulWholeArraySize; lDelta++) {
949 if(( pbstrReAllocStr = SysAllocString(
950 *(BSTR*)(psa->pvData+(lDelta * psa->cbElements)))) == NULL) {
952 SafeArrayUnlock(*ppsaOut);
953 return E_OUTOFMEMORY;
956 *((BSTR*)((*ppsaOut)->pvData+(lDelta * psa->cbElements))) =
957 pbstrReAllocStr;
960 } else { /* Simply copy the source array data into target array */
962 memcpy((*ppsaOut)->pvData, psa->pvData,
963 ulWholeArraySize*psa->cbElements);
966 SafeArrayUnlock(*ppsaOut);
968 return S_OK;