source: trunk/src/oleaut32/variant.c@ 10629

Last change on this file since 10629 was 10629, checked in by cinc, 21 years ago

Cinc:
o Rewrote VarNumFromParseNum()
o Added VarDecFromStr() from Wine.
o VarParseNumFromStr() updated with Wine code
o Updated DECIMAL struct (include\win\windef.h) to Wine level.
o updated V_DECIMAL(A) macro (oleaut.h) to Wine level.

Added stubs for:

VarDecAdd()
VarDecMul()
VarDecSub()
VarDecAbs()
VarDecFix()
VarDecInt()
VarDecNeg()
VarDecRound()
VarDecCmp()
VarDecCmpR8()
VarOr()
VarNeg()
VarEqv()
VarIdiv()
VarAbs()
VarMod()
VarImp()
VarFix()
VarRound()
VarInt()
VarFormatNumber()
VarFormatPercent()
VarWeekdayName()
VarMonthName()

Added from Wine:

VarPow()
VarXor()
VarAdd()

svl:
o Added VT_R8 support to VarCmp

File size: 216.1 KB
Line 
1/*
2 * VARIANT
3 *
4 * Copyright 1998 Jean-Claude Cote
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * NOTES
21 * This implements the low-level and hi-level APIs for manipulating VARIANTs.
22 * The low-level APIs are used to do data coercion between different data types.
23 * The hi-level APIs are built on top of these low-level APIs and handle
24 * initialization, copying, destroying and changing the type of VARIANTs.
25 *
26 * TODO:
27 * - The Variant APIs do not support international languages, currency
28 * types, number formating and calendar. They only support U.S. English format.
29 * - The Variant APIs do not the following types: IUknown, IDispatch, DECIMAL and SafeArray.
30 * The prototypes for these are commented out in the oleauto.h file. They need
31 * to be implemented and cases need to be added to the switches of the existing APIs.
32 * - The parsing of date for the VarDateFromStr is not complete.
33 * - The date manipulations do not support dates prior to 1900.
34 * - The parsing does not accept as many formats as the Windows implementation.
35 */
36
37#include "config.h"
38
39#include <string.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <math.h>
43#include <time.h>
44
45#ifdef HAVE_FLOAT_H
46# include <float.h>
47#endif
48
49#include "windef.h"
50#include "oleauto.h"
51#include "heap.h"
52#include "wine/debug.h"
53#include "winerror.h"
54#include "parsedt.h"
55#include "typelib.h"
56
57WINE_DEFAULT_DEBUG_CHANNEL(ole);
58
59#define SYSDUPSTRING(str) SysAllocStringLen((str), SysStringLen(str))
60
61#ifndef FLT_MAX
62# ifdef MAXFLOAT
63# define FLT_MAX MAXFLOAT
64# else
65# error "Can't find #define for MAXFLOAT/FLT_MAX"
66# endif
67#endif
68
69#undef CHAR_MAX
70#undef CHAR_MIN
71static const char CHAR_MAX = 127;
72static const char CHAR_MIN = -128;
73static const BYTE UI1_MAX = 255;
74static const BYTE UI1_MIN = 0;
75static const unsigned short UI2_MAX = 65535;
76static const unsigned short UI2_MIN = 0;
77static const short I2_MAX = 32767;
78static const short I2_MIN = -32768;
79static const unsigned long UI4_MAX = 4294967295U;
80static const unsigned long UI4_MIN = 0;
81static const long I4_MAX = 2147483647;
82static const long I4_MIN = -(2147483648U);
83static const DATE DATE_MIN = -657434;
84static const DATE DATE_MAX = 2958465;
85
86
87/* This mask is used to set a flag in wReserved1 of
88 * the VARIANTARG structure. The flag indicates if
89 * the API function is using an inner variant or not.
90 */
91#define PROCESSING_INNER_VARIANT 0x0001
92
93/* General use buffer.
94 */
95#define BUFFER_MAX 1024
96static char pBuffer[BUFFER_MAX];
97
98/*
99 * Note a leap year is one that is a multiple of 4
100 * but not of a 100. Except if it is a multiple of
101 * 400 then it is a leap year.
102 */
103
104/*
105 * Use 365 days/year and a manual calculation for leap year days
106 * to keep arithmetic simple
107 */
108static const double DAYS_IN_ONE_YEAR = 365.0;
109
110/*
111 * Token definitions for Varient Formatting
112 * Worked out by experimentation on a w2k machine. Doesnt appear to be
113 * documented anywhere obviously so keeping definitions internally
114 *
115 */
116/* Pre defined tokens */
117#define TOK_COPY 0x00
118#define TOK_END 0x02
119#define LARGEST_TOKENID 6
120
121/* Mapping of token name to id put into the tokenized form
122 Note testing on W2K shows aaaa and oooo are not parsed??!! */
123#define TOK_COLON 0x03
124#define TOK_SLASH 0x04
125#define TOK_c 0x05
126#define TOK_d 0x08
127#define TOK_dd 0x09
128#define TOK_ddd 0x0a
129#define TOK_dddd 0x0b
130#define TOK_ddddd 0x0c
131#define TOK_dddddd 0x0d
132#define TOK_w 0x0f
133#define TOK_ww 0x10
134#define TOK_m 0x11
135#define TOK_mm 0x12
136#define TOK_mmm 0x13
137#define TOK_mmmm 0x14
138#define TOK_q 0x06
139#define TOK_y 0x15
140#define TOK_yy 0x16
141#define TOK_yyyy 0x18
142#define TOK_h 0x1e
143#define TOK_Hh 0x1f
144#define TOK_N 0x1a
145#define TOK_Nn 0x1b
146#define TOK_S 0x1c
147#define TOK_Ss 0x1d
148#define TOK_ttttt 0x07
149#define TOK_AMsPM 0x2f
150#define TOK_amspm 0x32
151#define TOK_AsP 0x30
152#define TOK_asp 0x33
153#define TOK_AMPM 0x2e
154
155typedef struct tagFORMATTOKEN {
156 char *str;
157 BYTE tokenSize;
158 BYTE tokenId;
159 int varTypeRequired;
160} FORMATTOKEN;
161
162typedef struct tagFORMATHDR {
163 BYTE len;
164 BYTE hex3;
165 BYTE hex6;
166 BYTE reserved[8];
167} FORMATHDR;
168
169FORMATTOKEN formatTokens[] = { /* FIXME: Only date formats so far */
170 {":" , 1, TOK_COLON , 0},
171 {"/" , 1, TOK_SLASH , 0},
172 {"c" , 1, TOK_c , VT_DATE},
173 {"dddddd", 6, TOK_dddddd , VT_DATE},
174 {"ddddd" , 5, TOK_ddddd , VT_DATE},
175 {"dddd" , 4, TOK_dddd , VT_DATE},
176 {"ddd" , 3, TOK_ddd , VT_DATE},
177 {"dd" , 2, TOK_dd , VT_DATE},
178 {"d" , 1, TOK_d , VT_DATE},
179 {"ww" , 2, TOK_ww , VT_DATE},
180 {"w" , 1, TOK_w , VT_DATE},
181 {"mmmm" , 4, TOK_mmmm , VT_DATE},
182 {"mmm" , 3, TOK_mmm , VT_DATE},
183 {"mm" , 2, TOK_mm , VT_DATE},
184 {"m" , 1, TOK_m , VT_DATE},
185 {"q" , 1, TOK_q , VT_DATE},
186 {"yyyy" , 4, TOK_yyyy , VT_DATE},
187 {"yy" , 2, TOK_yy , VT_DATE},
188 {"y" , 1, TOK_y , VT_DATE},
189 {"h" , 1, TOK_h , VT_DATE},
190 {"Hh" , 2, TOK_Hh , VT_DATE},
191 {"Nn" , 2, TOK_Nn , VT_DATE},
192 {"N" , 1, TOK_N , VT_DATE},
193 {"S" , 1, TOK_S , VT_DATE},
194 {"Ss" , 2, TOK_Ss , VT_DATE},
195 {"ttttt" , 5, TOK_ttttt , VT_DATE},
196 {"AM/PM" , 5, TOK_AMsPM , VT_DATE},
197 {"am/pm" , 5, TOK_amspm , VT_DATE},
198 {"A/P" , 3, TOK_AsP , VT_DATE},
199 {"a/p" , 3, TOK_asp , VT_DATE},
200 {"AMPM" , 4, TOK_AMPM , VT_DATE},
201 {0x00 , 0, 0 , VT_NULL}
202};
203
204
205/************** Form wine: oleaut32/variant.h **************/
206
207/* Value of sign for a positive decimal number */
208#define DECIMAL_POS 0
209
210/* Native headers don't change the union ordering for DECIMAL sign/scale (duh).
211 * This means that the signscale member is only useful for setting both members to 0.
212 * SIGNSCALE creates endian-correct values so that we can properly set both at once
213 * to values other than 0.
214 */
215#ifdef WORDS_BIGENDIAN
216#define SIGNSCALE(sign,scale) (((scale) << 8) | sign)
217#else
218#define SIGNSCALE(sign,scale) (((sign) << 8) | scale)
219#endif
220/* Macros for getting at a DECIMAL's parts */
221#define DEC_SIGN(d) ((d)->u.s.sign)
222#define DEC_SCALE(d) ((d)->u.s.scale)
223#define DEC_SIGNSCALE(d) ((d)->u.signscale)
224#define DEC_HI32(d) ((d)->Hi32)
225#define DEC_MID32(d) ((d)->u1.s1.Mid32)
226#define DEC_LO32(d) ((d)->u1.s1.Lo32)
227#define DEC_LO64(d) ((d)->u1.Lo64)
228
229/* DECIMAL */
230#define _VarDecFromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_DECIMAL)
231/* R8 (double) */
232#define _VarR8FromStr(str,lcid,flags,out) VARIANT_NumberFromBstr(str,lcid,flags,(BYTE*)out,VT_R8)
233
234/* Internal flags for low level conversion functions */
235#define VAR_BOOLONOFF 0x0400 /* Convert bool to "On"/"Off" */
236#define VAR_BOOLYESNO 0x0800 /* Convert bool to "Yes"/"No" */
237#define VAR_NEGATIVE 0x1000 /* Number is negative */
238
239/* The localised characters that make up a valid number */
240typedef struct tagVARIANT_NUMBER_CHARS
241{
242 WCHAR cNegativeSymbol;
243 WCHAR cPositiveSymbol;
244 WCHAR cDecimalPoint;
245 WCHAR cDigitSeperator;
246 WCHAR cCurrencyLocal;
247 WCHAR cCurrencyLocal2;
248 WCHAR cCurrencyDecimalPoint;
249 WCHAR cCurrencyDigitSeperator;
250} VARIANT_NUMBER_CHARS;
251
252void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS*,LCID,DWORD);
253/********** End of Form wine: oleaut32/variant.h ************/
254
255/* Write a number from a UI8 and sign */
256#ifdef __WIN32OS2__
257static WCHAR *VARIANT_WriteNumber(ULONG ulVal, WCHAR* szOut)
258{
259 //FIXME("%s: Hack! No real ULONG64 support here, using ULONG instead. ulVal=%x!!\n", __FUNCTION__, ulVal);
260#else
261static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
262 {
263#endif
264
265 do
266 {
267 WCHAR ulNextDigit = ulVal % 10;
268
269 *szOut-- = '0' + ulNextDigit;
270 ulVal = (ulVal - ulNextDigit) / 10;
271 } while (ulVal);
272
273 szOut++;
274 return szOut;
275}
276
277/* Create a (possibly localised) BSTR from a UI8 and sign */
278static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
279{
280 WCHAR szConverted[256];
281
282 if (dwFlags & VAR_NEGATIVE)
283 *--szOut = '-';
284
285 if (dwFlags & LOCALE_USE_NLS)
286 {
287 /* Format the number for the locale */
288 szConverted[0] = '\0';
289 GetNumberFormatW(lcid,
290 dwFlags & LOCALE_NOUSEROVERRIDE,
291 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
292 szOut = szConverted;
293 }
294 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
295}
296
297
298/******************************************************************************
299 * VarBstrFromDec (OLEAUT32.232)
300 *
301 * Convert a VT_DECIMAL to a VT_BSTR.
302 *
303 * PARAMS
304 * pDecIn [I] Source
305 * lcid [I] LCID for the conversion
306 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
307 * pbstrOut [O] Destination
308 *
309 * RETURNS
310 * Success: S_OK.
311 * Failure: E_INVALIDARG, if pbstrOut is invalid.
312 * E_OUTOFMEMORY, if memory allocation fails.
313 */
314HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
315{
316 TRACE("%s: entering function. pDecIn->lo32: %x, pDecIn->Mid32: %x, pDecIn->Hi32: %x, sign: %x, dwFlags: %x\n",
317 __FUNCTION__, DEC_LO32(pDecIn), DEC_MID32(pDecIn), DEC_HI32(pDecIn), DEC_SIGN(pDecIn), dwFlags);
318 if (!pbstrOut)
319 return E_INVALIDARG;
320
321 if (!DEC_SCALE(pDecIn) && !DEC_HI32(pDecIn))
322 {
323 WCHAR szBuff[256], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
324
325 /* Create the basic number string */
326 *szOut-- = '\0';
327
328
329#ifdef __WIN32OS2__
330 szOut = VARIANT_WriteNumber(DEC_LO32(pDecIn), szOut);
331#else
332 szOut = VARIANT_WriteNumber(DEC_LO64(pDecIn), szOut);
333#endif
334 if (DEC_SIGN(pDecIn))
335 dwFlags |= VAR_NEGATIVE;
336
337 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
338 TRACE("%s: returning %s\n", __FUNCTION__, debugstr_w(*pbstrOut));
339 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
340 }
341 FIXME("semi-stub\n");
342 return E_INVALIDARG;
343}
344
345
346/* Copy data from one variant to another. */
347static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
348{
349 // TRACE("%s: entering function.\n", __FUNCTION__);
350 switch (vt)
351 {
352 case VT_I1:
353 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
354 case VT_BOOL:
355 case VT_I2:
356 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
357 case VT_R4:
358 case VT_INT:
359 case VT_I4:
360 case VT_UINT:
361 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
362 case VT_R8:
363 case VT_DATE:
364 case VT_CY:
365 case VT_I8:
366#ifdef __WIN32OS2__
367 /* case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONGLONG)); break; */
368 /* case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break; */
369 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
370#else
371 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONGLONG)); break;
372 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
373 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
374#endif
375 default:
376 FIXME("%s: VT_ type %d unhandled, please report!\n", __FUNCTION__, vt);
377 }
378}
379
380/* Form wine: oleaut32/vartype.c */
381/* Coerce VT_BSTR to a numeric type */
382HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
383 void* pOut, VARTYPE vt)
384{
385 VARIANTARG dstVar;
386 HRESULT hRet;
387 NUMPARSE np;
388 BYTE rgb[1024];
389
390 TRACE("%s: (StrIn: %s, LCID: 0x%08lx, ulFlags: 0x%08lx )\n", __FUNCTION__, pStrIn, lcid, ulFlags );
391
392 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
393 np.cDig = sizeof(rgb) / sizeof(BYTE);
394 np.dwInFlags = NUMPRS_STD;
395
396 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
397
398 if (SUCCEEDED(hRet))
399 {
400 /* 1 << vt gives us the VTBIT constant for the destination number type */
401 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
402 if (SUCCEEDED(hRet)) {
403 VARIANT_CopyData(&dstVar, vt, pOut);
404 TRACE("%s: Returning dstVar-> type : %x", __FUNCTION__, V_VT(&dstVar));
405 }
406 }
407 return hRet;
408}
409
410
411/******************************************************************************
412 * DateTimeStringToTm [INTERNAL]
413 *
414 * Converts a string representation of a date and/or time to a tm structure.
415 *
416 * Note this function uses the postgresql date parsing functions found
417 * in the parsedt.c file.
418 *
419 * Returns TRUE if successful.
420 *
421 * Note: This function does not parse the day of the week,
422 * daylight savings time. It will only fill the followin fields in
423 * the tm struct, tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
424 *
425 ******************************************************************************/
426static BOOL DateTimeStringToTm( OLECHAR* strIn, DWORD dwFlags, struct tm* pTm )
427{
428 BOOL res = FALSE;
429 double fsec;
430 int tzp;
431 int dtype;
432 int nf;
433 char *field[MAXDATEFIELDS];
434 int ftype[MAXDATEFIELDS];
435 char lowstr[MAXDATELEN + 1];
436 char* strDateTime = NULL;
437
438 /* Convert the string to ASCII since this is the only format
439 * postgesql can handle.
440 */
441 strDateTime = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
442
443 if( strDateTime != NULL )
444 {
445 /* Make sure we don't go over the maximum length
446 * accepted by postgesql.
447 */
448 if( strlen( strDateTime ) <= MAXDATELEN )
449 {
450 if( ParseDateTime( strDateTime, lowstr, field, ftype, MAXDATEFIELDS, &nf) == 0 )
451 {
452 if( dwFlags & VAR_DATEVALUEONLY )
453 {
454 /* Get the date information.
455 * It returns 0 if date information was
456 * present and 1 if only time information was present.
457 * -1 if an error occures.
458 */
459 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) == 0 )
460 {
461 /* Eliminate the time information since we
462 * were asked to get date information only.
463 */
464 pTm->tm_sec = 0;
465 pTm->tm_min = 0;
466 pTm->tm_hour = 0;
467 res = TRUE;
468 }
469 }
470 if( dwFlags & VAR_TIMEVALUEONLY )
471 {
472 /* Get time information only.
473 */
474 if( DecodeTimeOnly(field, ftype, nf, &dtype, pTm, &fsec) == 0 )
475 {
476 res = TRUE;
477 }
478 }
479 else
480 {
481 /* Get both date and time information.
482 * It returns 0 if date information was
483 * present and 1 if only time information was present.
484 * -1 if an error occures.
485 */
486 if( DecodeDateTime(field, ftype, nf, &dtype, pTm, &fsec, &tzp) != -1 )
487 {
488 res = TRUE;
489 }
490 }
491 }
492 }
493 HeapFree( GetProcessHeap(), 0, strDateTime );
494 }
495
496 return res;
497}
498
499
500
501
502
503
504/******************************************************************************
505 * TmToDATE [INTERNAL]
506 *
507 * The date is implemented using an 8 byte floating-point number.
508 * Days are represented by whole numbers increments starting with 0.00 has
509 * being December 30 1899, midnight.
510 * The hours are expressed as the fractional part of the number.
511 * December 30 1899 at midnight = 0.00
512 * January 1 1900 at midnight = 2.00
513 * January 4 1900 at 6 AM = 5.25
514 * January 4 1900 at noon = 5.50
515 * December 29 1899 at midnight = -1.00
516 * December 18 1899 at midnight = -12.00
517 * December 18 1899 at 6AM = -12.25
518 * December 18 1899 at 6PM = -12.75
519 * December 19 1899 at midnight = -11.00
520 * The tm structure is as follows:
521 * struct tm {
522 * int tm_sec; seconds after the minute - [0,59]
523 * int tm_min; minutes after the hour - [0,59]
524 * int tm_hour; hours since midnight - [0,23]
525 * int tm_mday; day of the month - [1,31]
526 * int tm_mon; months since January - [0,11]
527 * int tm_year; years
528 * int tm_wday; days since Sunday - [0,6]
529 * int tm_yday; days since January 1 - [0,365]
530 * int tm_isdst; daylight savings time flag
531 * };
532 *
533 * Note: This function does not use the tm_wday, tm_yday, tm_wday,
534 * and tm_isdst fields of the tm structure. And only converts years
535 * after 1900.
536 *
537 * Returns TRUE if successful.
538 */
539static BOOL TmToDATE( struct tm* pTm, DATE *pDateOut )
540{
541 int leapYear = 0;
542
543 /* Hmmm... An uninitialized Date in VB is December 30 1899 so
544 Start at 0. This is the way DATE is defined. */
545
546 /* Start at 1. This is the way DATE is defined.
547 * January 1, 1900 at Midnight is 1.00.
548 * January 1, 1900 at 6AM is 1.25.
549 * and so on.
550 */
551 *pDateOut = 1;
552
553 if( (pTm->tm_year - 1900) >= 0 ) {
554
555 /* Add the number of days corresponding to
556 * tm_year.
557 */
558 *pDateOut += (pTm->tm_year - 1900) * 365;
559
560 /* Add the leap days in the previous years between now and 1900.
561 * Note a leap year is one that is a multiple of 4
562 * but not of a 100. Except if it is a multiple of
563 * 400 then it is a leap year.
564 * Copied + reversed functionality into TmToDate
565 */
566 *pDateOut += ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
567 *pDateOut -= ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
568 *pDateOut += ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
569
570 /* Set the leap year flag if the
571 * current year specified by tm_year is a
572 * leap year. This will be used to add a day
573 * to the day count.
574 */
575 if( isleap( pTm->tm_year ) )
576 leapYear = 1;
577
578 /* Add the number of days corresponding to
579 * the month. (remember tm_mon is 0..11)
580 */
581 switch( pTm->tm_mon )
582 {
583 case 1:
584 *pDateOut += 31;
585 break;
586 case 2:
587 *pDateOut += ( 59 + leapYear );
588 break;
589 case 3:
590 *pDateOut += ( 90 + leapYear );
591 break;
592 case 4:
593 *pDateOut += ( 120 + leapYear );
594 break;
595 case 5:
596 *pDateOut += ( 151 + leapYear );
597 break;
598 case 6:
599 *pDateOut += ( 181 + leapYear );
600 break;
601 case 7:
602 *pDateOut += ( 212 + leapYear );
603 break;
604 case 8:
605 *pDateOut += ( 243 + leapYear );
606 break;
607 case 9:
608 *pDateOut += ( 273 + leapYear );
609 break;
610 case 10:
611 *pDateOut += ( 304 + leapYear );
612 break;
613 case 11:
614 *pDateOut += ( 334 + leapYear );
615 break;
616 }
617 /* Add the number of days in this month.
618 */
619 *pDateOut += pTm->tm_mday;
620
621 /* Add the number of seconds, minutes, and hours
622 * to the DATE. Note these are the fracionnal part
623 * of the DATE so seconds / number of seconds in a day.
624 */
625 } else {
626 *pDateOut = 0;
627 }
628
629 *pDateOut += pTm->tm_hour / 24.0;
630 *pDateOut += pTm->tm_min / 1440.0;
631 *pDateOut += pTm->tm_sec / 86400.0;
632 return TRUE;
633}
634
635/******************************************************************************
636 * DateToTm [INTERNAL]
637 *
638 * This function converts a windows DATE to a tm structure.
639 *
640 * It does not fill all the fields of the tm structure.
641 * Here is a list of the fields that are filled:
642 * tm_sec, tm_min, tm_hour, tm_year, tm_day, tm_mon.
643 *
644 * Note this function does not support dates before the January 1, 1900
645 * or ( dateIn < 2.0 ).
646 *
647 * Returns TRUE if successful.
648 */
649BOOL DateToTm( DATE dateIn, DWORD dwFlags, struct tm* pTm )
650{
651 double decimalPart = 0.0;
652 double wholePart = 0.0;
653
654 memset(pTm,0,sizeof(*pTm));
655
656 /* Because of the nature of DATE format which
657 * associates 2.0 to January 1, 1900. We will
658 * remove 1.0 from the whole part of the DATE
659 * so that in the following code 1.0
660 * will correspond to January 1, 1900.
661 * This simplifies the processing of the DATE value.
662 */
663 decimalPart = fmod( dateIn, 1.0 ); /* Do this before the -1, otherwise 0.xx goes negative */
664 dateIn -= 1.0;
665 wholePart = (double) floor( dateIn );
666
667 if( !(dwFlags & VAR_TIMEVALUEONLY) )
668 {
669 unsigned int nDay = 0;
670 int leapYear = 0;
671 double yearsSince1900 = 0;
672
673 /* Hard code dates smaller than January 1, 1900. */
674 if( dateIn < 2.0 ) {
675 pTm->tm_year = 1899;
676 pTm->tm_mon = 11; /* December as tm_mon is 0..11 */
677 if( dateIn < 1.0 ) {
678 pTm->tm_mday = 30;
679 dateIn = dateIn * -1.0; /* Ensure +ve for time calculation */
680 decimalPart = decimalPart * -1.0; /* Ensure +ve for time calculation */
681 } else {
682 pTm->tm_mday = 31;
683 }
684
685 } else {
686
687 /* Start at 1900, this is where the DATE time 0.0 starts.
688 */
689 pTm->tm_year = 1900;
690 /* find in what year the day in the "wholePart" falls into.
691 * add the value to the year field.
692 */
693 yearsSince1900 = floor( (wholePart / DAYS_IN_ONE_YEAR) + 0.001 );
694 pTm->tm_year += yearsSince1900;
695 /* determine if this is a leap year.
696 */
697 if( isleap( pTm->tm_year ) )
698 {
699 leapYear = 1;
700 wholePart++;
701 }
702
703 /* find what day of that year the "wholePart" corresponds to.
704 * Note: nDay is in [1-366] format
705 */
706 nDay = (((unsigned int) wholePart) - ((pTm->tm_year-1900) * DAYS_IN_ONE_YEAR ));
707
708 /* Remove the leap days in the previous years between now and 1900.
709 * Note a leap year is one that is a multiple of 4
710 * but not of a 100. Except if it is a multiple of
711 * 400 then it is a leap year.
712 * Copied + reversed functionality from TmToDate
713 */
714 nDay -= ( (pTm->tm_year - 1) / 4 ) - ( 1900 / 4 );
715 nDay += ( (pTm->tm_year - 1) / 100 ) - ( 1900 / 100 );
716 nDay -= ( (pTm->tm_year - 1) / 400 ) - ( 1900 / 400 );
717
718 /* Set the tm_yday value.
719 * Note: The day must be converted from [1-366] to [0-365]
720 */
721 /*pTm->tm_yday = nDay - 1;*/
722 /* find which month this day corresponds to.
723 */
724 if( nDay <= 31 )
725 {
726 pTm->tm_mday = nDay;
727 pTm->tm_mon = 0;
728 }
729 else if( nDay <= ( 59 + leapYear ) )
730 {
731 pTm->tm_mday = nDay - 31;
732 pTm->tm_mon = 1;
733 }
734 else if( nDay <= ( 90 + leapYear ) )
735 {
736 pTm->tm_mday = nDay - ( 59 + leapYear );
737 pTm->tm_mon = 2;
738 }
739 else if( nDay <= ( 120 + leapYear ) )
740 {
741 pTm->tm_mday = nDay - ( 90 + leapYear );
742 pTm->tm_mon = 3;
743 }
744 else if( nDay <= ( 151 + leapYear ) )
745 {
746 pTm->tm_mday = nDay - ( 120 + leapYear );
747 pTm->tm_mon = 4;
748 }
749 else if( nDay <= ( 181 + leapYear ) )
750 {
751 pTm->tm_mday = nDay - ( 151 + leapYear );
752 pTm->tm_mon = 5;
753 }
754 else if( nDay <= ( 212 + leapYear ) )
755 {
756 pTm->tm_mday = nDay - ( 181 + leapYear );
757 pTm->tm_mon = 6;
758 }
759 else if( nDay <= ( 243 + leapYear ) )
760 {
761 pTm->tm_mday = nDay - ( 212 + leapYear );
762 pTm->tm_mon = 7;
763 }
764 else if( nDay <= ( 273 + leapYear ) )
765 {
766 pTm->tm_mday = nDay - ( 243 + leapYear );
767 pTm->tm_mon = 8;
768 }
769 else if( nDay <= ( 304 + leapYear ) )
770 {
771 pTm->tm_mday = nDay - ( 273 + leapYear );
772 pTm->tm_mon = 9;
773 }
774 else if( nDay <= ( 334 + leapYear ) )
775 {
776 pTm->tm_mday = nDay - ( 304 + leapYear );
777 pTm->tm_mon = 10;
778 }
779 else if( nDay <= ( 365 + leapYear ) )
780 {
781 pTm->tm_mday = nDay - ( 334 + leapYear );
782 pTm->tm_mon = 11;
783 }
784 }
785 }
786 if( !(dwFlags & VAR_DATEVALUEONLY) )
787 {
788 /* find the number of seconds in this day.
789 * fractional part times, hours, minutes, seconds.
790 * Note: 0.1 is hack to ensure figures come out in whole numbers
791 * due to floating point inaccuracies
792 */
793 pTm->tm_hour = (int) ( decimalPart * 24 );
794 pTm->tm_min = (int) ( ( ( decimalPart * 24 ) - pTm->tm_hour ) * 60 );
795 /* Note: 0.1 is hack to ensure seconds come out in whole numbers
796 due to floating point inaccuracies */
797 pTm->tm_sec = (int) (( ( ( decimalPart * 24 * 60 ) - ( pTm->tm_hour * 60 ) - pTm->tm_min ) * 60 ) + 0.1);
798 }
799 return TRUE;
800}
801
802
803
804/******************************************************************************
805 * SizeOfVariantData [INTERNAL]
806 *
807 * This function finds the size of the data referenced by a Variant based
808 * the type "vt" of the Variant.
809 */
810static int SizeOfVariantData( VARIANT* parg )
811{
812 int size = 0;
813 switch( V_VT(parg) & VT_TYPEMASK )
814 {
815 case( VT_I2 ):
816 size = sizeof(short);
817 break;
818 case( VT_INT ):
819 size = sizeof(int);
820 break;
821 case( VT_I4 ):
822 size = sizeof(long);
823 break;
824 case( VT_UI1 ):
825 size = sizeof(BYTE);
826 break;
827 case( VT_UI2 ):
828 size = sizeof(unsigned short);
829 break;
830 case( VT_UINT ):
831 size = sizeof(unsigned int);
832 break;
833 case( VT_UI4 ):
834 size = sizeof(unsigned long);
835 break;
836 case( VT_R4 ):
837 size = sizeof(float);
838 break;
839 case( VT_R8 ):
840 size = sizeof(double);
841 break;
842 case( VT_DATE ):
843 size = sizeof(DATE);
844 break;
845 case( VT_BOOL ):
846 size = sizeof(VARIANT_BOOL);
847 break;
848 case( VT_BSTR ):
849 case( VT_DISPATCH ):
850 case( VT_UNKNOWN ):
851 size = sizeof(void*);
852 break;
853 case( VT_CY ):
854 size = sizeof(CY);
855 break;
856 case( VT_DECIMAL ): /* hmm, tricky, DECIMAL is only VT_BYREF */
857 default:
858 FIXME("Add size information for type vt=%d\n", V_VT(parg) & VT_TYPEMASK );
859 break;
860 }
861
862 return size;
863}
864/******************************************************************************
865 * StringDupAtoBstr [INTERNAL]
866 *
867 */
868static BSTR StringDupAtoBstr( char* strIn )
869{
870 BSTR bstr = NULL;
871 OLECHAR* pNewString = NULL;
872 pNewString = HEAP_strdupAtoW( GetProcessHeap(), 0, strIn );
873 bstr = SysAllocString( pNewString );
874 HeapFree( GetProcessHeap(), 0, pNewString );
875 return bstr;
876}
877
878/******************************************************************************
879 * round [INTERNAL]
880 *
881 * Round the double value to the nearest integer value.
882 */
883static double round( double d )
884{
885 double decimals = 0.0, integerValue = 0.0, roundedValue = 0.0;
886 BOOL bEvenNumber = FALSE;
887 int nSign = 0;
888
889 /* Save the sign of the number
890 */
891 nSign = (d >= 0.0) ? 1 : -1;
892 d = fabs( d );
893
894 /* Remove the decimals.
895 */
896 integerValue = floor( d );
897
898 /* Set the Even flag. This is used to round the number when
899 * the decimals are exactly 1/2. If the integer part is
900 * odd the number is rounded up. If the integer part
901 * is even the number is rounded down. Using this method
902 * numbers are rounded up|down half the time.
903 */
904 bEvenNumber = (((short)fmod(integerValue, 2)) == 0) ? TRUE : FALSE;
905
906 /* Remove the integral part of the number.
907 */
908 decimals = d - integerValue;
909
910 /* Note: Ceil returns the smallest integer that is greater that x.
911 * and floor returns the largest integer that is less than or equal to x.
912 */
913 if( decimals > 0.5 )
914 {
915 /* If the decimal part is greater than 1/2
916 */
917 roundedValue = ceil( d );
918 }
919 else if( decimals < 0.5 )
920 {
921 /* If the decimal part is smaller than 1/2
922 */
923 roundedValue = floor( d );
924 }
925 else
926 {
927 /* the decimals are exactly 1/2 so round according to
928 * the bEvenNumber flag.
929 */
930 if( bEvenNumber )
931 {
932 roundedValue = floor( d );
933 }
934 else
935 {
936 roundedValue = ceil( d );
937 }
938 }
939
940 return roundedValue * nSign;
941}
942
943/******************************************************************************
944 * RemoveCharacterFromString [INTERNAL]
945 *
946 * Removes any of the characters in "strOfCharToRemove" from the "str" argument.
947 */
948static void RemoveCharacterFromString( LPSTR str, LPSTR strOfCharToRemove )
949{
950 LPSTR pNewString = NULL;
951 LPSTR strToken = NULL;
952
953 /* Check if we have a valid argument
954 */
955 if( str != NULL )
956 {
957 pNewString = strdup( str );
958 str[0] = '\0';
959 strToken = strtok( pNewString, strOfCharToRemove );
960 while( strToken != NULL ) {
961 strcat( str, strToken );
962 strToken = strtok( NULL, strOfCharToRemove );
963 }
964 free( pNewString );
965 }
966 return;
967}
968
969/******************************************************************************
970 * GetValidRealString [INTERNAL]
971 *
972 * Checks if the string is of proper format to be converted to a real value.
973 */
974static BOOL IsValidRealString( LPSTR strRealString )
975{
976 /* Real values that have a decimal point are required to either have
977 * digits before or after the decimal point. We will assume that
978 * we do not have any digits at either position. If we do encounter
979 * some we will disable this flag.
980 */
981 BOOL bDigitsRequired = TRUE;
982 /* Processed fields in the string representation of the real number.
983 */
984 BOOL bWhiteSpaceProcessed = FALSE;
985 BOOL bFirstSignProcessed = FALSE;
986 BOOL bFirstDigitsProcessed = FALSE;
987 BOOL bDecimalPointProcessed = FALSE;
988 BOOL bSecondDigitsProcessed = FALSE;
989 BOOL bExponentProcessed = FALSE;
990 BOOL bSecondSignProcessed = FALSE;
991 BOOL bThirdDigitsProcessed = FALSE;
992 /* Assume string parameter "strRealString" is valid and try to disprove it.
993 */
994 BOOL bValidRealString = TRUE;
995
996 /* Used to count the number of tokens in the "strRealString".
997 */
998 LPSTR strToken = NULL;
999 int nTokens = 0;
1000 LPSTR pChar = NULL;
1001
1002 /* Check if we have a valid argument
1003 */
1004 if( strRealString == NULL )
1005 {
1006 bValidRealString = FALSE;
1007 }
1008
1009 if( bValidRealString == TRUE )
1010 {
1011 /* Make sure we only have ONE token in the string.
1012 */
1013 strToken = strtok( strRealString, " " );
1014 while( strToken != NULL ) {
1015 nTokens++;
1016 strToken = strtok( NULL, " " );
1017 }
1018
1019 if( nTokens != 1 )
1020 {
1021 bValidRealString = FALSE;
1022 }
1023 }
1024
1025
1026 /* Make sure this token contains only valid characters.
1027 * The string argument to atof has the following form:
1028 * [whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]
1029 * Whitespace consists of space and|or <TAB> characters, which are ignored.
1030 * Sign is either plus '+' or minus '-'.
1031 * Digits are one or more decimal digits.
1032 * Note: If no digits appear before the decimal point, at least one must
1033 * appear after the decimal point.
1034 * The decimal digits may be followed by an exponent.
1035 * An Exponent consists of an introductory letter ( D, d, E, or e) and
1036 * an optionally signed decimal integer.
1037 */
1038 pChar = strRealString;
1039 while( bValidRealString == TRUE && *pChar != '\0' )
1040 {
1041 switch( *pChar )
1042 {
1043 /* If whitespace...
1044 */
1045 case ' ':
1046 case '\t':
1047 if( bWhiteSpaceProcessed ||
1048 bFirstSignProcessed ||
1049 bFirstDigitsProcessed ||
1050 bDecimalPointProcessed ||
1051 bSecondDigitsProcessed ||
1052 bExponentProcessed ||
1053 bSecondSignProcessed ||
1054 bThirdDigitsProcessed )
1055 {
1056 bValidRealString = FALSE;
1057 }
1058 break;
1059 /* If sign...
1060 */
1061 case '+':
1062 case '-':
1063 if( bFirstSignProcessed == FALSE )
1064 {
1065 if( bFirstDigitsProcessed ||
1066 bDecimalPointProcessed ||
1067 bSecondDigitsProcessed ||
1068 bExponentProcessed ||
1069 bSecondSignProcessed ||
1070 bThirdDigitsProcessed )
1071 {
1072 bValidRealString = FALSE;
1073 }
1074 bWhiteSpaceProcessed = TRUE;
1075 bFirstSignProcessed = TRUE;
1076 }
1077 else if( bSecondSignProcessed == FALSE )
1078 {
1079 /* Note: The exponent must be present in
1080 * order to accept the second sign...
1081 */
1082 if( bExponentProcessed == FALSE ||
1083 bThirdDigitsProcessed ||
1084 bDigitsRequired )
1085 {
1086 bValidRealString = FALSE;
1087 }
1088 bFirstSignProcessed = TRUE;
1089 bWhiteSpaceProcessed = TRUE;
1090 bFirstDigitsProcessed = TRUE;
1091 bDecimalPointProcessed = TRUE;
1092 bSecondDigitsProcessed = TRUE;
1093 bSecondSignProcessed = TRUE;
1094 }
1095 break;
1096
1097 /* If decimals...
1098 */
1099 case '0':
1100 case '1':
1101 case '2':
1102 case '3':
1103 case '4':
1104 case '5':
1105 case '6':
1106 case '7':
1107 case '8':
1108 case '9':
1109 if( bFirstDigitsProcessed == FALSE )
1110 {
1111 if( bDecimalPointProcessed ||
1112 bSecondDigitsProcessed ||
1113 bExponentProcessed ||
1114 bSecondSignProcessed ||
1115 bThirdDigitsProcessed )
1116 {
1117 bValidRealString = FALSE;
1118 }
1119 bFirstSignProcessed = TRUE;
1120 bWhiteSpaceProcessed = TRUE;
1121 /* We have found some digits before the decimal point
1122 * so disable the "Digits required" flag.
1123 */
1124 bDigitsRequired = FALSE;
1125 }
1126 else if( bSecondDigitsProcessed == FALSE )
1127 {
1128 if( bExponentProcessed ||
1129 bSecondSignProcessed ||
1130 bThirdDigitsProcessed )
1131 {
1132 bValidRealString = FALSE;
1133 }
1134 bFirstSignProcessed = TRUE;
1135 bWhiteSpaceProcessed = TRUE;
1136 bFirstDigitsProcessed = TRUE;
1137 bDecimalPointProcessed = TRUE;
1138 /* We have found some digits after the decimal point
1139 * so disable the "Digits required" flag.
1140 */
1141 bDigitsRequired = FALSE;
1142 }
1143 else if( bThirdDigitsProcessed == FALSE )
1144 {
1145 /* Getting here means everything else should be processed.
1146 * If we get anything else than a decimal following this
1147 * digit it will be flagged by the other cases, so
1148 * we do not really need to do anything in here.
1149 */
1150 }
1151 break;
1152 /* If DecimalPoint...
1153 */
1154 case '.':
1155 if( bDecimalPointProcessed ||
1156 bSecondDigitsProcessed ||
1157 bExponentProcessed ||
1158 bSecondSignProcessed ||
1159 bThirdDigitsProcessed )
1160 {
1161 bValidRealString = FALSE;
1162 }
1163 bFirstSignProcessed = TRUE;
1164 bWhiteSpaceProcessed = TRUE;
1165 bFirstDigitsProcessed = TRUE;
1166 bDecimalPointProcessed = TRUE;
1167 break;
1168 /* If Exponent...
1169 */
1170 case 'e':
1171 case 'E':
1172 case 'd':
1173 case 'D':
1174 if( bExponentProcessed ||
1175 bSecondSignProcessed ||
1176 bThirdDigitsProcessed ||
1177 bDigitsRequired )
1178 {
1179 bValidRealString = FALSE;
1180 }
1181 bFirstSignProcessed = TRUE;
1182 bWhiteSpaceProcessed = TRUE;
1183 bFirstDigitsProcessed = TRUE;
1184 bDecimalPointProcessed = TRUE;
1185 bSecondDigitsProcessed = TRUE;
1186 bExponentProcessed = TRUE;
1187 break;
1188 default:
1189 bValidRealString = FALSE;
1190 break;
1191 }
1192 /* Process next character.
1193 */
1194 pChar++;
1195 }
1196
1197 /* If the required digits were not present we have an invalid
1198 * string representation of a real number.
1199 */
1200 if( bDigitsRequired == TRUE )
1201 {
1202 bValidRealString = FALSE;
1203 }
1204
1205 return bValidRealString;
1206}
1207
1208
1209/******************************************************************************
1210 * Coerce [INTERNAL]
1211 *
1212 * This function dispatches execution to the proper conversion API
1213 * to do the necessary coercion.
1214 *
1215 * FIXME: Passing down dwFlags to the conversion functions is wrong, this
1216 * is a different flagmask. Check MSDN.
1217 */
1218static HRESULT Coerce( VARIANTARG* pd, LCID lcid, ULONG dwFlags, VARIANTARG* ps, VARTYPE vt )
1219{
1220 HRESULT res = S_OK;
1221 unsigned short vtFrom = 0;
1222 vtFrom = V_VT(ps) & VT_TYPEMASK;
1223
1224
1225 /* Note: Since "long" and "int" values both have 4 bytes and are
1226 * both signed integers "int" will be treated as "long" in the
1227 * following code.
1228 * The same goes for their unsigned versions.
1229 */
1230
1231 /* Trivial Case: If the coercion is from two types that are
1232 * identical then we can blindly copy from one argument to another.*/
1233 if ((vt==vtFrom))
1234 {
1235 return VariantCopy(pd,ps);
1236 }
1237
1238 /* Cases requiring thought*/
1239 switch( vt )
1240 {
1241
1242 case( VT_EMPTY ):
1243 res = VariantClear( pd );
1244 break;
1245 case( VT_NULL ):
1246 res = VariantClear( pd );
1247 if( res == S_OK )
1248 {
1249 V_VT(pd) = VT_NULL;
1250 }
1251 break;
1252 case( VT_I1 ):
1253 switch( vtFrom )
1254 {
1255 case( VT_I1 ):
1256 res = VariantCopy( pd, ps );
1257 break;
1258 case( VT_I2 ):
1259 res = VarI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,cVal) );
1260 break;
1261 case( VT_INT ):
1262 case( VT_I4 ):
1263 res = VarI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,cVal) );
1264 break;
1265 case( VT_UI1 ):
1266 res = VarI1FromUI1( V_UNION(ps,bVal), &V_UNION(pd,cVal) );
1267 break;
1268 case( VT_UI2 ):
1269 res = VarI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cVal) );
1270 break;
1271 case( VT_UINT ):
1272 case( VT_UI4 ):
1273 res = VarI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cVal) );
1274 break;
1275 case( VT_R4 ):
1276 res = VarI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,cVal) );
1277 break;
1278 case( VT_R8 ):
1279 res = VarI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,cVal) );
1280 break;
1281 case( VT_DATE ):
1282 res = VarI1FromDate( V_UNION(ps,date), &V_UNION(pd,cVal) );
1283 break;
1284 case( VT_BOOL ):
1285 res = VarI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,cVal) );
1286 break;
1287 case( VT_BSTR ):
1288 res = VarI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cVal) );
1289 break;
1290 case( VT_CY ):
1291 res = VarI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,cVal) );
1292 break;
1293 case( VT_DISPATCH ):
1294 /*res = VarI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cVal) );*/
1295 case( VT_DECIMAL ):
1296 /*res = VarI1FromDec( V_UNION(ps,decVal), &V_UNION(pd,cVal) );*/
1297 case( VT_UNKNOWN ):
1298 default:
1299 res = DISP_E_TYPEMISMATCH;
1300 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1301 break;
1302 }
1303 break;
1304
1305 case( VT_I2 ):
1306 switch( vtFrom )
1307 {
1308 case( VT_I1 ):
1309 res = VarI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,iVal) );
1310 break;
1311 case( VT_I2 ):
1312 res = VariantCopy( pd, ps );
1313 break;
1314 case( VT_INT ):
1315 case( VT_I4 ):
1316 res = VarI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,iVal) );
1317 break;
1318 case( VT_UI1 ):
1319 res = VarI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,iVal) );
1320 break;
1321 case( VT_UI2 ):
1322 res = VarI2FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,iVal) );
1323 break;
1324 case( VT_UINT ):
1325 case( VT_UI4 ):
1326 res = VarI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,iVal) );
1327 break;
1328 case( VT_R4 ):
1329 res = VarI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,iVal) );
1330 break;
1331 case( VT_R8 ):
1332 res = VarI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,iVal) );
1333 break;
1334 case( VT_DATE ):
1335 res = VarI2FromDate( V_UNION(ps,date), &V_UNION(pd,iVal) );
1336 break;
1337 case( VT_BOOL ):
1338 res = VarI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,iVal) );
1339 break;
1340 case( VT_BSTR ):
1341 res = VarI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,iVal) );
1342 break;
1343 case( VT_CY ):
1344 res = VarI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,iVal) );
1345 break;
1346 case( VT_DISPATCH ):
1347 /*res = VarI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,iVal) );*/
1348 case( VT_DECIMAL ):
1349 /*res = VarI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,iVal) );*/
1350 case( VT_UNKNOWN ):
1351 default:
1352 res = DISP_E_TYPEMISMATCH;
1353 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1354 break;
1355 }
1356 break;
1357
1358 case( VT_INT ):
1359 case( VT_I4 ):
1360 switch( vtFrom )
1361 {
1362 case( VT_EMPTY ):
1363 V_UNION(pd,lVal) = 0;
1364 res = S_OK;
1365 break;
1366 case( VT_I1 ):
1367 res = VarI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,lVal) );
1368 break;
1369 case( VT_I2 ):
1370 res = VarI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,lVal) );
1371 break;
1372 case( VT_INT ):
1373 case( VT_I4 ):
1374#ifdef __WIN32OS2__
1375 case( VT_HRESULT ):
1376#endif
1377 res = VariantCopy( pd, ps );
1378 break;
1379 case( VT_UI1 ):
1380 res = VarI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,lVal) );
1381 break;
1382 case( VT_UI2 ):
1383 res = VarI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,lVal) );
1384 break;
1385 case( VT_UINT ):
1386 case( VT_UI4 ):
1387 res = VarI4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,lVal) );
1388 break;
1389 case( VT_R4 ):
1390 res = VarI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,lVal) );
1391 break;
1392 case( VT_R8 ):
1393 res = VarI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,lVal) );
1394 break;
1395 case( VT_DATE ):
1396 res = VarI4FromDate( V_UNION(ps,date), &V_UNION(pd,lVal) );
1397 break;
1398 case( VT_BOOL ):
1399 res = VarI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,lVal) );
1400 break;
1401 case( VT_BSTR ):
1402 res = VarI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,lVal) );
1403 break;
1404 case( VT_CY ):
1405 res = VarI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,lVal) );
1406 break;
1407 case( VT_DISPATCH ):
1408 /*res = VarI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,lVal) );*/
1409 case( VT_DECIMAL ):
1410 /*res = VarI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,lVal) );*/
1411 case( VT_UNKNOWN ):
1412 default:
1413 res = DISP_E_TYPEMISMATCH;
1414 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1415 break;
1416 }
1417 break;
1418
1419 case( VT_UI1 ):
1420 switch( vtFrom )
1421 {
1422 case( VT_I1 ):
1423 res = VarUI1FromI1( V_UNION(ps,cVal), &V_UNION(pd,bVal) );
1424 break;
1425 case( VT_I2 ):
1426 res = VarUI1FromI2( V_UNION(ps,iVal), &V_UNION(pd,bVal) );
1427 break;
1428 case( VT_INT ):
1429 case( VT_I4 ):
1430 res = VarUI1FromI4( V_UNION(ps,lVal), &V_UNION(pd,bVal) );
1431 break;
1432 case( VT_UI1 ):
1433 res = VariantCopy( pd, ps );
1434 break;
1435 case( VT_UI2 ):
1436 res = VarUI1FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,bVal) );
1437 break;
1438 case( VT_UINT ):
1439 case( VT_UI4 ):
1440 res = VarUI1FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,bVal) );
1441 break;
1442 case( VT_R4 ):
1443 res = VarUI1FromR4( V_UNION(ps,fltVal), &V_UNION(pd,bVal) );
1444 break;
1445 case( VT_R8 ):
1446 res = VarUI1FromR8( V_UNION(ps,dblVal), &V_UNION(pd,bVal) );
1447 break;
1448 case( VT_DATE ):
1449 res = VarUI1FromDate( V_UNION(ps,date), &V_UNION(pd,bVal) );
1450 break;
1451 case( VT_BOOL ):
1452 res = VarUI1FromBool( V_UNION(ps,boolVal), &V_UNION(pd,bVal) );
1453 break;
1454 case( VT_BSTR ):
1455 res = VarUI1FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,bVal) );
1456 break;
1457 case( VT_CY ):
1458 res = VarUI1FromCy( V_UNION(ps,cyVal), &V_UNION(pd,bVal) );
1459 break;
1460 case( VT_DISPATCH ):
1461 /*res = VarUI1FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,bVal) );*/
1462 case( VT_DECIMAL ):
1463 /*res = VarUI1FromDec( V_UNION(ps,deiVal), &V_UNION(pd,bVal) );*/
1464 case( VT_UNKNOWN ):
1465 default:
1466 res = DISP_E_TYPEMISMATCH;
1467 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1468 break;
1469 }
1470 break;
1471
1472 case( VT_UI2 ):
1473 switch( vtFrom )
1474 {
1475 case( VT_I1 ):
1476 res = VarUI2FromI1( V_UNION(ps,cVal), &V_UNION(pd,uiVal) );
1477 break;
1478 case( VT_I2 ):
1479 res = VarUI2FromI2( V_UNION(ps,iVal), &V_UNION(pd,uiVal) );
1480 break;
1481 case( VT_INT ):
1482 case( VT_I4 ):
1483 res = VarUI2FromI4( V_UNION(ps,lVal), &V_UNION(pd,uiVal) );
1484 break;
1485 case( VT_UI1 ):
1486 res = VarUI2FromUI1( V_UNION(ps,bVal), &V_UNION(pd,uiVal) );
1487 break;
1488 case( VT_UI2 ):
1489 res = VariantCopy( pd, ps );
1490 break;
1491 case( VT_UINT ):
1492 case( VT_UI4 ):
1493 res = VarUI2FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,uiVal) );
1494 break;
1495 case( VT_R4 ):
1496 res = VarUI2FromR4( V_UNION(ps,fltVal), &V_UNION(pd,uiVal) );
1497 break;
1498 case( VT_R8 ):
1499 res = VarUI2FromR8( V_UNION(ps,dblVal), &V_UNION(pd,uiVal) );
1500 break;
1501 case( VT_DATE ):
1502 res = VarUI2FromDate( V_UNION(ps,date), &V_UNION(pd,uiVal) );
1503 break;
1504 case( VT_BOOL ):
1505 res = VarUI2FromBool( V_UNION(ps,boolVal), &V_UNION(pd,uiVal) );
1506 break;
1507 case( VT_BSTR ):
1508 res = VarUI2FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,uiVal) );
1509 break;
1510 case( VT_CY ):
1511 res = VarUI2FromCy( V_UNION(ps,cyVal), &V_UNION(pd,uiVal) );
1512 break;
1513 case( VT_DISPATCH ):
1514 /*res = VarUI2FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,uiVal) );*/
1515 case( VT_DECIMAL ):
1516 /*res = VarUI2FromDec( V_UNION(ps,deiVal), &V_UNION(pd,uiVal) );*/
1517 case( VT_UNKNOWN ):
1518 default:
1519 res = DISP_E_TYPEMISMATCH;
1520 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1521 break;
1522 }
1523 break;
1524
1525 case( VT_UINT ):
1526 case( VT_UI4 ):
1527 switch( vtFrom )
1528 {
1529 case( VT_I1 ):
1530 res = VarUI4FromI1( V_UNION(ps,cVal), &V_UNION(pd,ulVal) );
1531 break;
1532 case( VT_I2 ):
1533 res = VarUI4FromI2( V_UNION(ps,iVal), &V_UNION(pd,ulVal) );
1534 break;
1535 case( VT_INT ):
1536 case( VT_I4 ):
1537 res = VarUI4FromI4( V_UNION(ps,lVal), &V_UNION(pd,ulVal) );
1538 break;
1539 case( VT_UI1 ):
1540 res = VarUI4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,ulVal) );
1541 break;
1542 case( VT_UI2 ):
1543 res = VarUI4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,ulVal) );
1544 break;
1545 case( VT_UI4 ):
1546 res = VariantCopy( pd, ps );
1547 break;
1548 case( VT_R4 ):
1549 res = VarUI4FromR4( V_UNION(ps,fltVal), &V_UNION(pd,ulVal) );
1550 break;
1551 case( VT_R8 ):
1552 res = VarUI4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,ulVal) );
1553 break;
1554 case( VT_DATE ):
1555 res = VarUI4FromDate( V_UNION(ps,date), &V_UNION(pd,ulVal) );
1556 break;
1557 case( VT_BOOL ):
1558 res = VarUI4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,ulVal) );
1559 break;
1560 case( VT_BSTR ):
1561 res = VarUI4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,ulVal) );
1562 break;
1563 case( VT_CY ):
1564 res = VarUI4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,ulVal) );
1565 break;
1566 case( VT_DISPATCH ):
1567 /*res = VarUI4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,ulVal) );*/
1568 case( VT_DECIMAL ):
1569 /*res = VarUI4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,ulVal) );*/
1570 case( VT_UNKNOWN ):
1571 default:
1572 res = DISP_E_TYPEMISMATCH;
1573 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1574 break;
1575 }
1576 break;
1577
1578 case( VT_R4 ):
1579 switch( vtFrom )
1580 {
1581 case( VT_I1 ):
1582 res = VarR4FromI1( V_UNION(ps,cVal), &V_UNION(pd,fltVal) );
1583 break;
1584 case( VT_I2 ):
1585 res = VarR4FromI2( V_UNION(ps,iVal), &V_UNION(pd,fltVal) );
1586 break;
1587 case( VT_INT ):
1588 case( VT_I4 ):
1589 res = VarR4FromI4( V_UNION(ps,lVal), &V_UNION(pd,fltVal) );
1590 break;
1591 case( VT_UI1 ):
1592 res = VarR4FromUI1( V_UNION(ps,bVal), &V_UNION(pd,fltVal) );
1593 break;
1594 case( VT_UI2 ):
1595 res = VarR4FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,fltVal) );
1596 break;
1597 case( VT_UINT ):
1598 case( VT_UI4 ):
1599 res = VarR4FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,fltVal) );
1600 break;
1601 case( VT_R4 ):
1602 res = VariantCopy( pd, ps );
1603 break;
1604 case( VT_R8 ):
1605 res = VarR4FromR8( V_UNION(ps,dblVal), &V_UNION(pd,fltVal) );
1606 break;
1607 case( VT_DATE ):
1608 res = VarR4FromDate( V_UNION(ps,date), &V_UNION(pd,fltVal) );
1609 break;
1610 case( VT_BOOL ):
1611 res = VarR4FromBool( V_UNION(ps,boolVal), &V_UNION(pd,fltVal) );
1612 break;
1613 case( VT_BSTR ):
1614 res = VarR4FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,fltVal) );
1615 break;
1616 case( VT_CY ):
1617 res = VarR4FromCy( V_UNION(ps,cyVal), &V_UNION(pd,fltVal) );
1618 break;
1619 case( VT_DISPATCH ):
1620 /*res = VarR4FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,fltVal) );*/
1621 case( VT_DECIMAL ):
1622 /*res = VarR4FromDec( V_UNION(ps,deiVal), &V_UNION(pd,fltVal) );*/
1623 case( VT_UNKNOWN ):
1624 default:
1625 res = DISP_E_TYPEMISMATCH;
1626 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1627 break;
1628 }
1629 break;
1630
1631 case( VT_R8 ):
1632 switch( vtFrom )
1633 {
1634 case( VT_I1 ):
1635 res = VarR8FromI1( V_UNION(ps,cVal), &V_UNION(pd,dblVal) );
1636 break;
1637 case( VT_I2 ):
1638 res = VarR8FromI2( V_UNION(ps,iVal), &V_UNION(pd,dblVal) );
1639 break;
1640 case( VT_INT ):
1641 case( VT_I4 ):
1642 res = VarR8FromI4( V_UNION(ps,lVal), &V_UNION(pd,dblVal) );
1643 break;
1644 case( VT_UI1 ):
1645 res = VarR8FromUI1( V_UNION(ps,bVal), &V_UNION(pd,dblVal) );
1646 break;
1647 case( VT_UI2 ):
1648 res = VarR8FromUI2( V_UNION(ps,uiVal), &V_UNION(pd,dblVal) );
1649 break;
1650 case( VT_UINT ):
1651 case( VT_UI4 ):
1652 res = VarR8FromUI4( V_UNION(ps,ulVal), &V_UNION(pd,dblVal) );
1653 break;
1654 case( VT_R4 ):
1655 res = VarR8FromR4( V_UNION(ps,fltVal), &V_UNION(pd,dblVal) );
1656 break;
1657 case( VT_R8 ):
1658 res = VariantCopy( pd, ps );
1659 break;
1660 case( VT_DATE ):
1661 res = VarR8FromDate( V_UNION(ps,date), &V_UNION(pd,dblVal) );
1662 break;
1663 case( VT_BOOL ):
1664 res = VarR8FromBool( V_UNION(ps,boolVal), &V_UNION(pd,dblVal) );
1665 break;
1666 case( VT_BSTR ):
1667 res = VarR8FromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,dblVal) );
1668 break;
1669 case( VT_CY ):
1670 res = VarR8FromCy( V_UNION(ps,cyVal), &V_UNION(pd,dblVal) );
1671 break;
1672 case( VT_DISPATCH ):
1673 /*res = VarR8FromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,dblVal) );*/
1674 case( VT_DECIMAL ):
1675 /*res = VarR8FromDec( V_UNION(ps,deiVal), &V_UNION(pd,dblVal) );*/
1676 case( VT_UNKNOWN ):
1677 default:
1678 res = DISP_E_TYPEMISMATCH;
1679 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1680 break;
1681 }
1682 break;
1683
1684 case( VT_DATE ):
1685 switch( vtFrom )
1686 {
1687 case( VT_I1 ):
1688 res = VarDateFromI1( V_UNION(ps,cVal), &V_UNION(pd,date) );
1689 break;
1690 case( VT_I2 ):
1691 res = VarDateFromI2( V_UNION(ps,iVal), &V_UNION(pd,date) );
1692 break;
1693 case( VT_INT ):
1694 res = VarDateFromInt( V_UNION(ps,intVal), &V_UNION(pd,date) );
1695 break;
1696 case( VT_I4 ):
1697 res = VarDateFromI4( V_UNION(ps,lVal), &V_UNION(pd,date) );
1698 break;
1699 case( VT_UI1 ):
1700 res = VarDateFromUI1( V_UNION(ps,bVal), &V_UNION(pd,date) );
1701 break;
1702 case( VT_UI2 ):
1703 res = VarDateFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,date) );
1704 break;
1705 case( VT_UINT ):
1706 res = VarDateFromUint( V_UNION(ps,uintVal), &V_UNION(pd,date) );
1707 break;
1708 case( VT_UI4 ):
1709 res = VarDateFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,date) );
1710 break;
1711 case( VT_R4 ):
1712 res = VarDateFromR4( V_UNION(ps,fltVal), &V_UNION(pd,date) );
1713 break;
1714 case( VT_R8 ):
1715 res = VarDateFromR8( V_UNION(ps,dblVal), &V_UNION(pd,date) );
1716 break;
1717 case( VT_DATE ):
1718 res = VariantCopy( pd, ps );
1719 break;
1720 case( VT_BOOL ):
1721 res = VarDateFromBool( V_UNION(ps,boolVal), &V_UNION(pd,date) );
1722 break;
1723 case( VT_BSTR ):
1724 res = VarDateFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,date) );
1725 break;
1726 case( VT_CY ):
1727 res = VarDateFromCy( V_UNION(ps,cyVal), &V_UNION(pd,date) );
1728 break;
1729 case( VT_DISPATCH ):
1730 /*res = VarDateFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,date) );*/
1731 case( VT_DECIMAL ):
1732 /*res = VarDateFromDec( V_UNION(ps,deiVal), &V_UNION(pd,date) );*/
1733 case( VT_UNKNOWN ):
1734 default:
1735 res = DISP_E_TYPEMISMATCH;
1736 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1737 break;
1738 }
1739 break;
1740
1741 case( VT_BOOL ):
1742 switch( vtFrom )
1743 {
1744 case( VT_EMPTY ):
1745 res = S_OK;
1746 V_UNION(pd,boolVal) = VARIANT_FALSE;
1747 break;
1748 case( VT_I1 ):
1749 res = VarBoolFromI1( V_UNION(ps,cVal), &V_UNION(pd,boolVal) );
1750 break;
1751 case( VT_I2 ):
1752 res = VarBoolFromI2( V_UNION(ps,iVal), &V_UNION(pd,boolVal) );
1753 break;
1754 case( VT_INT ):
1755 res = VarBoolFromInt( V_UNION(ps,intVal), &V_UNION(pd,boolVal) );
1756 break;
1757 case( VT_I4 ):
1758 res = VarBoolFromI4( V_UNION(ps,lVal), &V_UNION(pd,boolVal) );
1759 break;
1760 case( VT_UI1 ):
1761 res = VarBoolFromUI1( V_UNION(ps,bVal), &V_UNION(pd,boolVal) );
1762 break;
1763 case( VT_UI2 ):
1764 res = VarBoolFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,boolVal) );
1765 break;
1766 case( VT_UINT ):
1767 res = VarBoolFromUint( V_UNION(ps,uintVal), &V_UNION(pd,boolVal) );
1768 break;
1769 case( VT_UI4 ):
1770 res = VarBoolFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,boolVal) );
1771 break;
1772 case( VT_R4 ):
1773 res = VarBoolFromR4( V_UNION(ps,fltVal), &V_UNION(pd,boolVal) );
1774 break;
1775 case( VT_R8 ):
1776 res = VarBoolFromR8( V_UNION(ps,dblVal), &V_UNION(pd,boolVal) );
1777 break;
1778 case( VT_DATE ):
1779 res = VarBoolFromDate( V_UNION(ps,date), &V_UNION(pd,boolVal) );
1780 break;
1781 case( VT_BOOL ):
1782 res = VariantCopy( pd, ps );
1783 break;
1784 case( VT_BSTR ):
1785 res = VarBoolFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,boolVal) );
1786 break;
1787 case( VT_CY ):
1788 res = VarBoolFromCy( V_UNION(ps,cyVal), &V_UNION(pd,boolVal) );
1789 break;
1790 case( VT_DISPATCH ):
1791 /*res = VarBoolFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,boolVal) );*/
1792 case( VT_DECIMAL ):
1793 /*res = VarBoolFromDec( V_UNION(ps,deiVal), &V_UNION(pd,boolVal) );*/
1794 case( VT_UNKNOWN ):
1795 default:
1796 res = DISP_E_TYPEMISMATCH;
1797 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1798 break;
1799 }
1800 break;
1801
1802 case( VT_BSTR ):
1803 switch( vtFrom )
1804 {
1805 case( VT_EMPTY ):
1806 if ((V_UNION(pd,bstrVal) = SysAllocStringLen(NULL, 0)))
1807 res = S_OK;
1808 else
1809 res = E_OUTOFMEMORY;
1810 break;
1811 case( VT_I1 ):
1812 res = VarBstrFromI1( V_UNION(ps,cVal), lcid, 0, &V_UNION(pd,bstrVal) );
1813 break;
1814 case( VT_I2 ):
1815 res = VarBstrFromI2( V_UNION(ps,iVal), lcid, 0, &V_UNION(pd,bstrVal) );
1816 break;
1817 case( VT_INT ):
1818 res = VarBstrFromInt( V_UNION(ps,intVal), lcid, 0, &V_UNION(pd,bstrVal) );
1819 break;
1820 case( VT_I4 ):
1821 res = VarBstrFromI4( V_UNION(ps,lVal), lcid, 0, &V_UNION(pd,bstrVal) );
1822 break;
1823 case( VT_UI1 ):
1824 res = VarBstrFromUI1( V_UNION(ps,bVal), lcid, 0, &V_UNION(pd,bstrVal) );
1825 break;
1826 case( VT_UI2 ):
1827 res = VarBstrFromUI2( V_UNION(ps,uiVal), lcid, 0, &V_UNION(pd,bstrVal) );
1828 break;
1829 case( VT_UINT ):
1830 res = VarBstrFromUint( V_UNION(ps,uintVal), lcid, 0, &V_UNION(pd,bstrVal) );
1831 break;
1832 case( VT_UI4 ):
1833 res = VarBstrFromUI4( V_UNION(ps,ulVal), lcid, 0, &V_UNION(pd,bstrVal) );
1834 break;
1835 case( VT_R4 ):
1836 res = VarBstrFromR4( V_UNION(ps,fltVal), lcid, 0, &V_UNION(pd,bstrVal) );
1837 break;
1838 case( VT_R8 ):
1839 res = VarBstrFromR8( V_UNION(ps,dblVal), lcid, 0, &V_UNION(pd,bstrVal) );
1840 break;
1841 case( VT_DATE ):
1842 res = VarBstrFromDate( V_UNION(ps,date), lcid, 0, &V_UNION(pd,bstrVal) );
1843 break;
1844 case( VT_BOOL ):
1845 res = VarBstrFromBool( V_UNION(ps,boolVal), lcid, 0, &V_UNION(pd,bstrVal) );
1846 break;
1847 case( VT_BSTR ):
1848 res = VariantCopy( pd, ps );
1849 break;
1850 case( VT_CY ):
1851 res = VarBstrFromCy( V_UNION(ps,cyVal), lcid, 0, &V_UNION(pd,bstrVal) );
1852 break;
1853 case( VT_DISPATCH ):
1854 /*res = VarBstrFromDisp( V_UNION(ps,pdispVal), lcid, 0, &(pd,bstrVal) );*/
1855 case( VT_DECIMAL ):
1856 /*res = VarBstrFromDec( V_UNION(ps,deiVal), lcid, 0, &(pd,bstrVal) );*/
1857 case( VT_UNKNOWN ):
1858 default:
1859 res = DISP_E_TYPEMISMATCH;
1860 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1861 break;
1862 }
1863 break;
1864
1865 case( VT_CY ):
1866 switch( vtFrom )
1867 {
1868 case( VT_I1 ):
1869 res = VarCyFromI1( V_UNION(ps,cVal), &V_UNION(pd,cyVal) );
1870 break;
1871 case( VT_I2 ):
1872 res = VarCyFromI2( V_UNION(ps,iVal), &V_UNION(pd,cyVal) );
1873 break;
1874 case( VT_INT ):
1875 res = VarCyFromInt( V_UNION(ps,intVal), &V_UNION(pd,cyVal) );
1876 break;
1877 case( VT_I4 ):
1878 res = VarCyFromI4( V_UNION(ps,lVal), &V_UNION(pd,cyVal) );
1879 break;
1880 case( VT_UI1 ):
1881 res = VarCyFromUI1( V_UNION(ps,bVal), &V_UNION(pd,cyVal) );
1882 break;
1883 case( VT_UI2 ):
1884 res = VarCyFromUI2( V_UNION(ps,uiVal), &V_UNION(pd,cyVal) );
1885 break;
1886 case( VT_UINT ):
1887 res = VarCyFromUint( V_UNION(ps,uintVal), &V_UNION(pd,cyVal) );
1888 break;
1889 case( VT_UI4 ):
1890 res = VarCyFromUI4( V_UNION(ps,ulVal), &V_UNION(pd,cyVal) );
1891 break;
1892 case( VT_R4 ):
1893 res = VarCyFromR4( V_UNION(ps,fltVal), &V_UNION(pd,cyVal) );
1894 break;
1895 case( VT_R8 ):
1896 res = VarCyFromR8( V_UNION(ps,dblVal), &V_UNION(pd,cyVal) );
1897 break;
1898 case( VT_DATE ):
1899 res = VarCyFromDate( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1900 break;
1901 case( VT_BOOL ):
1902 res = VarCyFromBool( V_UNION(ps,date), &V_UNION(pd,cyVal) );
1903 break;
1904 case( VT_CY ):
1905 res = VariantCopy( pd, ps );
1906 break;
1907 case( VT_BSTR ):
1908 res = VarCyFromStr( V_UNION(ps,bstrVal), lcid, 0, &V_UNION(pd,cyVal) );
1909 break;
1910 case( VT_DISPATCH ):
1911 /*res = VarCyFromDisp( V_UNION(ps,pdispVal), lcid, &V_UNION(pd,cyVal) );*/
1912 case( VT_DECIMAL ):
1913 /*res = VarCyFromDec( V_UNION(ps,deiVal), &V_UNION(pd,cyVal) );*/
1914 break;
1915 case( VT_UNKNOWN ):
1916 default:
1917 res = DISP_E_TYPEMISMATCH;
1918 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1919 break;
1920 }
1921 break;
1922
1923 case( VT_UNKNOWN ):
1924 if (vtFrom == VT_DISPATCH)
1925 {
1926 res = IDispatch_QueryInterface(V_DISPATCH(ps), &IID_IUnknown, (LPVOID*)&V_UNKNOWN(pd));
1927 }
1928 else
1929 {
1930 res = DISP_E_TYPEMISMATCH;
1931 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1932 }
1933 break;
1934
1935 default:
1936 res = DISP_E_TYPEMISMATCH;
1937 FIXME("Coercion from %d to %d\n", vtFrom, vt );
1938 break;
1939 }
1940
1941 return res;
1942}
1943
1944/******************************************************************************
1945 * ValidateVtRange [INTERNAL]
1946 *
1947 * Used internally by the hi-level Variant API to determine
1948 * if the vartypes are valid.
1949 */
1950static HRESULT WINAPI ValidateVtRange( VARTYPE vt )
1951{
1952 /* if by value we must make sure it is in the
1953 * range of the valid types.
1954 */
1955 if( ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1956 {
1957 return DISP_E_BADVARTYPE;
1958 }
1959 return S_OK;
1960}
1961
1962
1963/******************************************************************************
1964 * ValidateVartype [INTERNAL]
1965 *
1966 * Used internally by the hi-level Variant API to determine
1967 * if the vartypes are valid.
1968 */
1969static HRESULT WINAPI ValidateVariantType( VARTYPE vt )
1970{
1971 HRESULT res = S_OK;
1972
1973 /* check if we have a valid argument.
1974 */
1975 if( vt & VT_BYREF )
1976 {
1977 /* if by reference check that the type is in
1978 * the valid range and that it is not of empty or null type
1979 */
1980 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
1981 ( vt & VT_TYPEMASK ) == VT_NULL ||
1982 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
1983 {
1984 res = DISP_E_BADVARTYPE;
1985 }
1986
1987 }
1988 else
1989 {
1990 res = ValidateVtRange( vt );
1991 }
1992
1993 return res;
1994}
1995
1996/******************************************************************************
1997 * ValidateVt [INTERNAL]
1998 *
1999 * Used internally by the hi-level Variant API to determine
2000 * if the vartypes are valid.
2001 */
2002static HRESULT WINAPI ValidateVt( VARTYPE vt )
2003{
2004 HRESULT res = S_OK;
2005
2006 /* check if we have a valid argument.
2007 */
2008 if( vt & VT_BYREF )
2009 {
2010 /* if by reference check that the type is in
2011 * the valid range and that it is not of empty or null type
2012 */
2013 if( ( vt & VT_TYPEMASK ) == VT_EMPTY ||
2014 ( vt & VT_TYPEMASK ) == VT_NULL ||
2015 ( vt & VT_TYPEMASK ) > VT_MAXVALIDTYPE )
2016 {
2017 res = DISP_E_BADVARTYPE;
2018 }
2019
2020 }
2021 else
2022 {
2023 res = ValidateVtRange( vt );
2024 }
2025
2026 return res;
2027}
2028
2029
2030
2031
2032
2033/******************************************************************************
2034 * VariantInit [OLEAUT32.8]
2035 *
2036 * Initializes the Variant. Unlike VariantClear it does not interpret
2037 * the current contents of the Variant.
2038 */
2039void WINAPI VariantInit(VARIANTARG* pvarg)
2040{
2041 TRACE("%s: (%p)\n", __FUNCTION__, pvarg);
2042
2043 memset(pvarg, 0, sizeof (VARIANTARG));
2044 V_VT(pvarg) = VT_EMPTY;
2045
2046 return;
2047}
2048
2049/******************************************************************************
2050 * VariantClear [OLEAUT32.9]
2051 *
2052 * This function clears the VARIANT by setting the vt field to VT_EMPTY. It also
2053 * sets the wReservedX field to 0. The current contents of the VARIANT are
2054 * freed. If the vt is VT_BSTR the string is freed. If VT_DISPATCH the object is
2055 * released. If VT_ARRAY the array is freed.
2056 */
2057HRESULT WINAPI VariantClear(VARIANTARG* pvarg)
2058{
2059 HRESULT res = S_OK;
2060 TRACE("%s: (%p)\n",__FUNCTION__, pvarg);
2061
2062 res = ValidateVariantType( V_VT(pvarg) );
2063 if( res == S_OK )
2064 {
2065 if( !( V_VT(pvarg) & VT_BYREF ) )
2066 {
2067 /*
2068 * The VT_ARRAY flag is a special case of a safe array.
2069 */
2070 if ( (V_VT(pvarg) & VT_ARRAY) != 0)
2071 {
2072 SafeArrayDestroy(V_UNION(pvarg,parray));
2073 }
2074 else
2075 {
2076 switch( V_VT(pvarg) & VT_TYPEMASK )
2077 {
2078 case( VT_BSTR ):
2079 SysFreeString( V_UNION(pvarg,bstrVal) );
2080 break;
2081 case( VT_DISPATCH ):
2082 if(V_UNION(pvarg,pdispVal)!=NULL)
2083 ICOM_CALL(Release,V_UNION(pvarg,pdispVal));
2084 break;
2085 case( VT_VARIANT ):
2086 VariantClear(V_UNION(pvarg,pvarVal));
2087 break;
2088 case( VT_UNKNOWN ):
2089 if(V_UNION(pvarg,punkVal)!=NULL)
2090 ICOM_CALL(Release,V_UNION(pvarg,punkVal));
2091 break;
2092 case( VT_SAFEARRAY ):
2093 SafeArrayDestroy(V_UNION(pvarg,parray));
2094 break;
2095 default:
2096 break;
2097 }
2098 }
2099 }
2100
2101 /*
2102 * Empty all the fields and mark the type as empty.
2103 */
2104 memset(pvarg, 0, sizeof (VARIANTARG));
2105 V_VT(pvarg) = VT_EMPTY;
2106 }
2107
2108 return res;
2109}
2110
2111/******************************************************************************
2112 * VariantCopy [OLEAUT32.10]
2113 *
2114 * Frees up the designation variant and makes a copy of the source.
2115 */
2116HRESULT WINAPI VariantCopy(VARIANTARG* pvargDest, VARIANTARG* pvargSrc)
2117{
2118 HRESULT res = S_OK;
2119
2120 TRACE("%s: (Dest: %p, Src: %p), vt=%d\n", __FUNCTION__, pvargDest, pvargSrc, V_VT(pvargSrc));
2121
2122 res = ValidateVariantType( V_VT(pvargSrc) );
2123
2124 /* If the pointer are to the same variant we don't need
2125 * to do anything.
2126 */
2127 if( pvargDest != pvargSrc && res == S_OK )
2128 {
2129 res = VariantClear( pvargDest );
2130
2131 if( res == S_OK )
2132 {
2133 if( V_VT(pvargSrc) & VT_BYREF )
2134 {
2135 /* In the case of byreference we only need
2136 * to copy the pointer.
2137 */
2138 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
2139 V_VT(pvargDest) = V_VT(pvargSrc);
2140 }
2141 else
2142 {
2143 /*
2144 * The VT_ARRAY flag is another way to designate a safe array.
2145 */
2146 if (V_VT(pvargSrc) & VT_ARRAY)
2147 {
2148 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
2149 }
2150 else
2151 {
2152 /* In the case of by value we need to
2153 * copy the actual value. In the case of
2154 * VT_BSTR a copy of the string is made,
2155 * if VT_DISPATCH or VT_IUNKNOWN AddRef is
2156 * called to increment the object's reference count.
2157 */
2158 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2159 {
2160 case( VT_BSTR ):
2161 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( V_UNION(pvargSrc,bstrVal) );
2162 break;
2163 case( VT_DISPATCH ):
2164 V_UNION(pvargDest,pdispVal) = V_UNION(pvargSrc,pdispVal);
2165 if (V_UNION(pvargDest,pdispVal)!=NULL)
2166 ICOM_CALL(AddRef,V_UNION(pvargDest,pdispVal));
2167 break;
2168 case( VT_VARIANT ):
2169 VariantCopy(V_UNION(pvargDest,pvarVal),V_UNION(pvargSrc,pvarVal));
2170 break;
2171 case( VT_UNKNOWN ):
2172 V_UNION(pvargDest,punkVal) = V_UNION(pvargSrc,punkVal);
2173 if (V_UNION(pvargDest,pdispVal)!=NULL)
2174 ICOM_CALL(AddRef,V_UNION(pvargDest,punkVal));
2175 break;
2176 case( VT_SAFEARRAY ):
2177 SafeArrayCopy(V_UNION(pvargSrc,parray), &V_UNION(pvargDest,parray));
2178 break;
2179 default:
2180 pvargDest->n1.n2.n3 = pvargSrc->n1.n2.n3;
2181 break;
2182 }
2183 }
2184
2185 V_VT(pvargDest) = V_VT(pvargSrc);
2186 }
2187 }
2188 }
2189
2190 return res;
2191}
2192
2193
2194/******************************************************************************
2195 * VariantCopyInd [OLEAUT32.11]
2196 *
2197 * Frees up the destination variant and makes a copy of the source. If
2198 * the source is of type VT_BYREF it performs the necessary indirections.
2199 */
2200HRESULT WINAPI VariantCopyInd(VARIANT* pvargDest, VARIANTARG* pvargSrc)
2201{
2202 HRESULT res = S_OK;
2203
2204 TRACE("(%p, %p)\n", pvargDest, pvargSrc);
2205
2206 res = ValidateVariantType( V_VT(pvargSrc) );
2207
2208 if( res != S_OK )
2209 return res;
2210
2211 if( V_VT(pvargSrc) & VT_BYREF )
2212 {
2213 VARIANTARG varg;
2214 VariantInit( &varg );
2215
2216 /* handle the in place copy.
2217 */
2218 if( pvargDest == pvargSrc )
2219 {
2220 /* we will use a copy of the source instead.
2221 */
2222 res = VariantCopy( &varg, pvargSrc );
2223 pvargSrc = &varg;
2224 }
2225
2226 if( res == S_OK )
2227 {
2228 res = VariantClear( pvargDest );
2229
2230 if( res == S_OK )
2231 {
2232 /*
2233 * The VT_ARRAY flag is another way to designate a safearray variant.
2234 */
2235 if ( V_VT(pvargSrc) & VT_ARRAY)
2236 {
2237 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2238 }
2239 else
2240 {
2241 /* In the case of by reference we need
2242 * to copy the date pointed to by the variant.
2243 */
2244
2245 /* Get the variant type.
2246 */
2247 switch( V_VT(pvargSrc) & VT_TYPEMASK )
2248 {
2249 case( VT_BSTR ):
2250 V_UNION(pvargDest,bstrVal) = SYSDUPSTRING( *(V_UNION(pvargSrc,pbstrVal)) );
2251 break;
2252 case( VT_DISPATCH ):
2253 break;
2254 case( VT_VARIANT ):
2255 {
2256 /* Prevent from cycling. According to tests on
2257 * VariantCopyInd in Windows and the documentation
2258 * this API dereferences the inner Variants to only one depth.
2259 * If the inner Variant itself contains an
2260 * other inner variant the E_INVALIDARG error is
2261 * returned.
2262 */
2263 if( pvargSrc->n1.n2.wReserved1 & PROCESSING_INNER_VARIANT )
2264 {
2265 /* If we get here we are attempting to deference
2266 * an inner variant that that is itself contained
2267 * in an inner variant so report E_INVALIDARG error.
2268 */
2269 res = E_INVALIDARG;
2270 }
2271 else
2272 {
2273 /* Set the processing inner variant flag.
2274 * We will set this flag in the inner variant
2275 * that will be passed to the VariantCopyInd function.
2276 */
2277 (V_UNION(pvargSrc,pvarVal))->n1.n2.wReserved1 |= PROCESSING_INNER_VARIANT;
2278
2279 /* Dereference the inner variant.
2280 */
2281 res = VariantCopyInd( pvargDest, V_UNION(pvargSrc,pvarVal) );
2282 /* We must also copy its type, I think.
2283 */
2284 V_VT(pvargSrc) = V_VT(V_UNION(pvargSrc,pvarVal));
2285 }
2286 }
2287 break;
2288 case( VT_UNKNOWN ):
2289 break;
2290 case( VT_SAFEARRAY ):
2291 SafeArrayCopy(*V_UNION(pvargSrc,pparray), &V_UNION(pvargDest,parray));
2292 break;
2293 default:
2294 /* This is a by reference Variant which means that the union
2295 * part of the Variant contains a pointer to some data of
2296 * type "V_VT(pvargSrc) & VT_TYPEMASK".
2297 * We will deference this data in a generic fashion using
2298 * the void pointer "Variant.u.byref".
2299 * We will copy this data into the union of the destination
2300 * Variant.
2301 */
2302 memcpy( &pvargDest->n1.n2.n3, V_UNION(pvargSrc,byref), SizeOfVariantData( pvargSrc ) );
2303 break;
2304 }
2305 }
2306
2307 if (res == S_OK) V_VT(pvargDest) = V_VT(pvargSrc) & VT_TYPEMASK;
2308 }
2309 }
2310
2311 /* this should not fail.
2312 */
2313 VariantClear( &varg );
2314 }
2315 else
2316 {
2317 res = VariantCopy( pvargDest, pvargSrc );
2318 }
2319
2320 return res;
2321}
2322
2323/******************************************************************************
2324 * VariantChangeType [OLEAUT32.12]
2325 */
2326HRESULT WINAPI VariantChangeType(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2327 USHORT wFlags, VARTYPE vt)
2328{
2329 return VariantChangeTypeEx( pvargDest, pvargSrc, 0, wFlags, vt );
2330}
2331
2332/******************************************************************************
2333 * VariantChangeTypeEx [OLEAUT32.147]
2334 */
2335HRESULT WINAPI VariantChangeTypeEx(VARIANTARG* pvargDest, VARIANTARG* pvargSrc,
2336 LCID lcid, USHORT wFlags, VARTYPE vt)
2337{
2338 HRESULT res = S_OK;
2339 VARIANTARG varg;
2340 VariantInit( &varg );
2341 TRACE("%s: (Dest: %p, source: %p, LCID: %ld, wFlags: %u, VARTYPE: %u) vt=%d\n", __FUNCTION__, pvargDest, pvargSrc, lcid, wFlags, vt, V_VT(pvargSrc));
2342 TRACE("Src Var:\n");
2343 dump_Variant(pvargSrc);
2344
2345 /* validate our source argument.
2346 */
2347 res = ValidateVariantType( V_VT(pvargSrc) );
2348
2349 /* validate the vartype.
2350 */
2351 if( res == S_OK )
2352 {
2353 res = ValidateVt( vt );
2354 }
2355
2356 /* if we are doing an in-place conversion make a copy of the source.
2357 */
2358 if( res == S_OK && pvargDest == pvargSrc )
2359 {
2360 res = VariantCopy( &varg, pvargSrc );
2361 pvargSrc = &varg;
2362 }
2363
2364 if( res == S_OK )
2365 {
2366 /* free up the destination variant.
2367 */
2368 res = VariantClear( pvargDest );
2369 }
2370
2371 if( res == S_OK )
2372 {
2373 if( V_VT(pvargSrc) & VT_BYREF )
2374 {
2375 /* Convert the source variant to a "byvalue" variant.
2376 */
2377 VARIANTARG Variant;
2378
2379 VariantInit( &Variant );
2380 res = VariantCopyInd( &Variant, pvargSrc );
2381 if( res == S_OK )
2382 {
2383 res = Coerce( pvargDest, lcid, wFlags, &Variant, vt );
2384 /* this should not fail.
2385 */
2386 VariantClear( &Variant );
2387 }
2388 }
2389 else
2390 {
2391 /* Use the current "byvalue" source variant.
2392 */
2393 res = Coerce( pvargDest, lcid, wFlags, pvargSrc, vt );
2394 }
2395 }
2396 /* this should not fail.
2397 */
2398 VariantClear( &varg );
2399
2400 /* set the type of the destination
2401 */
2402 if ( res == S_OK )
2403 V_VT(pvargDest) = vt;
2404
2405 TRACE("Dest Var (re: %x)\n", res);
2406 dump_Variant(pvargDest);
2407
2408 return res;
2409}
2410
2411
2412
2413
2414/******************************************************************************
2415 * VarUI1FromI2 [OLEAUT32.130]
2416 */
2417HRESULT WINAPI VarUI1FromI2(short sIn, BYTE* pbOut)
2418{
2419 TRACE("( %d, %p ), stub\n", sIn, pbOut );
2420
2421 /* Check range of value.
2422 */
2423 if( sIn < UI1_MIN || sIn > UI1_MAX )
2424 {
2425 return DISP_E_OVERFLOW;
2426 }
2427
2428 *pbOut = (BYTE) sIn;
2429
2430 return S_OK;
2431}
2432
2433/******************************************************************************
2434 * VarUI1FromI4 [OLEAUT32.131]
2435 */
2436HRESULT WINAPI VarUI1FromI4(LONG lIn, BYTE* pbOut)
2437{
2438 TRACE("( %ld, %p ), stub\n", lIn, pbOut );
2439
2440 /* Check range of value.
2441 */
2442 if( lIn < UI1_MIN || lIn > UI1_MAX )
2443 {
2444 return DISP_E_OVERFLOW;
2445 }
2446
2447 *pbOut = (BYTE) lIn;
2448
2449 return S_OK;
2450}
2451
2452
2453/******************************************************************************
2454 * VarUI1FromR4 [OLEAUT32.132]
2455 */
2456HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
2457{
2458 TRACE("( %f, %p ), stub\n", fltIn, pbOut );
2459
2460 /* Check range of value.
2461 */
2462 fltIn = round( fltIn );
2463 if( fltIn < UI1_MIN || fltIn > UI1_MAX )
2464 {
2465 return DISP_E_OVERFLOW;
2466 }
2467
2468 *pbOut = (BYTE) fltIn;
2469
2470 return S_OK;
2471}
2472
2473/******************************************************************************
2474 * VarUI1FromR8 [OLEAUT32.133]
2475 */
2476HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
2477{
2478 TRACE("( %f, %p ), stub\n", dblIn, pbOut );
2479
2480 /* Check range of value.
2481 */
2482 dblIn = round( dblIn );
2483 if( dblIn < UI1_MIN || dblIn > UI1_MAX )
2484 {
2485 return DISP_E_OVERFLOW;
2486 }
2487
2488 *pbOut = (BYTE) dblIn;
2489
2490 return S_OK;
2491}
2492
2493/******************************************************************************
2494 * VarUI1FromDate [OLEAUT32.135]
2495 */
2496HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
2497{
2498 TRACE("( %f, %p ), stub\n", dateIn, pbOut );
2499
2500 /* Check range of value.
2501 */
2502 dateIn = round( dateIn );
2503 if( dateIn < UI1_MIN || dateIn > UI1_MAX )
2504 {
2505 return DISP_E_OVERFLOW;
2506 }
2507
2508 *pbOut = (BYTE) dateIn;
2509
2510 return S_OK;
2511}
2512
2513/******************************************************************************
2514 * VarUI1FromBool [OLEAUT32.138]
2515 */
2516HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
2517{
2518 TRACE("( %d, %p ), stub\n", boolIn, pbOut );
2519
2520 *pbOut = (BYTE) boolIn;
2521
2522 return S_OK;
2523}
2524
2525/******************************************************************************
2526 * VarUI1FromI1 [OLEAUT32.237]
2527 */
2528HRESULT WINAPI VarUI1FromI1(CHAR cIn, BYTE* pbOut)
2529{
2530 TRACE("( %c, %p ), stub\n", cIn, pbOut );
2531
2532 *pbOut = cIn;
2533
2534 return S_OK;
2535}
2536
2537/******************************************************************************
2538 * VarUI1FromUI2 [OLEAUT32.238]
2539 */
2540HRESULT WINAPI VarUI1FromUI2(USHORT uiIn, BYTE* pbOut)
2541{
2542 TRACE("( %d, %p ), stub\n", uiIn, pbOut );
2543
2544 /* Check range of value.
2545 */
2546 if( uiIn > UI1_MAX )
2547 {
2548 return DISP_E_OVERFLOW;
2549 }
2550
2551 *pbOut = (BYTE) uiIn;
2552
2553 return S_OK;
2554}
2555
2556/******************************************************************************
2557 * VarUI1FromUI4 [OLEAUT32.239]
2558 */
2559HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
2560{
2561 TRACE("( %ld, %p ), stub\n", ulIn, pbOut );
2562
2563 /* Check range of value.
2564 */
2565 if( ulIn > UI1_MAX )
2566 {
2567 return DISP_E_OVERFLOW;
2568 }
2569
2570 *pbOut = (BYTE) ulIn;
2571
2572 return S_OK;
2573}
2574
2575
2576/******************************************************************************
2577 * VarUI1FromStr [OLEAUT32.136]
2578 */
2579HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
2580{
2581 double dValue = 0.0;
2582 LPSTR pNewString = NULL;
2583
2584 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, pbOut );
2585
2586 /* Check if we have a valid argument
2587 */
2588 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2589 RemoveCharacterFromString( pNewString, "," );
2590 if( IsValidRealString( pNewString ) == FALSE )
2591 {
2592 return DISP_E_TYPEMISMATCH;
2593 }
2594
2595 /* Convert the valid string to a floating point number.
2596 */
2597 dValue = atof( pNewString );
2598
2599 /* We don't need the string anymore so free it.
2600 */
2601 HeapFree( GetProcessHeap(), 0 , pNewString );
2602
2603 /* Check range of value.
2604 */
2605 dValue = round( dValue );
2606 if( dValue < UI1_MIN || dValue > UI1_MAX )
2607 {
2608 return DISP_E_OVERFLOW;
2609 }
2610
2611 *pbOut = (BYTE) dValue;
2612
2613 return S_OK;
2614}
2615
2616/**********************************************************************
2617 * VarUI1FromCy [OLEAUT32.134]
2618 * Convert currency to unsigned char
2619 */
2620HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut) {
2621 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2622
2623 if (t > UI1_MAX || t < UI1_MIN) return DISP_E_OVERFLOW;
2624
2625 *pbOut = (BYTE)t;
2626 return S_OK;
2627}
2628
2629/******************************************************************************
2630 * VarI2FromUI1 [OLEAUT32.48]
2631 */
2632HRESULT WINAPI VarI2FromUI1(BYTE bIn, short* psOut)
2633{
2634 TRACE("( 0x%08x, %p ), stub\n", bIn, psOut );
2635
2636 *psOut = (short) bIn;
2637
2638 return S_OK;
2639}
2640
2641/******************************************************************************
2642 * VarI2FromI4 [OLEAUT32.49]
2643 */
2644HRESULT WINAPI VarI2FromI4(LONG lIn, short* psOut)
2645{
2646 TRACE("( %lx, %p ), stub\n", lIn, psOut );
2647
2648 /* Check range of value.
2649 */
2650 if( lIn < I2_MIN || lIn > I2_MAX )
2651 {
2652 return DISP_E_OVERFLOW;
2653 }
2654
2655 *psOut = (short) lIn;
2656
2657 return S_OK;
2658}
2659
2660/******************************************************************************
2661 * VarI2FromR4 [OLEAUT32.50]
2662 */
2663HRESULT WINAPI VarI2FromR4(FLOAT fltIn, short* psOut)
2664{
2665 TRACE("( %f, %p ), stub\n", fltIn, psOut );
2666
2667 /* Check range of value.
2668 */
2669 fltIn = round( fltIn );
2670 if( fltIn < I2_MIN || fltIn > I2_MAX )
2671 {
2672 return DISP_E_OVERFLOW;
2673 }
2674
2675 *psOut = (short) fltIn;
2676
2677 return S_OK;
2678}
2679
2680/******************************************************************************
2681 * VarI2FromR8 [OLEAUT32.51]
2682 */
2683HRESULT WINAPI VarI2FromR8(double dblIn, short* psOut)
2684{
2685 TRACE("( %f, %p ), stub\n", dblIn, psOut );
2686
2687 /* Check range of value.
2688 */
2689 dblIn = round( dblIn );
2690 if( dblIn < I2_MIN || dblIn > I2_MAX )
2691 {
2692 return DISP_E_OVERFLOW;
2693 }
2694
2695 *psOut = (short) dblIn;
2696
2697 return S_OK;
2698}
2699
2700/******************************************************************************
2701 * VarI2FromDate [OLEAUT32.53]
2702 */
2703HRESULT WINAPI VarI2FromDate(DATE dateIn, short* psOut)
2704{
2705 TRACE("( %f, %p ), stub\n", dateIn, psOut );
2706
2707 /* Check range of value.
2708 */
2709 dateIn = round( dateIn );
2710 if( dateIn < I2_MIN || dateIn > I2_MAX )
2711 {
2712 return DISP_E_OVERFLOW;
2713 }
2714
2715 *psOut = (short) dateIn;
2716
2717 return S_OK;
2718}
2719
2720/******************************************************************************
2721 * VarI2FromBool [OLEAUT32.56]
2722 */
2723HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, short* psOut)
2724{
2725 TRACE("( %d, %p ), stub\n", boolIn, psOut );
2726
2727 *psOut = (short) boolIn;
2728
2729 return S_OK;
2730}
2731
2732/******************************************************************************
2733 * VarI2FromI1 [OLEAUT32.205]
2734 */
2735HRESULT WINAPI VarI2FromI1(CHAR cIn, short* psOut)
2736{
2737 TRACE("( %c, %p ), stub\n", cIn, psOut );
2738
2739 *psOut = (short) cIn;
2740
2741 return S_OK;
2742}
2743
2744/******************************************************************************
2745 * VarI2FromUI2 [OLEAUT32.206]
2746 */
2747HRESULT WINAPI VarI2FromUI2(USHORT uiIn, short* psOut)
2748{
2749 TRACE("( %d, %p ), stub\n", uiIn, psOut );
2750
2751 /* Check range of value.
2752 */
2753 if( uiIn > I2_MAX )
2754 {
2755 return DISP_E_OVERFLOW;
2756 }
2757
2758 *psOut = (short) uiIn;
2759
2760 return S_OK;
2761}
2762
2763/******************************************************************************
2764 * VarI2FromUI4 [OLEAUT32.207]
2765 */
2766HRESULT WINAPI VarI2FromUI4(ULONG ulIn, short* psOut)
2767{
2768 TRACE("( %lx, %p ), stub\n", ulIn, psOut );
2769
2770 /* Check range of value.
2771 */
2772 if( ulIn < I2_MIN || ulIn > I2_MAX )
2773 {
2774 return DISP_E_OVERFLOW;
2775 }
2776
2777 *psOut = (short) ulIn;
2778
2779 return S_OK;
2780}
2781
2782/******************************************************************************
2783 * VarI2FromStr [OLEAUT32.54]
2784 */
2785HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, short* psOut)
2786{
2787 double dValue = 0.0;
2788 LPSTR pNewString = NULL;
2789
2790 TRACE("( %p, 0x%08lx, 0x%08lx, %p ), stub\n", strIn, lcid, dwFlags, psOut );
2791
2792 /* Check if we have a valid argument
2793 */
2794 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2795 RemoveCharacterFromString( pNewString, "," );
2796 if( IsValidRealString( pNewString ) == FALSE )
2797 {
2798 return DISP_E_TYPEMISMATCH;
2799 }
2800
2801 /* Convert the valid string to a floating point number.
2802 */
2803 dValue = atof( pNewString );
2804
2805 /* We don't need the string anymore so free it.
2806 */
2807 HeapFree( GetProcessHeap(), 0, pNewString );
2808
2809 /* Check range of value.
2810 */
2811 dValue = round( dValue );
2812 if( dValue < I2_MIN || dValue > I2_MAX )
2813 {
2814 return DISP_E_OVERFLOW;
2815 }
2816
2817 *psOut = (short) dValue;
2818
2819 return S_OK;
2820}
2821
2822/**********************************************************************
2823 * VarI2FromCy [OLEAUT32.52]
2824 * Convert currency to signed short
2825 */
2826HRESULT WINAPI VarI2FromCy(CY cyIn, short* psOut) {
2827 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
2828
2829 if (t > I2_MAX || t < I2_MIN) return DISP_E_OVERFLOW;
2830
2831 *psOut = (SHORT)t;
2832 return S_OK;
2833}
2834
2835/******************************************************************************
2836 * VarI4FromUI1 [OLEAUT32.58]
2837 */
2838HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG* plOut)
2839{
2840 TRACE("( %X, %p ), stub\n", bIn, plOut );
2841
2842 *plOut = (LONG) bIn;
2843
2844 return S_OK;
2845}
2846
2847
2848/******************************************************************************
2849 * VarI4FromR4 [OLEAUT32.60]
2850 */
2851HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG* plOut)
2852{
2853 TRACE("( %f, %p ), stub\n", fltIn, plOut );
2854
2855 /* Check range of value.
2856 */
2857 fltIn = round( fltIn );
2858 if( fltIn < I4_MIN || fltIn > I4_MAX )
2859 {
2860 return DISP_E_OVERFLOW;
2861 }
2862
2863 *plOut = (LONG) fltIn;
2864
2865 return S_OK;
2866}
2867
2868/******************************************************************************
2869 * VarI4FromR8 [OLEAUT32.61]
2870 */
2871HRESULT WINAPI VarI4FromR8(double dblIn, LONG* plOut)
2872{
2873 TRACE("( %f, %p ), stub\n", dblIn, plOut );
2874
2875 /* Check range of value.
2876 */
2877 dblIn = round( dblIn );
2878 if( dblIn < I4_MIN || dblIn > I4_MAX )
2879 {
2880 return DISP_E_OVERFLOW;
2881 }
2882
2883 *plOut = (LONG) dblIn;
2884
2885 return S_OK;
2886}
2887
2888/******************************************************************************
2889 * VarI4FromDate [OLEAUT32.63]
2890 */
2891HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG* plOut)
2892{
2893 TRACE("( %f, %p ), stub\n", dateIn, plOut );
2894
2895 /* Check range of value.
2896 */
2897 dateIn = round( dateIn );
2898 if( dateIn < I4_MIN || dateIn > I4_MAX )
2899 {
2900 return DISP_E_OVERFLOW;
2901 }
2902
2903 *plOut = (LONG) dateIn;
2904
2905 return S_OK;
2906}
2907
2908/******************************************************************************
2909 * VarI4FromBool [OLEAUT32.66]
2910 */
2911HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG* plOut)
2912{
2913 TRACE("( %d, %p ), stub\n", boolIn, plOut );
2914
2915 *plOut = (LONG) boolIn;
2916
2917 return S_OK;
2918}
2919
2920/******************************************************************************
2921 * VarI4FromI1 [OLEAUT32.209]
2922 */
2923HRESULT WINAPI VarI4FromI1(CHAR cIn, LONG* plOut)
2924{
2925 TRACE("( %c, %p ), stub\n", cIn, plOut );
2926
2927 *plOut = (LONG) cIn;
2928
2929 return S_OK;
2930}
2931
2932/******************************************************************************
2933 * VarI4FromUI2 [OLEAUT32.210]
2934 */
2935HRESULT WINAPI VarI4FromUI2(USHORT uiIn, LONG* plOut)
2936{
2937 TRACE("( %d, %p ), stub\n", uiIn, plOut );
2938
2939 *plOut = (LONG) uiIn;
2940
2941 return S_OK;
2942}
2943
2944/******************************************************************************
2945 * VarI4FromUI4 [OLEAUT32.211]
2946 */
2947HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG* plOut)
2948{
2949 TRACE("( %lx, %p ), stub\n", ulIn, plOut );
2950
2951 /* Check range of value.
2952 */
2953 if( ulIn < I4_MIN || ulIn > I4_MAX )
2954 {
2955 return DISP_E_OVERFLOW;
2956 }
2957
2958 *plOut = (LONG) ulIn;
2959
2960 return S_OK;
2961}
2962
2963/******************************************************************************
2964 * VarI4FromI2 [OLEAUT32.59]
2965 */
2966HRESULT WINAPI VarI4FromI2(short sIn, LONG* plOut)
2967{
2968 TRACE("( %d, %p ), stub\n", sIn, plOut );
2969
2970 *plOut = (LONG) sIn;
2971
2972 return S_OK;
2973}
2974
2975/******************************************************************************
2976 * VarI4FromStr [OLEAUT32.64]
2977 */
2978HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG* plOut)
2979{
2980 double dValue = 0.0;
2981 LPSTR pNewString = NULL;
2982
2983 TRACE("%s: ( strIn: %p -> %s, lcid: 0x%08lx, dwFlags: 0x%08lx, plOut: %p ), stub\n", __FUNCTION__, strIn, debugstr_w(strIn), lcid, dwFlags, plOut );
2984
2985 /* Check if we have a valid argument
2986 */
2987 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
2988 RemoveCharacterFromString( pNewString, "," );
2989 if( IsValidRealString( pNewString ) == FALSE )
2990 {
2991 return DISP_E_TYPEMISMATCH;
2992 }
2993
2994 /* Convert the valid string to a floating point number.
2995 */
2996 dValue = atof( pNewString );
2997
2998 /* We don't need the string anymore so free it.
2999 */
3000 HeapFree( GetProcessHeap(), 0, pNewString );
3001
3002 /* Check range of value.
3003 */
3004 dValue = round( dValue );
3005 if( dValue < I4_MIN || dValue > I4_MAX )
3006 {
3007 return DISP_E_OVERFLOW;
3008 }
3009
3010 *plOut = (LONG) dValue;
3011
3012 return S_OK;
3013}
3014
3015/**********************************************************************
3016 * VarI4FromCy [OLEAUT32.62]
3017 * Convert currency to signed long
3018 */
3019HRESULT WINAPI VarI4FromCy(CY cyIn, LONG* plOut) {
3020 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3021
3022 if (t > I4_MAX || t < I4_MIN) return DISP_E_OVERFLOW;
3023
3024 *plOut = (LONG)t;
3025 return S_OK;
3026}
3027
3028/******************************************************************************
3029 * VarR4FromUI1 [OLEAUT32.68]
3030 */
3031HRESULT WINAPI VarR4FromUI1(BYTE bIn, FLOAT* pfltOut)
3032{
3033 TRACE("( %X, %p ), stub\n", bIn, pfltOut );
3034
3035 *pfltOut = (FLOAT) bIn;
3036
3037 return S_OK;
3038}
3039
3040/******************************************************************************
3041 * VarR4FromI2 [OLEAUT32.69]
3042 */
3043HRESULT WINAPI VarR4FromI2(short sIn, FLOAT* pfltOut)
3044{
3045 TRACE("( %d, %p ), stub\n", sIn, pfltOut );
3046
3047 *pfltOut = (FLOAT) sIn;
3048
3049 return S_OK;
3050}
3051
3052/******************************************************************************
3053 * VarR4FromI4 [OLEAUT32.70]
3054 */
3055HRESULT WINAPI VarR4FromI4(LONG lIn, FLOAT* pfltOut)
3056{
3057 TRACE("( %lx, %p ), stub\n", lIn, pfltOut );
3058
3059 *pfltOut = (FLOAT) lIn;
3060
3061 return S_OK;
3062}
3063
3064/******************************************************************************
3065 * VarR4FromR8 [OLEAUT32.71]
3066 */
3067HRESULT WINAPI VarR4FromR8(double dblIn, FLOAT* pfltOut)
3068{
3069 TRACE("( %f, %p ), stub\n", dblIn, pfltOut );
3070
3071 /* Check range of value.
3072 */
3073 if( dblIn < -(FLT_MAX) || dblIn > FLT_MAX )
3074 {
3075 return DISP_E_OVERFLOW;
3076 }
3077
3078 *pfltOut = (FLOAT) dblIn;
3079
3080 return S_OK;
3081}
3082
3083/******************************************************************************
3084 * VarR4FromDate [OLEAUT32.73]
3085 */
3086HRESULT WINAPI VarR4FromDate(DATE dateIn, FLOAT* pfltOut)
3087{
3088 TRACE("( %f, %p ), stub\n", dateIn, pfltOut );
3089
3090 /* Check range of value.
3091 */
3092 if( dateIn < -(FLT_MAX) || dateIn > FLT_MAX )
3093 {
3094 return DISP_E_OVERFLOW;
3095 }
3096
3097 *pfltOut = (FLOAT) dateIn;
3098
3099 return S_OK;
3100}
3101
3102/******************************************************************************
3103 * VarR4FromBool [OLEAUT32.76]
3104 */
3105HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, FLOAT* pfltOut)
3106{
3107 TRACE("( %d, %p ), stub\n", boolIn, pfltOut );
3108
3109 *pfltOut = (FLOAT) boolIn;
3110
3111 return S_OK;
3112}
3113
3114/******************************************************************************
3115 * VarR4FromI1 [OLEAUT32.213]
3116 */
3117HRESULT WINAPI VarR4FromI1(CHAR cIn, FLOAT* pfltOut)
3118{
3119 TRACE("( %c, %p ), stub\n", cIn, pfltOut );
3120
3121 *pfltOut = (FLOAT) cIn;
3122
3123 return S_OK;
3124}
3125
3126/******************************************************************************
3127 * VarR4FromUI2 [OLEAUT32.214]
3128 */
3129HRESULT WINAPI VarR4FromUI2(USHORT uiIn, FLOAT* pfltOut)
3130{
3131 TRACE("( %d, %p ), stub\n", uiIn, pfltOut );
3132
3133 *pfltOut = (FLOAT) uiIn;
3134
3135 return S_OK;
3136}
3137
3138/******************************************************************************
3139 * VarR4FromUI4 [OLEAUT32.215]
3140 */
3141HRESULT WINAPI VarR4FromUI4(ULONG ulIn, FLOAT* pfltOut)
3142{
3143 TRACE("( %ld, %p ), stub\n", ulIn, pfltOut );
3144
3145 *pfltOut = (FLOAT) ulIn;
3146
3147 return S_OK;
3148}
3149
3150/******************************************************************************
3151 * VarR4FromStr [OLEAUT32.74]
3152 */
3153HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, FLOAT* pfltOut)
3154{
3155 double dValue = 0.0;
3156 LPSTR pNewString = NULL;
3157
3158 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pfltOut );
3159
3160 /* Check if we have a valid argument
3161 */
3162 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3163 RemoveCharacterFromString( pNewString, "," );
3164 if( IsValidRealString( pNewString ) == FALSE )
3165 {
3166 return DISP_E_TYPEMISMATCH;
3167 }
3168
3169 /* Convert the valid string to a floating point number.
3170 */
3171 dValue = atof( pNewString );
3172
3173 /* We don't need the string anymore so free it.
3174 */
3175 HeapFree( GetProcessHeap(), 0, pNewString );
3176
3177 /* Check range of value.
3178 */
3179 if( dValue < -(FLT_MAX) || dValue > FLT_MAX )
3180 {
3181 return DISP_E_OVERFLOW;
3182 }
3183
3184 *pfltOut = (FLOAT) dValue;
3185
3186 return S_OK;
3187}
3188
3189/**********************************************************************
3190 * VarR4FromCy [OLEAUT32.72]
3191 * Convert currency to float
3192 */
3193HRESULT WINAPI VarR4FromCy(CY cyIn, FLOAT* pfltOut) {
3194 *pfltOut = (FLOAT)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3195
3196 return S_OK;
3197}
3198
3199/******************************************************************************
3200 * VarR8FromUI1 [OLEAUT32.78]
3201 */
3202HRESULT WINAPI VarR8FromUI1(BYTE bIn, double* pdblOut)
3203{
3204 TRACE("( %d, %p ), stub\n", bIn, pdblOut );
3205
3206 *pdblOut = (double) bIn;
3207
3208 return S_OK;
3209}
3210
3211/******************************************************************************
3212 * VarR8FromI2 [OLEAUT32.79]
3213 */
3214HRESULT WINAPI VarR8FromI2(short sIn, double* pdblOut)
3215{
3216 TRACE("( %d, %p ), stub\n", sIn, pdblOut );
3217
3218 *pdblOut = (double) sIn;
3219
3220 return S_OK;
3221}
3222
3223/******************************************************************************
3224 * VarR8FromI4 [OLEAUT32.80]
3225 */
3226HRESULT WINAPI VarR8FromI4(LONG lIn, double* pdblOut)
3227{
3228 TRACE("( %ld, %p ), stub\n", lIn, pdblOut );
3229
3230 *pdblOut = (double) lIn;
3231
3232 return S_OK;
3233}
3234
3235/******************************************************************************
3236 * VarR8FromR4 [OLEAUT32.81]
3237 */
3238HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double* pdblOut)
3239{
3240 TRACE("( %f, %p ), stub\n", fltIn, pdblOut );
3241
3242 *pdblOut = (double) fltIn;
3243
3244 return S_OK;
3245}
3246
3247/******************************************************************************
3248 * VarR8FromDate [OLEAUT32.83]
3249 */
3250HRESULT WINAPI VarR8FromDate(DATE dateIn, double* pdblOut)
3251{
3252 TRACE("( %f, %p ), stub\n", dateIn, pdblOut );
3253
3254 *pdblOut = (double) dateIn;
3255
3256 return S_OK;
3257}
3258
3259/******************************************************************************
3260 * VarR8FromBool [OLEAUT32.86]
3261 */
3262HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double* pdblOut)
3263{
3264 TRACE("( %d, %p ), stub\n", boolIn, pdblOut );
3265
3266 *pdblOut = (double) boolIn;
3267
3268 return S_OK;
3269}
3270
3271/******************************************************************************
3272 * VarR8FromI1 [OLEAUT32.217]
3273 */
3274HRESULT WINAPI VarR8FromI1(CHAR cIn, double* pdblOut)
3275{
3276 TRACE("( %c, %p ), stub\n", cIn, pdblOut );
3277
3278 *pdblOut = (double) cIn;
3279
3280 return S_OK;
3281}
3282
3283/******************************************************************************
3284 * VarR8FromUI2 [OLEAUT32.218]
3285 */
3286HRESULT WINAPI VarR8FromUI2(USHORT uiIn, double* pdblOut)
3287{
3288 TRACE("( %d, %p ), stub\n", uiIn, pdblOut );
3289
3290 *pdblOut = (double) uiIn;
3291
3292 return S_OK;
3293}
3294
3295/******************************************************************************
3296 * VarR8FromUI4 [OLEAUT32.219]
3297 */
3298HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double* pdblOut)
3299{
3300 TRACE("( %ld, %p ), stub\n", ulIn, pdblOut );
3301
3302 *pdblOut = (double) ulIn;
3303
3304 return S_OK;
3305}
3306
3307#if 0
3308/******************************************************************************
3309 * VarR8FromStr [OLEAUT32.84]
3310 */
3311HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double* pdblOut)
3312{
3313 double dValue = 0.0;
3314 LPSTR pNewString = NULL;
3315
3316 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3317 TRACE("( %s, %ld, %ld, %p ), stub\n", pNewString, lcid, dwFlags, pdblOut );
3318
3319 /* Check if we have a valid argument
3320 */
3321 RemoveCharacterFromString( pNewString, "," );
3322 if( IsValidRealString( pNewString ) == FALSE )
3323 {
3324 return DISP_E_TYPEMISMATCH;
3325 }
3326
3327 /* Convert the valid string to a floating point number.
3328 */
3329 dValue = atof( pNewString );
3330
3331 /* We don't need the string anymore so free it.
3332 */
3333 HeapFree( GetProcessHeap(), 0, pNewString );
3334
3335 *pdblOut = dValue;
3336
3337 return S_OK;
3338}
3339#endif
3340
3341/************************************************************************
3342 * VarR8FromStr (OLEAUT32.84)
3343 *
3344 * Convert a VT_BSTR to a VT_R8.
3345 *
3346 * PARAMS
3347 * strIn [I] Source
3348 * lcid [I] LCID for the conversion
3349 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3350 * pDblOut [O] Destination
3351 *
3352 * RETURNS
3353 * Success: S_OK.
3354 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3355 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3356 */
3357HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3358{
3359 return _VarR8FromStr(strIn, lcid, dwFlags, pDblOut);
3360}
3361
3362/**********************************************************************
3363 * VarR8FromCy [OLEAUT32.82]
3364 * Convert currency to double
3365 */
3366HRESULT WINAPI VarR8FromCy(CY cyIn, double* pdblOut) {
3367 *pdblOut = (double)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3368 TRACE("%lu %ld -> %f\n", cyIn.s.Hi, cyIn.s.Lo, *pdblOut);
3369 return S_OK;
3370}
3371
3372/******************************************************************************
3373 * VarDateFromUI1 [OLEAUT32.88]
3374 */
3375HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
3376{
3377 TRACE("( %d, %p ), stub\n", bIn, pdateOut );
3378
3379 *pdateOut = (DATE) bIn;
3380
3381 return S_OK;
3382}
3383
3384/******************************************************************************
3385 * VarDateFromI2 [OLEAUT32.89]
3386 */
3387HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
3388{
3389 TRACE("( %d, %p ), stub\n", sIn, pdateOut );
3390
3391 *pdateOut = (DATE) sIn;
3392
3393 return S_OK;
3394}
3395
3396/******************************************************************************
3397 * VarDateFromI4 [OLEAUT32.90]
3398 */
3399HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
3400{
3401 TRACE("( %ld, %p ), stub\n", lIn, pdateOut );
3402
3403 if( lIn < DATE_MIN || lIn > DATE_MAX )
3404 {
3405 return DISP_E_OVERFLOW;
3406 }
3407
3408 *pdateOut = (DATE) lIn;
3409
3410 return S_OK;
3411}
3412
3413/******************************************************************************
3414 * VarDateFromR4 [OLEAUT32.91]
3415 */
3416HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
3417{
3418 TRACE("( %f, %p ), stub\n", fltIn, pdateOut );
3419
3420 if( ceil(fltIn) < DATE_MIN || floor(fltIn) > DATE_MAX )
3421 {
3422 return DISP_E_OVERFLOW;
3423 }
3424
3425 *pdateOut = (DATE) fltIn;
3426
3427 return S_OK;
3428}
3429
3430/******************************************************************************
3431 * VarDateFromR8 [OLEAUT32.92]
3432 */
3433HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
3434{
3435 TRACE("( %f, %p ), stub\n", dblIn, pdateOut );
3436
3437 if( ceil(dblIn) < DATE_MIN || floor(dblIn) > DATE_MAX )
3438 {
3439 return DISP_E_OVERFLOW;
3440 }
3441
3442 *pdateOut = (DATE) dblIn;
3443
3444 return S_OK;
3445}
3446
3447/******************************************************************************
3448 * VarDateFromStr [OLEAUT32.94]
3449 * The string representing the date is composed of two parts, a date and time.
3450 *
3451 * The format of the time is has follows:
3452 * hh[:mm][:ss][AM|PM]
3453 * Whitespace can be inserted anywhere between these tokens. A whitespace consists
3454 * of space and/or tab characters, which are ignored.
3455 *
3456 * The formats for the date part are has follows:
3457 * mm/[dd/][yy]yy
3458 * [dd/]mm/[yy]yy
3459 * [yy]yy/mm/dd
3460 * January dd[,] [yy]yy
3461 * dd January [yy]yy
3462 * [yy]yy January dd
3463 * Whitespace can be inserted anywhere between these tokens.
3464 *
3465 * The formats for the date and time string are has follows.
3466 * date[whitespace][time]
3467 * [time][whitespace]date
3468 *
3469 * These are the only characters allowed in a string representing a date and time:
3470 * [A-Z] [a-z] [0-9] ':' '-' '/' ',' ' ' '\t'
3471 */
3472HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
3473{
3474 HRESULT ret = S_OK;
3475 struct tm TM;
3476
3477 memset( &TM, 0, sizeof(TM) );
3478
3479 TRACE("( %p, %lx, %lx, %p ), stub\n", strIn, lcid, dwFlags, pdateOut );
3480
3481 if( DateTimeStringToTm( strIn, dwFlags, &TM ) )
3482 {
3483 if( TmToDATE( &TM, pdateOut ) == FALSE )
3484 {
3485 ret = E_INVALIDARG;
3486 }
3487 }
3488 else
3489 {
3490 ret = DISP_E_TYPEMISMATCH;
3491 }
3492 TRACE("Return value %f\n", *pdateOut);
3493 return ret;
3494}
3495
3496/******************************************************************************
3497 * VarDateFromI1 [OLEAUT32.221]
3498 */
3499HRESULT WINAPI VarDateFromI1(CHAR cIn, DATE* pdateOut)
3500{
3501 TRACE("( %c, %p ), stub\n", cIn, pdateOut );
3502
3503 *pdateOut = (DATE) cIn;
3504
3505 return S_OK;
3506}
3507
3508/******************************************************************************
3509 * VarDateFromUI2 [OLEAUT32.222]
3510 */
3511HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
3512{
3513 TRACE("( %d, %p ), stub\n", uiIn, pdateOut );
3514
3515 if( uiIn > DATE_MAX )
3516 {
3517 return DISP_E_OVERFLOW;
3518 }
3519
3520 *pdateOut = (DATE) uiIn;
3521
3522 return S_OK;
3523}
3524
3525/******************************************************************************
3526 * VarDateFromUI4 [OLEAUT32.223]
3527 */
3528HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
3529{
3530 TRACE("( %ld, %p ), stub\n", ulIn, pdateOut );
3531
3532 if( ulIn < DATE_MIN || ulIn > DATE_MAX )
3533 {
3534 return DISP_E_OVERFLOW;
3535 }
3536
3537 *pdateOut = (DATE) ulIn;
3538
3539 return S_OK;
3540}
3541
3542/******************************************************************************
3543 * VarDateFromBool [OLEAUT32.96]
3544 */
3545HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
3546{
3547 TRACE("( %d, %p ), stub\n", boolIn, pdateOut );
3548
3549 *pdateOut = (DATE) boolIn;
3550
3551 return S_OK;
3552}
3553
3554/**********************************************************************
3555 * VarDateFromCy [OLEAUT32.93]
3556 * Convert currency to date
3557 */
3558HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut) {
3559 *pdateOut = (DATE)((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
3560
3561 if (*pdateOut > DATE_MAX || *pdateOut < DATE_MIN) return DISP_E_TYPEMISMATCH;
3562 return S_OK;
3563}
3564
3565
3566
3567/******************************************************************************
3568 * VarBstrFromUI1 [OLEAUT32.108]
3569 */
3570HRESULT WINAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3571{
3572 TRACE("( %d, %ld, %ld, %p ), stub\n", bVal, lcid, dwFlags, pbstrOut );
3573 sprintf( pBuffer, "%d", bVal );
3574
3575 *pbstrOut = StringDupAtoBstr( pBuffer );
3576
3577 return S_OK;
3578}
3579
3580/******************************************************************************
3581 * VarBstrFromI2 [OLEAUT32.109]
3582 */
3583HRESULT WINAPI VarBstrFromI2(short iVal, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3584{
3585 TRACE("( %d, %ld, %ld, %p ), stub\n", iVal, lcid, dwFlags, pbstrOut );
3586 sprintf( pBuffer, "%d", iVal );
3587 *pbstrOut = StringDupAtoBstr( pBuffer );
3588
3589 return S_OK;
3590}
3591
3592/******************************************************************************
3593 * VarBstrFromI4 [OLEAUT32.110]
3594 */
3595HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3596{
3597 TRACE("( %ld, %ld, %ld, %p ), stub\n", lIn, lcid, dwFlags, pbstrOut );
3598
3599 sprintf( pBuffer, "%ld", lIn );
3600 *pbstrOut = StringDupAtoBstr( pBuffer );
3601
3602 return S_OK;
3603}
3604
3605/******************************************************************************
3606 * VarBstrFromR4 [OLEAUT32.111]
3607 */
3608HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3609{
3610 TRACE("( %f, %ld, %ld, %p ), stub\n", fltIn, lcid, dwFlags, pbstrOut );
3611
3612 sprintf( pBuffer, "%.7g", fltIn );
3613 *pbstrOut = StringDupAtoBstr( pBuffer );
3614
3615 return S_OK;
3616}
3617
3618/******************************************************************************
3619 * VarBstrFromR8 [OLEAUT32.112]
3620 */
3621HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3622{
3623 TRACE("( %f, %ld, %ld, %p ), stub\n", dblIn, lcid, dwFlags, pbstrOut );
3624
3625 sprintf( pBuffer, "%.15g", dblIn );
3626 *pbstrOut = StringDupAtoBstr( pBuffer );
3627
3628 return S_OK;
3629}
3630
3631/******************************************************************************
3632 * VarBstrFromCy [OLEAUT32.113]
3633 */
3634HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut) {
3635 HRESULT rc = S_OK;
3636 double curVal = 0.0;
3637
3638 TRACE("([cyIn], %08lx, %08lx, %p), partial stub (no flags handled).\n", lcid, dwFlags, pbstrOut);
3639
3640 /* Firstly get the currency in a double, then put it in a buffer */
3641 rc = VarR8FromCy(cyIn, &curVal);
3642 if (rc == S_OK) {
3643 sprintf(pBuffer, "%g", curVal);
3644 *pbstrOut = StringDupAtoBstr( pBuffer );
3645 }
3646 return rc;
3647}
3648
3649
3650/******************************************************************************
3651 * VarBstrFromDate [OLEAUT32.114]
3652 *
3653 * The date is implemented using an 8 byte floating-point number.
3654 * Days are represented by whole numbers increments starting with 0.00 as
3655 * being December 30 1899, midnight.
3656 * The hours are expressed as the fractional part of the number.
3657 * December 30 1899 at midnight = 0.00
3658 * January 1 1900 at midnight = 2.00
3659 * January 4 1900 at 6 AM = 5.25
3660 * January 4 1900 at noon = 5.50
3661 * December 29 1899 at midnight = -1.00
3662 * December 18 1899 at midnight = -12.00
3663 * December 18 1899 at 6AM = -12.25
3664 * December 18 1899 at 6PM = -12.75
3665 * December 19 1899 at midnight = -11.00
3666 * The tm structure is as follows:
3667 * struct tm {
3668 * int tm_sec; seconds after the minute - [0,59]
3669 * int tm_min; minutes after the hour - [0,59]
3670 * int tm_hour; hours since midnight - [0,23]
3671 * int tm_mday; day of the month - [1,31]
3672 * int tm_mon; months since January - [0,11]
3673 * int tm_year; years
3674 * int tm_wday; days since Sunday - [0,6]
3675 * int tm_yday; days since January 1 - [0,365]
3676 * int tm_isdst; daylight savings time flag
3677 * };
3678 */
3679HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3680{
3681 struct tm TM;
3682 memset( &TM, 0, sizeof(TM) );
3683
3684 TRACE("( %20.20f, %ld, %ld, %p ), stub\n", dateIn, lcid, dwFlags, pbstrOut );
3685
3686 if( DateToTm( dateIn, dwFlags, &TM ) == FALSE )
3687 {
3688 return E_INVALIDARG;
3689 }
3690
3691 if( dwFlags & VAR_DATEVALUEONLY )
3692 strftime( pBuffer, BUFFER_MAX, "%x", &TM );
3693 else if( dwFlags & VAR_TIMEVALUEONLY )
3694 strftime( pBuffer, BUFFER_MAX, "%X", &TM );
3695 else
3696 strftime( pBuffer, BUFFER_MAX, "%x %X", &TM );
3697
3698 TRACE("result: %s\n", pBuffer);
3699 *pbstrOut = StringDupAtoBstr( pBuffer );
3700 return S_OK;
3701}
3702
3703/******************************************************************************
3704 * VarBstrFromBool [OLEAUT32.116]
3705 */
3706HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3707{
3708 TRACE("( %d, %ld, %ld, %p ), stub\n", boolIn, lcid, dwFlags, pbstrOut );
3709
3710 sprintf( pBuffer, (boolIn == VARIANT_FALSE) ? "False" : "True" );
3711
3712 *pbstrOut = StringDupAtoBstr( pBuffer );
3713
3714 return S_OK;
3715}
3716
3717/******************************************************************************
3718 * VarBstrFromI1 [OLEAUT32.229]
3719 */
3720HRESULT WINAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3721{
3722 TRACE("( %c, %ld, %ld, %p ), stub\n", cIn, lcid, dwFlags, pbstrOut );
3723 sprintf( pBuffer, "%d", cIn );
3724 *pbstrOut = StringDupAtoBstr( pBuffer );
3725
3726 return S_OK;
3727}
3728
3729/******************************************************************************
3730 * VarBstrFromUI2 [OLEAUT32.230]
3731 */
3732HRESULT WINAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3733{
3734 TRACE("( %d, %ld, %ld, %p ), stub\n", uiIn, lcid, dwFlags, pbstrOut );
3735 sprintf( pBuffer, "%d", uiIn );
3736 *pbstrOut = StringDupAtoBstr( pBuffer );
3737
3738 return S_OK;
3739}
3740
3741/******************************************************************************
3742 * VarBstrFromUI4 [OLEAUT32.231]
3743 */
3744HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
3745{
3746 TRACE("( %ld, %ld, %ld, %p ), stub\n", ulIn, lcid, dwFlags, pbstrOut );
3747 sprintf( pBuffer, "%ld", ulIn );
3748 *pbstrOut = StringDupAtoBstr( pBuffer );
3749
3750 return S_OK;
3751}
3752
3753/******************************************************************************
3754 * VarBoolFromUI1 [OLEAUT32.118]
3755 */
3756HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL* pboolOut)
3757{
3758 TRACE("( %d, %p ), stub\n", bIn, pboolOut );
3759
3760 if( bIn == 0 )
3761 {
3762 *pboolOut = VARIANT_FALSE;
3763 }
3764 else
3765 {
3766 *pboolOut = VARIANT_TRUE;
3767 }
3768
3769 return S_OK;
3770}
3771
3772/******************************************************************************
3773 * VarBoolFromI2 [OLEAUT32.119]
3774 */
3775HRESULT WINAPI VarBoolFromI2(short sIn, VARIANT_BOOL* pboolOut)
3776{
3777 TRACE("( %d, %p ), stub\n", sIn, pboolOut );
3778
3779 *pboolOut = (sIn) ? VARIANT_TRUE : VARIANT_FALSE;
3780
3781 return S_OK;
3782}
3783
3784/******************************************************************************
3785 * VarBoolFromI4 [OLEAUT32.120]
3786 */
3787HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL* pboolOut)
3788{
3789 TRACE("( %ld, %p ), stub\n", lIn, pboolOut );
3790
3791 *pboolOut = (lIn) ? VARIANT_TRUE : VARIANT_FALSE;
3792
3793 return S_OK;
3794}
3795
3796/******************************************************************************
3797 * VarBoolFromR4 [OLEAUT32.121]
3798 */
3799HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL* pboolOut)
3800{
3801 TRACE("( %f, %p ), stub\n", fltIn, pboolOut );
3802
3803 *pboolOut = (fltIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3804
3805 return S_OK;
3806}
3807
3808/******************************************************************************
3809 * VarBoolFromR8 [OLEAUT32.122]
3810 */
3811HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL* pboolOut)
3812{
3813 TRACE("( %f, %p ), stub\n", dblIn, pboolOut );
3814
3815 *pboolOut = (dblIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3816
3817 return S_OK;
3818}
3819
3820/******************************************************************************
3821 * VarBoolFromDate [OLEAUT32.123]
3822 */
3823HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL* pboolOut)
3824{
3825 TRACE("( %f, %p ), stub\n", dateIn, pboolOut );
3826
3827 *pboolOut = (dateIn == 0.0) ? VARIANT_FALSE : VARIANT_TRUE;
3828
3829 return S_OK;
3830}
3831
3832/******************************************************************************
3833 * VarBoolFromStr [OLEAUT32.125]
3834 */
3835HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL* pboolOut)
3836{
3837 HRESULT ret = S_OK;
3838 char* pNewString = NULL;
3839
3840 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pboolOut );
3841
3842 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
3843
3844 if( pNewString == NULL || strlen( pNewString ) == 0 )
3845 {
3846 ret = DISP_E_TYPEMISMATCH;
3847 }
3848
3849 if( ret == S_OK )
3850 {
3851 if( strncasecmp( pNewString, "True", strlen( pNewString ) ) == 0 )
3852 {
3853 *pboolOut = VARIANT_TRUE;
3854 }
3855 else if( strncasecmp( pNewString, "False", strlen( pNewString ) ) == 0 )
3856 {
3857 *pboolOut = VARIANT_FALSE;
3858 }
3859 else
3860 {
3861 /* Try converting the string to a floating point number.
3862 */
3863 double dValue = 0.0;
3864 HRESULT res = VarR8FromStr( strIn, lcid, dwFlags, &dValue );
3865 if( res != S_OK )
3866 {
3867 ret = DISP_E_TYPEMISMATCH;
3868 }
3869 else
3870 *pboolOut = (dValue == 0.0) ?
3871 VARIANT_FALSE : VARIANT_TRUE;
3872 }
3873 }
3874
3875 HeapFree( GetProcessHeap(), 0, pNewString );
3876
3877 return ret;
3878}
3879
3880/******************************************************************************
3881 * VarBoolFromI1 [OLEAUT32.233]
3882 */
3883HRESULT WINAPI VarBoolFromI1(CHAR cIn, VARIANT_BOOL* pboolOut)
3884{
3885 TRACE("( %c, %p ), stub\n", cIn, pboolOut );
3886
3887 *pboolOut = (cIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3888
3889 return S_OK;
3890}
3891
3892/******************************************************************************
3893 * VarBoolFromUI2 [OLEAUT32.234]
3894 */
3895HRESULT WINAPI VarBoolFromUI2(USHORT uiIn, VARIANT_BOOL* pboolOut)
3896{
3897 TRACE("( %d, %p ), stub\n", uiIn, pboolOut );
3898
3899 *pboolOut = (uiIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3900
3901 return S_OK;
3902}
3903
3904/******************************************************************************
3905 * VarBoolFromUI4 [OLEAUT32.235]
3906 */
3907HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL* pboolOut)
3908{
3909 TRACE("( %ld, %p ), stub\n", ulIn, pboolOut );
3910
3911 *pboolOut = (ulIn == 0) ? VARIANT_FALSE : VARIANT_TRUE;
3912
3913 return S_OK;
3914}
3915
3916/**********************************************************************
3917 * VarBoolFromCy [OLEAUT32.124]
3918 * Convert currency to boolean
3919 */
3920HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL* pboolOut) {
3921 if (cyIn.s.Hi || cyIn.s.Lo) *pboolOut = -1;
3922 else *pboolOut = 0;
3923
3924 return S_OK;
3925}
3926
3927/******************************************************************************
3928 * VarI1FromUI1 [OLEAUT32.244]
3929 */
3930HRESULT WINAPI VarI1FromUI1(BYTE bIn, CHAR* pcOut)
3931{
3932 TRACE("( %d, %p ), stub\n", bIn, pcOut );
3933
3934 /* Check range of value.
3935 */
3936 if( bIn > CHAR_MAX )
3937 {
3938 return DISP_E_OVERFLOW;
3939 }
3940
3941 *pcOut = (CHAR) bIn;
3942
3943 return S_OK;
3944}
3945
3946/******************************************************************************
3947 * VarI1FromI2 [OLEAUT32.245]
3948 */
3949HRESULT WINAPI VarI1FromI2(short uiIn, CHAR* pcOut)
3950{
3951 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
3952
3953 if( uiIn > CHAR_MAX )
3954 {
3955 return DISP_E_OVERFLOW;
3956 }
3957
3958 *pcOut = (CHAR) uiIn;
3959
3960 return S_OK;
3961}
3962
3963/******************************************************************************
3964 * VarI1FromI4 [OLEAUT32.246]
3965 */
3966HRESULT WINAPI VarI1FromI4(LONG lIn, CHAR* pcOut)
3967{
3968 TRACE("( %ld, %p ), stub\n", lIn, pcOut );
3969
3970 if( lIn < CHAR_MIN || lIn > CHAR_MAX )
3971 {
3972 return DISP_E_OVERFLOW;
3973 }
3974
3975 *pcOut = (CHAR) lIn;
3976
3977 return S_OK;
3978}
3979
3980/******************************************************************************
3981 * VarI1FromR4 [OLEAUT32.247]
3982 */
3983HRESULT WINAPI VarI1FromR4(FLOAT fltIn, CHAR* pcOut)
3984{
3985 TRACE("( %f, %p ), stub\n", fltIn, pcOut );
3986
3987 fltIn = round( fltIn );
3988 if( fltIn < CHAR_MIN || fltIn > CHAR_MAX )
3989 {
3990 return DISP_E_OVERFLOW;
3991 }
3992
3993 *pcOut = (CHAR) fltIn;
3994
3995 return S_OK;
3996}
3997
3998/******************************************************************************
3999 * VarI1FromR8 [OLEAUT32.248]
4000 */
4001HRESULT WINAPI VarI1FromR8(double dblIn, CHAR* pcOut)
4002{
4003 TRACE("( %f, %p ), stub\n", dblIn, pcOut );
4004
4005 dblIn = round( dblIn );
4006 if( dblIn < CHAR_MIN || dblIn > CHAR_MAX )
4007 {
4008 return DISP_E_OVERFLOW;
4009 }
4010
4011 *pcOut = (CHAR) dblIn;
4012
4013 return S_OK;
4014}
4015
4016/******************************************************************************
4017 * VarI1FromDate [OLEAUT32.249]
4018 */
4019HRESULT WINAPI VarI1FromDate(DATE dateIn, CHAR* pcOut)
4020{
4021 TRACE("( %f, %p ), stub\n", dateIn, pcOut );
4022
4023 dateIn = round( dateIn );
4024 if( dateIn < CHAR_MIN || dateIn > CHAR_MAX )
4025 {
4026 return DISP_E_OVERFLOW;
4027 }
4028
4029 *pcOut = (CHAR) dateIn;
4030
4031 return S_OK;
4032}
4033
4034/******************************************************************************
4035 * VarI1FromStr [OLEAUT32.251]
4036 */
4037HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CHAR* pcOut)
4038{
4039 double dValue = 0.0;
4040 LPSTR pNewString = NULL;
4041
4042 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pcOut );
4043
4044 /* Check if we have a valid argument
4045 */
4046 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4047 RemoveCharacterFromString( pNewString, "," );
4048 if( IsValidRealString( pNewString ) == FALSE )
4049 {
4050 return DISP_E_TYPEMISMATCH;
4051 }
4052
4053 /* Convert the valid string to a floating point number.
4054 */
4055 dValue = atof( pNewString );
4056
4057 /* We don't need the string anymore so free it.
4058 */
4059 HeapFree( GetProcessHeap(), 0, pNewString );
4060
4061 /* Check range of value.
4062 */
4063 dValue = round( dValue );
4064 if( dValue < CHAR_MIN || dValue > CHAR_MAX )
4065 {
4066 return DISP_E_OVERFLOW;
4067 }
4068
4069 *pcOut = (CHAR) dValue;
4070
4071 return S_OK;
4072}
4073
4074/******************************************************************************
4075 * VarI1FromBool [OLEAUT32.253]
4076 */
4077HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, CHAR* pcOut)
4078{
4079 TRACE("( %d, %p ), stub\n", boolIn, pcOut );
4080
4081 *pcOut = (CHAR) boolIn;
4082
4083 return S_OK;
4084}
4085
4086/******************************************************************************
4087 * VarI1FromUI2 [OLEAUT32.254]
4088 */
4089HRESULT WINAPI VarI1FromUI2(USHORT uiIn, CHAR* pcOut)
4090{
4091 TRACE("( %d, %p ), stub\n", uiIn, pcOut );
4092
4093 if( uiIn > CHAR_MAX )
4094 {
4095 return DISP_E_OVERFLOW;
4096 }
4097
4098 *pcOut = (CHAR) uiIn;
4099
4100 return S_OK;
4101}
4102
4103/******************************************************************************
4104 * VarI1FromUI4 [OLEAUT32.255]
4105 */
4106HRESULT WINAPI VarI1FromUI4(ULONG ulIn, CHAR* pcOut)
4107{
4108 TRACE("( %ld, %p ), stub\n", ulIn, pcOut );
4109
4110 if( ulIn > CHAR_MAX )
4111 {
4112 return DISP_E_OVERFLOW;
4113 }
4114
4115 *pcOut = (CHAR) ulIn;
4116
4117 return S_OK;
4118}
4119
4120/**********************************************************************
4121 * VarI1FromCy [OLEAUT32.250]
4122 * Convert currency to signed char
4123 */
4124HRESULT WINAPI VarI1FromCy(CY cyIn, CHAR* pcOut) {
4125 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4126
4127 if (t > CHAR_MAX || t < CHAR_MIN) return DISP_E_OVERFLOW;
4128
4129 *pcOut = (CHAR)t;
4130 return S_OK;
4131}
4132
4133/******************************************************************************
4134 * VarUI2FromUI1 [OLEAUT32.257]
4135 */
4136HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* puiOut)
4137{
4138 TRACE("( %d, %p ), stub\n", bIn, puiOut );
4139
4140 *puiOut = (USHORT) bIn;
4141
4142 return S_OK;
4143}
4144
4145/******************************************************************************
4146 * VarUI2FromI2 [OLEAUT32.258]
4147 */
4148HRESULT WINAPI VarUI2FromI2(short uiIn, USHORT* puiOut)
4149{
4150 TRACE("( %d, %p ), stub\n", uiIn, puiOut );
4151
4152 if( uiIn < UI2_MIN )
4153 {
4154 return DISP_E_OVERFLOW;
4155 }
4156
4157 *puiOut = (USHORT) uiIn;
4158
4159 return S_OK;
4160}
4161
4162/******************************************************************************
4163 * VarUI2FromI4 [OLEAUT32.259]
4164 */
4165HRESULT WINAPI VarUI2FromI4(LONG lIn, USHORT* puiOut)
4166{
4167 TRACE("( %ld, %p ), stub\n", lIn, puiOut );
4168
4169 if( lIn < UI2_MIN || lIn > UI2_MAX )
4170 {
4171 return DISP_E_OVERFLOW;
4172 }
4173
4174 *puiOut = (USHORT) lIn;
4175
4176 return S_OK;
4177}
4178
4179/******************************************************************************
4180 * VarUI2FromR4 [OLEAUT32.260]
4181 */
4182HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* puiOut)
4183{
4184 TRACE("( %f, %p ), stub\n", fltIn, puiOut );
4185
4186 fltIn = round( fltIn );
4187 if( fltIn < UI2_MIN || fltIn > UI2_MAX )
4188 {
4189 return DISP_E_OVERFLOW;
4190 }
4191
4192 *puiOut = (USHORT) fltIn;
4193
4194 return S_OK;
4195}
4196
4197/******************************************************************************
4198 * VarUI2FromR8 [OLEAUT32.261]
4199 */
4200HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* puiOut)
4201{
4202 TRACE("( %f, %p ), stub\n", dblIn, puiOut );
4203
4204 dblIn = round( dblIn );
4205 if( dblIn < UI2_MIN || dblIn > UI2_MAX )
4206 {
4207 return DISP_E_OVERFLOW;
4208 }
4209
4210 *puiOut = (USHORT) dblIn;
4211
4212 return S_OK;
4213}
4214
4215/******************************************************************************
4216 * VarUI2FromDate [OLEAUT32.262]
4217 */
4218HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* puiOut)
4219{
4220 TRACE("( %f, %p ), stub\n", dateIn, puiOut );
4221
4222 dateIn = round( dateIn );
4223 if( dateIn < UI2_MIN || dateIn > UI2_MAX )
4224 {
4225 return DISP_E_OVERFLOW;
4226 }
4227
4228 *puiOut = (USHORT) dateIn;
4229
4230 return S_OK;
4231}
4232
4233/******************************************************************************
4234 * VarUI2FromStr [OLEAUT32.264]
4235 */
4236HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* puiOut)
4237{
4238 double dValue = 0.0;
4239 LPSTR pNewString = NULL;
4240
4241 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, puiOut );
4242
4243 /* Check if we have a valid argument
4244 */
4245 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4246 RemoveCharacterFromString( pNewString, "," );
4247 if( IsValidRealString( pNewString ) == FALSE )
4248 {
4249 return DISP_E_TYPEMISMATCH;
4250 }
4251
4252 /* Convert the valid string to a floating point number.
4253 */
4254 dValue = atof( pNewString );
4255
4256 /* We don't need the string anymore so free it.
4257 */
4258 HeapFree( GetProcessHeap(), 0, pNewString );
4259
4260 /* Check range of value.
4261 */
4262 dValue = round( dValue );
4263 if( dValue < UI2_MIN || dValue > UI2_MAX )
4264 {
4265 return DISP_E_OVERFLOW;
4266 }
4267
4268 *puiOut = (USHORT) dValue;
4269
4270 return S_OK;
4271}
4272
4273/******************************************************************************
4274 * VarUI2FromBool [OLEAUT32.266]
4275 */
4276HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* puiOut)
4277{
4278 TRACE("( %d, %p ), stub\n", boolIn, puiOut );
4279
4280 *puiOut = (USHORT) boolIn;
4281
4282 return S_OK;
4283}
4284
4285/******************************************************************************
4286 * VarUI2FromI1 [OLEAUT32.267]
4287 */
4288HRESULT WINAPI VarUI2FromI1(CHAR cIn, USHORT* puiOut)
4289{
4290 TRACE("( %c, %p ), stub\n", cIn, puiOut );
4291
4292 *puiOut = (USHORT) cIn;
4293
4294 return S_OK;
4295}
4296
4297/******************************************************************************
4298 * VarUI2FromUI4 [OLEAUT32.268]
4299 */
4300HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* puiOut)
4301{
4302 TRACE("( %ld, %p ), stub\n", ulIn, puiOut );
4303
4304 if( ulIn > UI2_MAX )
4305 {
4306 return DISP_E_OVERFLOW;
4307 }
4308
4309 *puiOut = (USHORT) ulIn;
4310
4311 return S_OK;
4312}
4313
4314/******************************************************************************
4315 * VarUI4FromStr [OLEAUT32.277]
4316 */
4317HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG* pulOut)
4318{
4319 double dValue = 0.0;
4320 LPSTR pNewString = NULL;
4321
4322 TRACE("( %p, %ld, %ld, %p ), stub\n", strIn, lcid, dwFlags, pulOut );
4323
4324 /* Check if we have a valid argument
4325 */
4326 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4327 RemoveCharacterFromString( pNewString, "," );
4328 if( IsValidRealString( pNewString ) == FALSE )
4329 {
4330 return DISP_E_TYPEMISMATCH;
4331 }
4332
4333 /* Convert the valid string to a floating point number.
4334 */
4335 dValue = atof( pNewString );
4336
4337 /* We don't need the string anymore so free it.
4338 */
4339 HeapFree( GetProcessHeap(), 0, pNewString );
4340
4341 /* Check range of value.
4342 */
4343 dValue = round( dValue );
4344 if( dValue < UI4_MIN || dValue > UI4_MAX )
4345 {
4346 return DISP_E_OVERFLOW;
4347 }
4348
4349 *pulOut = (ULONG) dValue;
4350
4351 return S_OK;
4352}
4353
4354/**********************************************************************
4355 * VarUI2FromCy [OLEAUT32.263]
4356 * Convert currency to unsigned short
4357 */
4358HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut) {
4359 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4360
4361 if (t > UI2_MAX || t < UI2_MIN) return DISP_E_OVERFLOW;
4362
4363 *pusOut = (USHORT)t;
4364
4365 return S_OK;
4366}
4367
4368/******************************************************************************
4369 * VarUI4FromUI1 [OLEAUT32.270]
4370 */
4371HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG* pulOut)
4372{
4373 TRACE("( %d, %p ), stub\n", bIn, pulOut );
4374
4375 *pulOut = (USHORT) bIn;
4376
4377 return S_OK;
4378}
4379
4380/******************************************************************************
4381 * VarUI4FromI2 [OLEAUT32.271]
4382 */
4383HRESULT WINAPI VarUI4FromI2(short uiIn, ULONG* pulOut)
4384{
4385 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4386
4387 if( uiIn < UI4_MIN )
4388 {
4389 return DISP_E_OVERFLOW;
4390 }
4391
4392 *pulOut = (ULONG) uiIn;
4393
4394 return S_OK;
4395}
4396
4397/******************************************************************************
4398 * VarUI4FromI4 [OLEAUT32.272]
4399 */
4400HRESULT WINAPI VarUI4FromI4(LONG lIn, ULONG* pulOut)
4401{
4402 TRACE("( %ld, %p ), stub\n", lIn, pulOut );
4403
4404 if( lIn < 0 )
4405 {
4406 return DISP_E_OVERFLOW;
4407 }
4408
4409 *pulOut = (ULONG) lIn;
4410
4411 return S_OK;
4412}
4413
4414/******************************************************************************
4415 * VarUI4FromR4 [OLEAUT32.273]
4416 */
4417HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG* pulOut)
4418{
4419 fltIn = round( fltIn );
4420 if( fltIn < UI4_MIN || fltIn > UI4_MAX )
4421 {
4422 return DISP_E_OVERFLOW;
4423 }
4424
4425 *pulOut = (ULONG) fltIn;
4426
4427 return S_OK;
4428}
4429
4430/******************************************************************************
4431 * VarUI4FromR8 [OLEAUT32.274]
4432 */
4433HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG* pulOut)
4434{
4435 TRACE("( %f, %p ), stub\n", dblIn, pulOut );
4436
4437 dblIn = round( dblIn );
4438 if( dblIn < UI4_MIN || dblIn > UI4_MAX )
4439 {
4440 return DISP_E_OVERFLOW;
4441 }
4442
4443 *pulOut = (ULONG) dblIn;
4444
4445 return S_OK;
4446}
4447
4448/******************************************************************************
4449 * VarUI4FromDate [OLEAUT32.275]
4450 */
4451HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG* pulOut)
4452{
4453 TRACE("( %f, %p ), stub\n", dateIn, pulOut );
4454
4455 dateIn = round( dateIn );
4456 if( dateIn < UI4_MIN || dateIn > UI4_MAX )
4457 {
4458 return DISP_E_OVERFLOW;
4459 }
4460
4461 *pulOut = (ULONG) dateIn;
4462
4463 return S_OK;
4464}
4465
4466/******************************************************************************
4467 * VarUI4FromBool [OLEAUT32.279]
4468 */
4469HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG* pulOut)
4470{
4471 TRACE("( %d, %p ), stub\n", boolIn, pulOut );
4472
4473 *pulOut = (ULONG) boolIn;
4474
4475 return S_OK;
4476}
4477
4478/******************************************************************************
4479 * VarUI4FromI1 [OLEAUT32.280]
4480 */
4481HRESULT WINAPI VarUI4FromI1(CHAR cIn, ULONG* pulOut)
4482{
4483 TRACE("( %c, %p ), stub\n", cIn, pulOut );
4484
4485 *pulOut = (ULONG) cIn;
4486
4487 return S_OK;
4488}
4489
4490/******************************************************************************
4491 * VarUI4FromUI2 [OLEAUT32.281]
4492 */
4493HRESULT WINAPI VarUI4FromUI2(USHORT uiIn, ULONG* pulOut)
4494{
4495 TRACE("( %d, %p ), stub\n", uiIn, pulOut );
4496
4497 *pulOut = (ULONG) uiIn;
4498
4499 return S_OK;
4500}
4501
4502/**********************************************************************
4503 * VarUI4FromCy [OLEAUT32.276]
4504 * Convert currency to unsigned long
4505 */
4506HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG* pulOut) {
4507 double t = round((((double)cyIn.s.Hi * 4294967296.0) + (double)cyIn.s.Lo) / 10000);
4508
4509 if (t > UI4_MAX || t < UI4_MIN) return DISP_E_OVERFLOW;
4510
4511 *pulOut = (ULONG)t;
4512
4513 return S_OK;
4514}
4515
4516/**********************************************************************
4517 * VarCyFromUI1 [OLEAUT32.98]
4518 * Convert unsigned char to currency
4519 */
4520HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pcyOut) {
4521 pcyOut->s.Hi = 0;
4522 pcyOut->s.Lo = ((ULONG)bIn) * 10000;
4523
4524 return S_OK;
4525}
4526
4527/**********************************************************************
4528 * VarCyFromI2 [OLEAUT32.99]
4529 * Convert signed short to currency
4530 */
4531HRESULT WINAPI VarCyFromI2(short sIn, CY* pcyOut) {
4532 if (sIn < 0) pcyOut->s.Hi = -1;
4533 else pcyOut->s.Hi = 0;
4534 pcyOut->s.Lo = ((ULONG)sIn) * 10000;
4535
4536 return S_OK;
4537}
4538
4539/**********************************************************************
4540 * VarCyFromI4 [OLEAUT32.100]
4541 * Convert signed long to currency
4542 */
4543HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pcyOut) {
4544 double t = (double)lIn * (double)10000;
4545 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4546 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4547 if (lIn < 0) pcyOut->s.Hi--;
4548
4549 return S_OK;
4550}
4551
4552/**********************************************************************
4553 * VarCyFromR4 [OLEAUT32.101]
4554 * Convert float to currency
4555 */
4556HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pcyOut) {
4557 double t = round((double)fltIn * (double)10000);
4558 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4559 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4560 if (fltIn < 0) pcyOut->s.Hi--;
4561
4562 return S_OK;
4563}
4564
4565/**********************************************************************
4566 * VarCyFromR8 [OLEAUT32.102]
4567 * Convert double to currency
4568 */
4569HRESULT WINAPI VarCyFromR8(double dblIn, CY* pcyOut) {
4570 double t = round(dblIn * (double)10000);
4571 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4572 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4573 if (dblIn < 0) pcyOut->s.Hi--;
4574
4575 return S_OK;
4576}
4577
4578/**********************************************************************
4579 * VarCyFromDate [OLEAUT32.103]
4580 * Convert date to currency
4581 */
4582HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pcyOut) {
4583 double t = round((double)dateIn * (double)10000);
4584 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4585 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4586 if (dateIn < 0) pcyOut->s.Hi--;
4587
4588 return S_OK;
4589}
4590
4591/**********************************************************************
4592 * VarCyFromStr [OLEAUT32.104]
4593 * FIXME: Never tested with decimal seperator other than '.'
4594 */
4595HRESULT WINAPI VarCyFromStr(OLECHAR *strIn, LCID lcid, ULONG dwFlags, CY *pcyOut) {
4596
4597 LPSTR pNewString = NULL;
4598 char *decSep = NULL;
4599 char *strPtr,*curPtr = NULL;
4600 int size, rc;
4601 double currencyVal = 0.0;
4602
4603
4604 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, strIn );
4605 TRACE("( '%s', 0x%08lx, 0x%08lx, %p )\n", pNewString, lcid, dwFlags, pcyOut );
4606
4607 /* Get locale information - Decimal Seperator (size includes 0x00) */
4608 size = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, NULL, 0);
4609 decSep = (char *) malloc(size);
4610 rc = GetLocaleInfoA(lcid, LOCALE_SDECIMAL, decSep, size);
4611 TRACE("Decimal Seperator is '%s'\n", decSep);
4612
4613 /* Now copy to temporary buffer, skipping any character except 0-9 and
4614 the decimal seperator */
4615 curPtr = pBuffer; /* Current position in string being built */
4616 strPtr = pNewString; /* Current position in supplied currenct string */
4617
4618 while (*strPtr) {
4619 /* If decimal seperator, skip it and put '.' in string */
4620 if (strncmp(strPtr, decSep, (size-1)) == 0) {
4621 strPtr = strPtr + (size-1);
4622 *curPtr = '.';
4623 curPtr++;
4624 } else if ((*strPtr == '+' || *strPtr == '-') ||
4625 (*strPtr >= '0' && *strPtr <= '9')) {
4626 *curPtr = *strPtr;
4627 strPtr++;
4628 curPtr++;
4629 } else strPtr++;
4630 }
4631 *curPtr = 0x00;
4632
4633 /* Try to get currency into a double */
4634 currencyVal = atof(pBuffer);
4635 TRACE("Converted string '%s' to %f\n", pBuffer, currencyVal);
4636
4637 /* Free allocated storage */
4638 HeapFree( GetProcessHeap(), 0, pNewString );
4639 free(decSep);
4640
4641 /* Convert double -> currency using internal routine */
4642 return VarCyFromR8(currencyVal, pcyOut);
4643}
4644
4645
4646/**********************************************************************
4647 * VarCyFromBool [OLEAUT32.106]
4648 * Convert boolean to currency
4649 */
4650HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pcyOut) {
4651 if (boolIn < 0) pcyOut->s.Hi = -1;
4652 else pcyOut->s.Hi = 0;
4653 pcyOut->s.Lo = (ULONG)boolIn * (ULONG)10000;
4654
4655 return S_OK;
4656}
4657
4658/**********************************************************************
4659 * VarCyFromI1 [OLEAUT32.225]
4660 * Convert signed char to currency
4661 */
4662HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pcyOut) {
4663 if (cIn < 0) pcyOut->s.Hi = -1;
4664 else pcyOut->s.Hi = 0;
4665 pcyOut->s.Lo = (ULONG)cIn * (ULONG)10000;
4666
4667 return S_OK;
4668}
4669
4670/**********************************************************************
4671 * VarCyFromUI2 [OLEAUT32.226]
4672 * Convert unsigned short to currency
4673 */
4674HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pcyOut) {
4675 pcyOut->s.Hi = 0;
4676 pcyOut->s.Lo = (ULONG)usIn * (ULONG)10000;
4677
4678 return S_OK;
4679}
4680
4681/**********************************************************************
4682 * VarCyFromUI4 [OLEAUT32.227]
4683 * Convert unsigned long to currency
4684 */
4685HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pcyOut) {
4686 double t = (double)ulIn * (double)10000;
4687 pcyOut->s.Hi = (LONG)(t / (double)4294967296.0);
4688 pcyOut->s.Lo = (ULONG)fmod(t, (double)4294967296.0);
4689
4690 return S_OK;
4691}
4692
4693
4694/**********************************************************************
4695 * DosDateTimeToVariantTime [OLEAUT32.14]
4696 * Convert dos representation of time to the date and time representation
4697 * stored in a variant.
4698 */
4699INT WINAPI DosDateTimeToVariantTime(USHORT wDosDate, USHORT wDosTime,
4700 DATE *pvtime)
4701{
4702 struct tm t;
4703
4704 TRACE("( 0x%x, 0x%x, %p ), stub\n", wDosDate, wDosTime, pvtime );
4705
4706 t.tm_sec = (wDosTime & 0x001f) * 2;
4707 t.tm_min = (wDosTime & 0x07e0) >> 5;
4708 t.tm_hour = (wDosTime & 0xf800) >> 11;
4709
4710 t.tm_mday = (wDosDate & 0x001f);
4711 t.tm_mon = (wDosDate & 0x01e0) >> 5;
4712 t.tm_year = ((wDosDate & 0xfe00) >> 9) + 1980;
4713
4714 return TmToDATE( &t, pvtime );
4715}
4716
4717
4718#define GET_NUMBER_TEXT(fld,name) \
4719 buff[0] = 0; \
4720 if (!GetLocaleInfoW(lcid, lctype|fld, buff, 2)) \
4721 WARN("%s: buffer too small for " #fld "\n", __FUNCTION__); \
4722 else \
4723 if (buff[0]) lpChars->name = buff[0]; /* \
4724 TRACE("lcid 0x%lx, " #name "=%d '%c'\n", lcid, lpChars->name, lpChars->name)*/
4725
4726/* Get the valid number characters for an lcid */
4727void VARIANT_GetLocalisedNumberChars(VARIANT_NUMBER_CHARS *lpChars, LCID lcid, DWORD dwFlags)
4728{
4729 static const VARIANT_NUMBER_CHARS defaultChars = { '-','+','.',',','$',0,'.',',' };
4730 LCTYPE lctype = dwFlags & LOCALE_NOUSEROVERRIDE;
4731 WCHAR buff[4];
4732
4733 memcpy(lpChars, &defaultChars, sizeof(defaultChars));
4734 GET_NUMBER_TEXT(LOCALE_SNEGATIVESIGN, cNegativeSymbol);
4735 GET_NUMBER_TEXT(LOCALE_SPOSITIVESIGN, cPositiveSymbol);
4736 GET_NUMBER_TEXT(LOCALE_SDECIMAL, cDecimalPoint);
4737 GET_NUMBER_TEXT(LOCALE_STHOUSAND, cDigitSeperator);
4738 GET_NUMBER_TEXT(LOCALE_SMONDECIMALSEP, cCurrencyDecimalPoint);
4739 GET_NUMBER_TEXT(LOCALE_SMONTHOUSANDSEP, cCurrencyDigitSeperator);
4740
4741 /* Local currency symbols are often 2 characters */
4742 lpChars->cCurrencyLocal2 = '\0';
4743 switch(GetLocaleInfoW(lcid, lctype|LOCALE_SCURRENCY, buff, sizeof(buff)/sizeof(WCHAR)))
4744 {
4745 case 3: lpChars->cCurrencyLocal2 = buff[1]; /* Fall through */
4746 case 2: lpChars->cCurrencyLocal = buff[0];
4747 break;
4748 default: WARN("buffer too small for LOCALE_SCURRENCY\n");
4749 }
4750 TRACE("lcid 0x%lx, cCurrencyLocal =%d,%d '%c','%c'\n", lcid, lpChars->cCurrencyLocal,
4751 lpChars->cCurrencyLocal2, lpChars->cCurrencyLocal, lpChars->cCurrencyLocal2);
4752}
4753
4754/* Number Parsing States */
4755#define B_PROCESSING_EXPONENT 0x1
4756#define B_NEGATIVE_EXPONENT 0x2
4757#define B_EXPONENT_START 0x4
4758#define B_INEXACT_ZEROS 0x8
4759#define B_LEADING_ZERO 0x10
4760#define B_PROCESSING_HEX 0x20
4761#define B_PROCESSING_OCT 0x40
4762/**********************************************************************
4763 * VarParseNumFromStr [OLEAUT32.46]
4764 *
4765 * Parse a string containing a number into a NUMPARSE structure.
4766 *
4767 * PARAMS
4768 * lpszStr [I] String to parse number from
4769 * lcid [I] Locale Id for the conversion
4770 * dwFlags [I] 0, or LOCALE_NOUSEROVERRIDE to use system default number chars
4771 * pNumprs [I/O] Destination for parsed number
4772 * rgbDig [O] Destination for digits read in
4773 *
4774 * RETURNS
4775 * Success: S_OK. pNumprs and rgbDig contain the parsed representation of
4776 * the number.
4777 * Failure: E_INVALIDARG, if any parameter is invalid.
4778 * DISP_E_TYPEMISMATCH, if the string is not a number or is formatted
4779 * incorrectly.
4780 * DISP_E_OVERFLOW, if rgbDig is too small to hold the number.
4781 *
4782 * NOTES
4783 * pNumprs must have the following fields set:
4784 * cDig: Set to the size of rgbDig.
4785 * dwInFlags: Set to the allowable syntax of the number using NUMPRS_ flags
4786 * from "oleauto.h".
4787 *
4788 * FIXME
4789 * - I am unsure if this function should parse non-arabic (e.g. Thai)
4790 * numerals, so this has not been implemented.
4791 */
4792HRESULT WINAPI VarParseNumFromStr(OLECHAR *lpszStr, LCID lcid, ULONG dwFlags,
4793 NUMPARSE *pNumprs, BYTE *rgbDig)
4794{
4795 VARIANT_NUMBER_CHARS chars;
4796 BYTE rgbTmp[1024];
4797 DWORD dwState = B_EXPONENT_START|B_INEXACT_ZEROS;
4798 int iMaxDigits = sizeof(rgbTmp) / sizeof(BYTE);
4799 int cchUsed = 0;
4800
4801 TRACE("%s: (%s, %ld, dwFlags: 0x%08lx,%p,%p, NUMPARSE->dwInFlags: %x)\n", __FUNCTION__, debugstr_w(lpszStr), lcid, dwFlags, pNumprs, rgbDig, pNumprs->dwInFlags);
4802
4803 if (!pNumprs || !rgbDig)
4804 return E_INVALIDARG;
4805
4806 if (pNumprs->cDig < iMaxDigits)
4807 iMaxDigits = pNumprs->cDig;
4808
4809 pNumprs->cDig = 0;
4810 pNumprs->dwOutFlags = 0;
4811 pNumprs->cchUsed = 0;
4812 pNumprs->nBaseShift = 0;
4813 pNumprs->nPwr10 = 0;
4814
4815 if (!lpszStr)
4816 return DISP_E_TYPEMISMATCH;
4817
4818 VARIANT_GetLocalisedNumberChars(&chars, lcid, dwFlags);
4819
4820 /* First consume all the leading symbols and space from the string */
4821 while (1)
4822 {
4823 if (pNumprs->dwInFlags & NUMPRS_LEADING_WHITE && isspaceW(*lpszStr))
4824 {
4825 pNumprs->dwOutFlags |= NUMPRS_LEADING_WHITE;
4826 do
4827 {
4828 cchUsed++;
4829 lpszStr++;
4830 } while (isspaceW(*lpszStr));
4831 }
4832 else if (pNumprs->dwInFlags & NUMPRS_LEADING_PLUS &&
4833 *lpszStr == chars.cPositiveSymbol &&
4834 !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS))
4835 {
4836 pNumprs->dwOutFlags |= NUMPRS_LEADING_PLUS;
4837 cchUsed++;
4838 lpszStr++;
4839 }
4840 else if (pNumprs->dwInFlags & NUMPRS_LEADING_MINUS &&
4841 *lpszStr == chars.cNegativeSymbol &&
4842 !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS))
4843 {
4844 pNumprs->dwOutFlags |= (NUMPRS_LEADING_MINUS|NUMPRS_NEG);
4845 cchUsed++;
4846 lpszStr++;
4847 }
4848 else if (pNumprs->dwInFlags & NUMPRS_CURRENCY &&
4849 !(pNumprs->dwOutFlags & NUMPRS_CURRENCY) &&
4850 *lpszStr == chars.cCurrencyLocal &&
4851 (!chars.cCurrencyLocal2 || lpszStr[1] == chars.cCurrencyLocal2))
4852 {
4853 pNumprs->dwOutFlags |= NUMPRS_CURRENCY;
4854 cchUsed++;
4855 lpszStr++;
4856 /* Only accept currency characters */
4857 chars.cDecimalPoint = chars.cCurrencyDecimalPoint;
4858 chars.cDigitSeperator = chars.cCurrencyDigitSeperator;
4859 }
4860 else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == '(' &&
4861 !(pNumprs->dwOutFlags & NUMPRS_PARENS))
4862 {
4863 pNumprs->dwOutFlags |= NUMPRS_PARENS;
4864 cchUsed++;
4865 lpszStr++;
4866 }
4867 else
4868 break;
4869 } /* End of while */
4870
4871 if(pNumprs->dwOutFlags & (1<<VT_LPWSTR))
4872 {
4873 TRACE(" I'm here");
4874 }
4875 if (!(pNumprs->dwOutFlags & NUMPRS_CURRENCY))
4876 {
4877 /* Only accept non-currency characters */
4878 chars.cCurrencyDecimalPoint = chars.cDecimalPoint;
4879 chars.cCurrencyDigitSeperator = chars.cDigitSeperator;
4880 }
4881
4882 if ((*lpszStr == '&' && (*(lpszStr+1) == 'H' || *(lpszStr+1) == 'h')) &&
4883 pNumprs->dwInFlags & NUMPRS_HEX_OCT)
4884 {
4885 dwState |= B_PROCESSING_HEX;
4886 pNumprs->dwOutFlags |= NUMPRS_HEX_OCT;
4887 cchUsed=cchUsed+2;
4888 lpszStr=lpszStr+2;
4889 }
4890 else if ((*lpszStr == '&' && (*(lpszStr+1) == 'O' || *(lpszStr+1) == 'o')) &&
4891 pNumprs->dwInFlags & NUMPRS_HEX_OCT)
4892 {
4893 dwState |= B_PROCESSING_OCT;
4894 pNumprs->dwOutFlags |= NUMPRS_HEX_OCT;
4895 cchUsed=cchUsed+2;
4896 lpszStr=lpszStr+2;
4897 }
4898
4899 /* Strip Leading zeros */
4900 while (*lpszStr == '0')
4901 {
4902 dwState |= B_LEADING_ZERO;
4903 cchUsed++;
4904 lpszStr++;
4905 }
4906
4907 while (*lpszStr)
4908 {
4909 if (isdigitW(*lpszStr))
4910 {
4911 if (dwState & B_PROCESSING_EXPONENT)
4912 {
4913 int exponentSize = 0;
4914 if (dwState & B_EXPONENT_START)
4915 {
4916 while (*lpszStr == '0')
4917 {
4918 /* Skip leading zero's in the exponent */
4919 cchUsed++;
4920 lpszStr++;
4921 }
4922 if (!isdigitW(*lpszStr))
4923 break; /* No exponent digits - invalid */
4924 }
4925
4926 while (isdigitW(*lpszStr))
4927 {
4928 exponentSize *= 10;
4929 exponentSize += *lpszStr - '0';
4930 cchUsed++;
4931 lpszStr++;
4932 }
4933 if (dwState & B_NEGATIVE_EXPONENT)
4934 exponentSize = -exponentSize;
4935 /* Add the exponent into the powers of 10 */
4936 pNumprs->nPwr10 += exponentSize;
4937 dwState &= ~(B_PROCESSING_EXPONENT|B_EXPONENT_START);
4938 lpszStr--; /* back up to allow processing of next char */
4939 }
4940 else
4941 {
4942 if ((pNumprs->cDig >= iMaxDigits) && !(dwState & B_PROCESSING_HEX)
4943 && !(dwState & B_PROCESSING_OCT))
4944 {
4945 pNumprs->dwOutFlags |= NUMPRS_INEXACT;
4946
4947 if (*lpszStr != '0')
4948 dwState &= ~B_INEXACT_ZEROS; /* Inexact number with non-trailing zeros */
4949
4950 /* This digit can't be represented, but count it in nPwr10 */
4951 if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
4952 pNumprs->nPwr10--;
4953 else
4954 pNumprs->nPwr10++;
4955 }
4956 else
4957 {
4958 if ((dwState & B_PROCESSING_OCT) && ((*lpszStr == '8') || (*lpszStr == '9'))) {
4959 return DISP_E_TYPEMISMATCH;
4960 }
4961
4962 if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
4963 pNumprs->nPwr10--; /* Count decimal points in nPwr10 */
4964
4965 rgbTmp[pNumprs->cDig] = *lpszStr - '0';
4966 }
4967 pNumprs->cDig++;
4968 cchUsed++;
4969 }
4970 }
4971 else if (*lpszStr == chars.cDigitSeperator && pNumprs->dwInFlags & NUMPRS_THOUSANDS)
4972 {
4973 pNumprs->dwOutFlags |= NUMPRS_THOUSANDS;
4974 cchUsed++;
4975 }
4976 else if (*lpszStr == chars.cDecimalPoint &&
4977 pNumprs->dwInFlags & NUMPRS_DECIMAL &&
4978 !(pNumprs->dwOutFlags & (NUMPRS_DECIMAL|NUMPRS_EXPONENT)))
4979 {
4980 pNumprs->dwOutFlags |= NUMPRS_DECIMAL;
4981 cchUsed++;
4982
4983 /* Remove trailing zeros from the whole number part */
4984 while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
4985 {
4986 pNumprs->nPwr10++;
4987 pNumprs->cDig--;
4988 }
4989
4990 /* If we have no digits so far, skip leading zeros */
4991 if (!pNumprs->cDig)
4992 {
4993 while (lpszStr[1] == '0')
4994 {
4995 dwState |= B_LEADING_ZERO;
4996 cchUsed++;
4997 lpszStr++;
4998 }
4999 }
5000 }
5001 else if ((*lpszStr == 'e' || *lpszStr == 'E') &&
5002 pNumprs->dwInFlags & NUMPRS_EXPONENT &&
5003 !(pNumprs->dwOutFlags & NUMPRS_EXPONENT))
5004 {
5005 dwState |= B_PROCESSING_EXPONENT;
5006 pNumprs->dwOutFlags |= NUMPRS_EXPONENT;
5007 cchUsed++;
5008 }
5009 else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cPositiveSymbol)
5010 {
5011 cchUsed++; /* Ignore positive exponent */
5012 }
5013 else if (dwState & B_PROCESSING_EXPONENT && *lpszStr == chars.cNegativeSymbol)
5014 {
5015 dwState |= B_NEGATIVE_EXPONENT;
5016 cchUsed++;
5017 }
5018 else if (((*lpszStr >= 'a' && *lpszStr <= 'f') ||
5019 (*lpszStr >= 'A' && *lpszStr <= 'F')) &&
5020 dwState & B_PROCESSING_HEX)
5021 {
5022 if (pNumprs->cDig >= iMaxDigits)
5023 {
5024 return DISP_E_OVERFLOW;
5025 }
5026 else
5027 {
5028 if (*lpszStr >= 'a')
5029 rgbTmp[pNumprs->cDig] = *lpszStr - 'a' + 10;
5030 else
5031 rgbTmp[pNumprs->cDig] = *lpszStr - 'A' + 10;
5032 }
5033 pNumprs->cDig++;
5034 cchUsed++;
5035 }
5036 else
5037 break; /* Stop at an unrecognised character */
5038
5039 lpszStr++;
5040 }
5041
5042 if (!pNumprs->cDig && dwState & B_LEADING_ZERO)
5043 {
5044 /* Ensure a 0 on its own gets stored */
5045 pNumprs->cDig = 1;
5046 rgbTmp[0] = 0;
5047 }
5048
5049 if (pNumprs->dwOutFlags & NUMPRS_EXPONENT && dwState & B_PROCESSING_EXPONENT)
5050 {
5051 pNumprs->cchUsed = cchUsed;
5052 return DISP_E_TYPEMISMATCH; /* Failed to completely parse the exponent */
5053 }
5054
5055 if (pNumprs->dwOutFlags & NUMPRS_INEXACT)
5056 {
5057 if (dwState & B_INEXACT_ZEROS)
5058 pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* All zeros doesn't set NUMPRS_INEXACT */
5059 } else if(pNumprs->dwInFlags & NUMPRS_HEX_OCT)
5060 {
5061 /* copy all of the digits into the output digit buffer */
5062 /* this is exactly what windows does although it also returns */
5063 /* cDig of X and writes X+Y where Y>=0 number of digits to rgbDig */
5064 memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
5065
5066 if (dwState & B_PROCESSING_HEX) {
5067 /* hex numbers have always the same format */
5068 pNumprs->nPwr10=0;
5069 pNumprs->nBaseShift=4;
5070 } else {
5071 if (dwState & B_PROCESSING_OCT) {
5072 /* oct numbers have always the same format */
5073 pNumprs->nPwr10=0;
5074 pNumprs->nBaseShift=3;
5075 } else {
5076 while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
5077 {
5078 if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
5079 pNumprs->nPwr10--;
5080 else
5081 pNumprs->nPwr10++;
5082
5083 pNumprs->cDig--;
5084 }
5085 }
5086 }
5087 } else
5088 {
5089 /* Remove trailing zeros from the last (whole number or decimal) part */
5090 while (pNumprs->cDig > 1 && !rgbTmp[pNumprs->cDig - 1])
5091 {
5092 if (pNumprs->dwOutFlags & NUMPRS_DECIMAL)
5093 pNumprs->nPwr10--;
5094 else
5095 pNumprs->nPwr10++;
5096
5097 pNumprs->cDig--;
5098 }
5099 }
5100
5101 if (pNumprs->cDig <= iMaxDigits)
5102 pNumprs->dwOutFlags &= ~NUMPRS_INEXACT; /* Ignore stripped zeros for NUMPRS_INEXACT */
5103 else
5104 pNumprs->cDig = iMaxDigits; /* Only return iMaxDigits worth of digits */
5105
5106 /* Copy the digits we processed into rgbDig */
5107 memcpy(rgbDig, rgbTmp, pNumprs->cDig * sizeof(BYTE));
5108
5109 /* Consume any trailing symbols and space */
5110 while (1)
5111 {
5112 if ((pNumprs->dwInFlags & NUMPRS_TRAILING_WHITE) && isspaceW(*lpszStr))
5113 {
5114 pNumprs->dwOutFlags |= NUMPRS_TRAILING_WHITE;
5115 do
5116 {
5117 cchUsed++;
5118 lpszStr++;
5119 } while (isspaceW(*lpszStr));
5120 }
5121 else if (pNumprs->dwInFlags & NUMPRS_TRAILING_PLUS &&
5122 !(pNumprs->dwOutFlags & NUMPRS_LEADING_PLUS) &&
5123 *lpszStr == chars.cPositiveSymbol)
5124 {
5125 pNumprs->dwOutFlags |= NUMPRS_TRAILING_PLUS;
5126 cchUsed++;
5127 lpszStr++;
5128 }
5129 else if (pNumprs->dwInFlags & NUMPRS_TRAILING_MINUS &&
5130 !(pNumprs->dwOutFlags & NUMPRS_LEADING_MINUS) &&
5131 *lpszStr == chars.cNegativeSymbol)
5132 {
5133 pNumprs->dwOutFlags |= (NUMPRS_TRAILING_MINUS|NUMPRS_NEG);
5134 cchUsed++;
5135 lpszStr++;
5136 }
5137 else if (pNumprs->dwInFlags & NUMPRS_PARENS && *lpszStr == ')' &&
5138 pNumprs->dwOutFlags & NUMPRS_PARENS)
5139 {
5140 cchUsed++;
5141 lpszStr++;
5142 pNumprs->dwOutFlags |= NUMPRS_NEG;
5143 }
5144 else
5145 break;
5146 }
5147
5148 if (pNumprs->dwOutFlags & NUMPRS_PARENS && !(pNumprs->dwOutFlags & NUMPRS_NEG))
5149 {
5150 pNumprs->cchUsed = cchUsed;
5151 return DISP_E_TYPEMISMATCH; /* Opening parenthesis not matched */
5152 }
5153
5154 if (pNumprs->dwInFlags & NUMPRS_USE_ALL && *lpszStr != '\0')
5155 return DISP_E_TYPEMISMATCH; /* Not all chars were consumed */
5156
5157 if (!pNumprs->cDig)
5158 return DISP_E_TYPEMISMATCH; /* No Number found */
5159
5160 pNumprs->cchUsed = cchUsed;
5161 TRACE("%s: Returning, NUMPARS->cchUsed: %x, NUMPARS->cDig: %x, pNumprs->dwOutFlags: %x, NUMPARS->nBaseShift: %x,, NUMPARS->nPwr10: %x\n",
5162 __FUNCTION__, cchUsed, pNumprs->cDig, pNumprs->dwOutFlags, pNumprs->nBaseShift, pNumprs->nPwr10);
5163 return S_OK;
5164}
5165
5166#if 0
5167/**********************************************************************
5168 * VarParseNumFromStr [OLEAUT32.46]
5169 */
5170HRESULT WINAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
5171 NUMPARSE * pnumprs, BYTE * rgbDig)
5172{
5173 int i,lastent=0;
5174 int cDig;
5175 BOOL foundNum=FALSE;
5176
5177 FIXME("(%s,flags=%lx,....), partial stub!\n",debugstr_w(strIn),dwFlags);
5178 FIXME("numparse: cDig=%d, InFlags=%lx\n",pnumprs->cDig,pnumprs->dwInFlags);
5179
5180 /* The other struct components are to be set by us */
5181 memset(rgbDig,0,pnumprs->cDig);
5182
5183 /* FIXME: Just patching some values in */
5184 pnumprs->nPwr10 = 0;
5185 pnumprs->nBaseShift = 0;
5186 pnumprs->cchUsed = lastent;
5187 pnumprs->dwOutFlags = NUMPRS_DECIMAL;
5188
5189 cDig = 0;
5190 for (i=0; strIn[i] ;i++) {
5191 if ((strIn[i]>='0') && (strIn[i]<='9')) {
5192 foundNum = TRUE;
5193 if (pnumprs->cDig > cDig) {
5194 *(rgbDig++)=strIn[i]-'0';
5195 cDig++;
5196 lastent = i;
5197 }
5198 } else if ((strIn[i]=='-') && (foundNum==FALSE)) {
5199 pnumprs->dwOutFlags |= NUMPRS_NEG;
5200 }
5201 }
5202 pnumprs->cDig = cDig;
5203 TRACE("numparse out: cDig=%d, OutFlags=%lx\n",pnumprs->cDig,pnumprs->dwOutFlags);
5204 return S_OK;
5205}
5206#endif
5207
5208
5209/**********************************************************************
5210 * VarNumFromParseNum [OLEAUT32.47]
5211 *
5212 * Convert a NUMPARSE structure into a numeric Variant type.
5213 *
5214 * PARAMS
5215 * pNumprs [I] Source for parsed number. cDig must be set to the size of rgbDig
5216 * rgbDig [I] Source for the numbers digits
5217 * dwVtBits [I] VTBIT_ flags from "oleauto.h" indicating the acceptable dest types
5218 * pVarDst [O] Destination for the converted Variant value.
5219 *
5220 * RETURNS
5221 * Success: S_OK. pVarDst contains the converted value.
5222 * Failure: E_INVALIDARG, if any parameter is invalid.
5223 * DISP_E_OVERFLOW, if the number is too big for the types set in dwVtBits.
5224 *
5225 * NOTES
5226 * - The smallest favoured type present in dwVtBits that can represent the
5227 * number in pNumprs without losing precision is used.
5228 * - Signed types are preferrred over unsigned types of the same size.
5229 * - Preferred types in order are: integer, float, double, currency then decimal.
5230 * - Rounding (dropping of decimal points) occurs without error. See VarI8FromR8()
5231 * for details of the rounding method.
5232 * - pVarDst is not cleared before the result is stored in it.
5233 */
5234HRESULT WINAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
5235 ULONG dwVtBits, VARIANT * pvar)
5236{
5237#ifdef __WIN32OS2__
5238 DWORD xint;
5239 int i;
5240
5241 TRACE("%s: NUMPARSE->cDig: %x, NUMPARSE->nBaseShift: %x, NUMPARSE->dwOutFlags: %x dwVtBits=%lx. rgbDig: \n",
5242 __FUNCTION__, pnumprs->cDig, pnumprs->nBaseShift, pnumprs->dwOutFlags, dwVtBits);
5243
5244 xint = 0;
5245 for (i=0;i<pnumprs->cDig;i++)
5246 xint = xint*10 + rgbDig[i];
5247
5248 if (pnumprs->dwOutFlags & NUMPRS_NEG) {
5249 xint = xint * -1;
5250 }
5251 TRACE("%s: xint: %x (%ld)\n", __FUNCTION__, xint, xint);
5252
5253 VariantInit(pvar);
5254 if (dwVtBits & VTBIT_I4) {
5255 V_VT(pvar) = VT_I4;
5256 V_UNION(pvar,intVal) = xint;
5257 return S_OK;
5258 }
5259 if (dwVtBits & VTBIT_R8) {
5260 V_VT(pvar) = VT_R8;
5261 V_UNION(pvar,dblVal) = xint;
5262 return S_OK;
5263 }
5264 if (dwVtBits & VTBIT_R4) {
5265 V_VT(pvar) = VT_R4;
5266 V_UNION(pvar,fltVal) = xint;
5267 return S_OK;
5268 }
5269 if (dwVtBits & VTBIT_I2) {
5270 V_VT(pvar) = VT_I2;
5271 V_UNION(pvar,iVal) = xint;
5272 return S_OK;
5273 }
5274 /* FIXME: Currency should be from a double */
5275 if (dwVtBits & VTBIT_CY) {
5276 V_VT(pvar) = VT_CY;
5277 TRACE("Calculated currency is xint=%ld\n", xint);
5278 VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
5279 TRACE("Calculated cy is %ld,%lu\n", V_UNION(pvar,cyVal).s.Hi, V_UNION(pvar,cyVal).s.Lo);
5280 return VarCyFromInt( (int) xint, &V_UNION(pvar,cyVal) );
5281 }
5282
5283 if (dwVtBits & VTBIT_DECIMAL)
5284 {
5285 int i;
5286 ULONG carry;
5287 /* ULONG64 tmp; */
5288 ULONG tmp;
5289 DECIMAL* pDec = &V_DECIMAL(pvar);
5290
5291 V_VT(pvar) = VT_DECIMAL;
5292
5293 DECIMAL_SETZERO(pDec);
5294 DEC_LO32(pDec) = 0;
5295
5296 if (pnumprs->dwOutFlags & NUMPRS_NEG)
5297 DEC_SIGN(pDec) = DECIMAL_NEG;
5298 else
5299 DEC_SIGN(pDec) = DECIMAL_POS;
5300
5301 /* Factor the significant digits */
5302 for (i = 0; i < pnumprs->cDig; i++)
5303 {
5304 if(0xffffffff /10 - 9 < DEC_LO32(pDec) ) {
5305 /* Overflow expected. This code only support 32Bit numbers for now */
5306 FIXME("%s: Converted number will be > 32bit! Only partial implementation. Returning DISP_E_OVERFLOW.", __FUNCTION__);
5307 DEC_LO32(pDec) = UI4_MAX;
5308 return DISP_E_OVERFLOW;
5309 }
5310
5311 tmp = DEC_LO32(pDec) * 10 + rgbDig[i];
5312
5313 /* No support for numbers > 32 bit for now. */
5314 DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX);
5315 DEC_MID32(pDec) = (ULONG)0;
5316 DEC_HI32(pDec) = (ULONG)0;
5317
5318 /* The following is not working because of missing ULONG64 !! */
5319#if 0
5320 carry = (ULONG)(tmp >> 32);
5321 DEC_LO64(pDec)=tmp;
5322 DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX);
5323 tmp = (ULONG)DEC_MID32(pDec) * 10 + carry;
5324 carry = (ULONG)(tmp >> 32);
5325 DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX);
5326 tmp = (ULONG)DEC_HI32(pDec) * 10 + carry;
5327 DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX);
5328#endif
5329
5330 if (tmp >> 32 & UI4_MAX)
5331 {
5332 VarNumFromParseNum_DecOverflow:
5333 TRACE("Overflow\n");
5334 DEC_LO32(pDec) = DEC_MID32(pDec) = DEC_HI32(pDec) = UI4_MAX;
5335 return DISP_E_OVERFLOW;
5336 }
5337 }
5338
5339 TRACE("Done... LO32: %x, MID32: %x, HI32: %x, DEC_LO64: %x, SignScale: %x, sign: %x\n",
5340 DEC_LO32(pDec), DEC_MID32(pDec), DEC_HI32(pDec), DEC_LO64(pDec), DEC_SIGNSCALE(pDec), DEC_SIGN(pDec) );
5341
5342 return S_OK;
5343 }
5344
5345 FIXME("%s: (..,dwVtBits=%lx,....), partial stub!\n", __FUNCTION__, dwVtBits);
5346 FIXME("vtbitmask is unsupported %lx, int=%d\n",dwVtBits, (int) xint);
5347 return E_FAIL;
5348} /* End of __WIN32OS2__ */
5349
5350#else
5351
5352 /* Scale factors and limits for double arithmetic */
5353 static const double dblMultipliers[11] = {
5354 1.0, 10.0, 100.0, 1000.0, 10000.0, 100000.0,
5355 1000000.0, 10000000.0, 100000000.0, 1000000000.0, 10000000000.0
5356 };
5357 static const double dblMinimums[11] = {
5358 R8_MIN, R8_MIN*10.0, R8_MIN*100.0, R8_MIN*1000.0, R8_MIN*10000.0,
5359 R8_MIN*100000.0, R8_MIN*1000000.0, R8_MIN*10000000.0,
5360 R8_MIN*100000000.0, R8_MIN*1000000000.0, R8_MIN*10000000000.0
5361 };
5362 static const double dblMaximums[11] = {
5363 R8_MAX, R8_MAX/10.0, R8_MAX/100.0, R8_MAX/1000.0, R8_MAX/10000.0,
5364 R8_MAX/100000.0, R8_MAX/1000000.0, R8_MAX/10000000.0,
5365 R8_MAX/100000000.0, R8_MAX/1000000000.0, R8_MAX/10000000000.0
5366 };
5367
5368 int wholeNumberDigits, fractionalDigits, divisor10 = 0, multiplier10 = 0;
5369
5370 TRACE("(%p,%p,0x%lx,%p)\n", pNumprs, rgbDig, dwVtBits, pVarDst);
5371
5372 if (pNumprs->nBaseShift)
5373 {
5374 /* nBaseShift indicates a hex or octal number */
5375 ULONG64 ul64 = 0;
5376 LONG64 l64;
5377 int i;
5378
5379 /* Convert the hex or octal number string into a UI64 */
5380 for (i = 0; i < pNumprs->cDig; i++)
5381 {
5382 if (ul64 > ((UI8_MAX>>pNumprs->nBaseShift) - rgbDig[i]))
5383 {
5384 TRACE("Overflow multiplying digits\n");
5385 return DISP_E_OVERFLOW;
5386 }
5387 ul64 = (ul64<<pNumprs->nBaseShift) + rgbDig[i];
5388 }
5389
5390 /* also make a negative representation */
5391 l64=-ul64;
5392
5393 /* Try signed and unsigned types in size order */
5394 if (dwVtBits & VTBIT_I1 && ((ul64 <= I1_MAX)||(l64 >= I1_MIN)))
5395 {
5396 V_VT(pVarDst) = VT_I1;
5397 if (ul64 <= I1_MAX)
5398 V_I1(pVarDst) = ul64;
5399 else
5400 V_I1(pVarDst) = l64;
5401 return S_OK;
5402 }
5403 else if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX)
5404 {
5405 V_VT(pVarDst) = VT_UI1;
5406 V_UI1(pVarDst) = ul64;
5407 return S_OK;
5408 }
5409 else if (dwVtBits & VTBIT_I2 && ((ul64 <= I2_MAX)||(l64 >= I2_MIN)))
5410 {
5411 V_VT(pVarDst) = VT_I2;
5412 if (ul64 <= I2_MAX)
5413 V_I2(pVarDst) = ul64;
5414 else
5415 V_I2(pVarDst) = l64;
5416 return S_OK;
5417 }
5418 else if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX)
5419 {
5420 V_VT(pVarDst) = VT_UI2;
5421 V_UI2(pVarDst) = ul64;
5422 return S_OK;
5423 }
5424 else if (dwVtBits & VTBIT_I4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN)))
5425 {
5426 V_VT(pVarDst) = VT_I4;
5427 if (ul64 <= I4_MAX)
5428 V_I4(pVarDst) = ul64;
5429 else
5430 V_I4(pVarDst) = l64;
5431 return S_OK;
5432 }
5433 else if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX)
5434 {
5435 V_VT(pVarDst) = VT_UI4;
5436 V_UI4(pVarDst) = ul64;
5437 return S_OK;
5438 }
5439 else if (dwVtBits & VTBIT_I8 && ((ul64 <= I4_MAX)||(l64>=I4_MIN)))
5440 {
5441 V_VT(pVarDst) = VT_I8;
5442 V_I8(pVarDst) = ul64;
5443 return S_OK;
5444 }
5445 else if (dwVtBits & VTBIT_UI8)
5446 {
5447 V_VT(pVarDst) = VT_UI8;
5448 V_UI8(pVarDst) = ul64;
5449 return S_OK;
5450 }
5451 else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL)
5452 {
5453 V_VT(pVarDst) = VT_DECIMAL;
5454 DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0);
5455 DEC_HI32(&V_DECIMAL(pVarDst)) = 0;
5456 DEC_LO64(&V_DECIMAL(pVarDst)) = ul64;
5457 return S_OK;
5458 }
5459 else if (dwVtBits & VTBIT_R4 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN)))
5460 {
5461 V_VT(pVarDst) = VT_R4;
5462 if (ul64 <= I4_MAX)
5463 V_R4(pVarDst) = ul64;
5464 else
5465 V_R4(pVarDst) = l64;
5466 return S_OK;
5467 }
5468 else if (dwVtBits & VTBIT_R8 && ((ul64 <= I4_MAX)||(l64 >= I4_MIN)))
5469 {
5470 V_VT(pVarDst) = VT_R8;
5471 if (ul64 <= I4_MAX)
5472 V_R8(pVarDst) = ul64;
5473 else
5474 V_R8(pVarDst) = l64;
5475 return S_OK;
5476 }
5477 TRACE("Overflow: possible return types: 0x%lx, value: %s\n", dwVtBits, wine_dbgstr_longlong(ul64));
5478 return DISP_E_OVERFLOW;
5479 }
5480
5481 /* Count the number of relevant fractional and whole digits stored,
5482 * And compute the divisor/multiplier to scale the number by.
5483 */
5484 if (pNumprs->nPwr10 < 0)
5485 {
5486 if (-pNumprs->nPwr10 >= pNumprs->cDig)
5487 {
5488 /* A real number < +/- 1.0 e.g. 0.1024 or 0.01024 */
5489 wholeNumberDigits = 0;
5490 fractionalDigits = pNumprs->cDig;
5491 divisor10 = -pNumprs->nPwr10;
5492 }
5493 else
5494 {
5495 /* An exactly represented real number e.g. 1.024 */
5496 wholeNumberDigits = pNumprs->cDig + pNumprs->nPwr10;
5497 fractionalDigits = pNumprs->cDig - wholeNumberDigits;
5498 divisor10 = pNumprs->cDig - wholeNumberDigits;
5499 }
5500 }
5501 else if (pNumprs->nPwr10 == 0)
5502 {
5503 /* An exactly represented whole number e.g. 1024 */
5504 wholeNumberDigits = pNumprs->cDig;
5505 fractionalDigits = 0;
5506 }
5507 else /* pNumprs->nPwr10 > 0 */
5508 {
5509 /* A whole number followed by nPwr10 0's e.g. 102400 */
5510 wholeNumberDigits = pNumprs->cDig;
5511 fractionalDigits = 0;
5512 multiplier10 = pNumprs->nPwr10;
5513 }
5514
5515 TRACE("cDig %d; nPwr10 %d, whole %d, frac %d ", pNumprs->cDig,
5516 pNumprs->nPwr10, wholeNumberDigits, fractionalDigits);
5517 TRACE("mult %d; div %d\n", multiplier10, divisor10);
5518
5519 if (dwVtBits & (INTEGER_VTBITS|VTBIT_DECIMAL) &&
5520 (!fractionalDigits || !(dwVtBits & (REAL_VTBITS|VTBIT_CY|VTBIT_DECIMAL))))
5521 {
5522 /* We have one or more integer output choices, and either:
5523 * 1) An integer input value, or
5524 * 2) A real number input value but no floating output choices.
5525 * Alternately, we have a DECIMAL output available and an integer input.
5526 *
5527 * So, place the integer value into pVarDst, using the smallest type
5528 * possible and preferring signed over unsigned types.
5529 */
5530 BOOL bOverflow = FALSE, bNegative;
5531 ULONG64 ul64 = 0;
5532 int i;
5533
5534 /* Convert the integer part of the number into a UI8 */
5535 for (i = 0; i < wholeNumberDigits; i++)
5536 {
5537 if (ul64 > (UI8_MAX / 10 - rgbDig[i]))
5538 {
5539 TRACE("Overflow multiplying digits\n");
5540 bOverflow = TRUE;
5541 break;
5542 }
5543 ul64 = ul64 * 10 + rgbDig[i];
5544 }
5545
5546 /* Account for the scale of the number */
5547 if (!bOverflow && multiplier10)
5548 {
5549 for (i = 0; i < multiplier10; i++)
5550 {
5551 if (ul64 > (UI8_MAX / 10))
5552 {
5553 TRACE("Overflow scaling number\n");
5554 bOverflow = TRUE;
5555 break;
5556 }
5557 ul64 = ul64 * 10;
5558 }
5559 }
5560
5561 /* If we have any fractional digits, round the value.
5562 * Note we don't have to do this if divisor10 is < 1,
5563 * because this means the fractional part must be < 0.5
5564 */
5565 if (!bOverflow && fractionalDigits && divisor10 > 0)
5566 {
5567 const BYTE* fracDig = rgbDig + wholeNumberDigits;
5568 BOOL bAdjust = FALSE;
5569
5570 TRACE("first decimal value is %d\n", *fracDig);
5571
5572 if (*fracDig > 5)
5573 bAdjust = TRUE; /* > 0.5 */
5574 else if (*fracDig == 5)
5575 {
5576 for (i = 1; i < fractionalDigits; i++)
5577 {
5578 if (fracDig[i])
5579 {
5580 bAdjust = TRUE; /* > 0.5 */
5581 break;
5582 }
5583 }
5584 /* If exactly 0.5, round only odd values */
5585 if (i == fractionalDigits && (ul64 & 1))
5586 bAdjust = TRUE;
5587 }
5588
5589 if (bAdjust)
5590 {
5591 if (ul64 == UI8_MAX)
5592 {
5593 TRACE("Overflow after rounding\n");
5594 bOverflow = TRUE;
5595 }
5596 ul64++;
5597 }
5598 }
5599
5600 /* Zero is not a negative number */
5601 bNegative = pNumprs->dwOutFlags & NUMPRS_NEG && ul64 ? TRUE : FALSE;
5602
5603 TRACE("Integer value is %lld, bNeg %d\n", ul64, bNegative);
5604
5605 /* For negative integers, try the signed types in size order */
5606 if (!bOverflow && bNegative)
5607 {
5608 if (dwVtBits & (VTBIT_I1|VTBIT_I2|VTBIT_I4|VTBIT_I8))
5609 {
5610 if (dwVtBits & VTBIT_I1 && ul64 <= -I1_MIN)
5611 {
5612 V_VT(pVarDst) = VT_I1;
5613 V_I1(pVarDst) = -ul64;
5614 return S_OK;
5615 }
5616 else if (dwVtBits & VTBIT_I2 && ul64 <= -I2_MIN)
5617 {
5618 V_VT(pVarDst) = VT_I2;
5619 V_I2(pVarDst) = -ul64;
5620 return S_OK;
5621 }
5622 else if (dwVtBits & VTBIT_I4 && ul64 <= -((LONGLONG)I4_MIN))
5623 {
5624 V_VT(pVarDst) = VT_I4;
5625 V_I4(pVarDst) = -ul64;
5626 return S_OK;
5627 }
5628 else if (dwVtBits & VTBIT_I8 && ul64 <= (ULONGLONG)I8_MAX + 1)
5629 {
5630 V_VT(pVarDst) = VT_I8;
5631 V_I8(pVarDst) = -ul64;
5632 return S_OK;
5633 }
5634 else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL)
5635 {
5636 /* Decimal is only output choice left - fast path */
5637 V_VT(pVarDst) = VT_DECIMAL;
5638 DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_NEG,0);
5639 DEC_HI32(&V_DECIMAL(pVarDst)) = 0;
5640 DEC_LO64(&V_DECIMAL(pVarDst)) = -ul64;
5641 return S_OK;
5642 }
5643 }
5644 }
5645 else if (!bOverflow)
5646 {
5647 /* For positive integers, try signed then unsigned types in size order */
5648 if (dwVtBits & VTBIT_I1 && ul64 <= I1_MAX)
5649 {
5650 V_VT(pVarDst) = VT_I1;
5651 V_I1(pVarDst) = ul64;
5652 return S_OK;
5653 }
5654 else if (dwVtBits & VTBIT_UI1 && ul64 <= UI1_MAX)
5655 {
5656 V_VT(pVarDst) = VT_UI1;
5657 V_UI1(pVarDst) = ul64;
5658 return S_OK;
5659 }
5660 else if (dwVtBits & VTBIT_I2 && ul64 <= I2_MAX)
5661 {
5662 V_VT(pVarDst) = VT_I2;
5663 V_I2(pVarDst) = ul64;
5664 return S_OK;
5665 }
5666 else if (dwVtBits & VTBIT_UI2 && ul64 <= UI2_MAX)
5667 {
5668 V_VT(pVarDst) = VT_UI2;
5669 V_UI2(pVarDst) = ul64;
5670 return S_OK;
5671 }
5672 else if (dwVtBits & VTBIT_I4 && ul64 <= I4_MAX)
5673 {
5674 V_VT(pVarDst) = VT_I4;
5675 V_I4(pVarDst) = ul64;
5676 return S_OK;
5677 }
5678 else if (dwVtBits & VTBIT_UI4 && ul64 <= UI4_MAX)
5679 {
5680 V_VT(pVarDst) = VT_UI4;
5681 V_UI4(pVarDst) = ul64;
5682 return S_OK;
5683 }
5684 else if (dwVtBits & VTBIT_I8 && ul64 <= I8_MAX)
5685 {
5686 V_VT(pVarDst) = VT_I8;
5687 V_I8(pVarDst) = ul64;
5688 return S_OK;
5689 }
5690 else if (dwVtBits & VTBIT_UI8)
5691 {
5692 V_VT(pVarDst) = VT_UI8;
5693 V_UI8(pVarDst) = ul64;
5694 return S_OK;
5695 }
5696 else if ((dwVtBits & REAL_VTBITS) == VTBIT_DECIMAL)
5697 {
5698 /* Decimal is only output choice left - fast path */
5699 V_VT(pVarDst) = VT_DECIMAL;
5700 DEC_SIGNSCALE(&V_DECIMAL(pVarDst)) = SIGNSCALE(DECIMAL_POS,0);
5701 DEC_HI32(&V_DECIMAL(pVarDst)) = 0;
5702 DEC_LO64(&V_DECIMAL(pVarDst)) = ul64;
5703 return S_OK;
5704 }
5705 }
5706 }
5707
5708 if (dwVtBits & REAL_VTBITS)
5709 {
5710 /* Try to put the number into a float or real */
5711 BOOL bOverflow = FALSE, bNegative = pNumprs->dwOutFlags & NUMPRS_NEG;
5712 double whole = 0.0;
5713 int i;
5714
5715 /* Convert the number into a double */
5716 for (i = 0; i < pNumprs->cDig; i++)
5717 whole = whole * 10.0 + rgbDig[i];
5718
5719 TRACE("Whole double value is %16.16g\n", whole);
5720
5721 /* Account for the scale */
5722 while (multiplier10 > 10)
5723 {
5724 if (whole > dblMaximums[10])
5725 {
5726 dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY);
5727 bOverflow = TRUE;
5728 break;
5729 }
5730 whole = whole * dblMultipliers[10];
5731 multiplier10 -= 10;
5732 }
5733 if (multiplier10)
5734 {
5735 if (whole > dblMaximums[multiplier10])
5736 {
5737 dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY);
5738 bOverflow = TRUE;
5739 }
5740 else
5741 whole = whole * dblMultipliers[multiplier10];
5742 }
5743
5744 TRACE("Scaled double value is %16.16g\n", whole);
5745
5746 while (divisor10 > 10)
5747 {
5748 if (whole < dblMinimums[10])
5749 {
5750 dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */
5751 bOverflow = TRUE;
5752 break;
5753 }
5754 whole = whole / dblMultipliers[10];
5755 divisor10 -= 10;
5756 }
5757 if (divisor10)
5758 {
5759 if (whole < dblMinimums[divisor10])
5760 {
5761 dwVtBits &= ~(VTBIT_R4|VTBIT_R8|VTBIT_CY); /* Underflow */
5762 bOverflow = TRUE;
5763 }
5764 else
5765 whole = whole / dblMultipliers[divisor10];
5766 }
5767 if (!bOverflow)
5768 TRACE("Final double value is %16.16g\n", whole);
5769
5770 if (dwVtBits & VTBIT_R4 &&
5771 ((whole <= R4_MAX && whole >= R4_MIN) || whole == 0.0))
5772 {
5773 TRACE("Set R4 to final value\n");
5774 V_VT(pVarDst) = VT_R4; /* Fits into a float */
5775 V_R4(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole;
5776 return S_OK;
5777 }
5778
5779 if (dwVtBits & VTBIT_R8)
5780 {
5781 TRACE("Set R8 to final value\n");
5782 V_VT(pVarDst) = VT_R8; /* Fits into a double */
5783 V_R8(pVarDst) = pNumprs->dwOutFlags & NUMPRS_NEG ? -whole : whole;
5784 return S_OK;
5785 }
5786
5787 if (dwVtBits & VTBIT_CY)
5788 {
5789 if (SUCCEEDED(VarCyFromR8(bNegative ? -whole : whole, &V_CY(pVarDst))))
5790 {
5791 V_VT(pVarDst) = VT_CY; /* Fits into a currency */
5792 TRACE("Set CY to final value\n");
5793 return S_OK;
5794 }
5795 TRACE("Value Overflows CY\n");
5796 }
5797 }
5798
5799 if (dwVtBits & VTBIT_DECIMAL)
5800 {
5801 int i;
5802 ULONG carry;
5803 ULONG64 tmp;
5804 DECIMAL* pDec = &V_DECIMAL(pVarDst);
5805
5806 DECIMAL_SETZERO(pDec);
5807 DEC_LO32(pDec) = 0;
5808
5809 if (pNumprs->dwOutFlags & NUMPRS_NEG)
5810 DEC_SIGN(pDec) = DECIMAL_NEG;
5811 else
5812 DEC_SIGN(pDec) = DECIMAL_POS;
5813
5814 /* Factor the significant digits */
5815 for (i = 0; i < pNumprs->cDig; i++)
5816 {
5817 tmp = (ULONG64)DEC_LO32(pDec) * 10 + rgbDig[i];
5818 carry = (ULONG)(tmp >> 32);
5819 DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX);
5820 tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry;
5821 carry = (ULONG)(tmp >> 32);
5822 DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX);
5823 tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry;
5824 DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX);
5825
5826 if (tmp >> 32 & UI4_MAX)
5827 {
5828VarNumFromParseNum_DecOverflow:
5829 TRACE("Overflow\n");
5830 DEC_LO32(pDec) = DEC_MID32(pDec) = DEC_HI32(pDec) = UI4_MAX;
5831 return DISP_E_OVERFLOW;
5832 }
5833 }
5834
5835 /* Account for the scale of the number */
5836 while (multiplier10 > 0)
5837 {
5838 tmp = (ULONG64)DEC_LO32(pDec) * 10;
5839 carry = (ULONG)(tmp >> 32);
5840 DEC_LO32(pDec) = (ULONG)(tmp & UI4_MAX);
5841 tmp = (ULONG64)DEC_MID32(pDec) * 10 + carry;
5842 carry = (ULONG)(tmp >> 32);
5843 DEC_MID32(pDec) = (ULONG)(tmp & UI4_MAX);
5844 tmp = (ULONG64)DEC_HI32(pDec) * 10 + carry;
5845 DEC_HI32(pDec) = (ULONG)(tmp & UI4_MAX);
5846
5847 if (tmp >> 32 & UI4_MAX)
5848 goto VarNumFromParseNum_DecOverflow;
5849 multiplier10--;
5850 }
5851 DEC_SCALE(pDec) = divisor10;
5852
5853 V_VT(pVarDst) = VT_DECIMAL;
5854 return S_OK;
5855 }
5856 return DISP_E_OVERFLOW; /* No more output choices */
5857}
5858#endif
5859
5860/**********************************************************************
5861 * VarFormatDateTime [OLEAUT32.97]
5862 */
5863HRESULT WINAPI VarFormatDateTime(LPVARIANT var, INT format, ULONG dwFlags, BSTR *out)
5864{
5865 FIXME("%p %d %lx %p\n", var, format, dwFlags, out);
5866 return E_NOTIMPL;
5867}
5868
5869/**********************************************************************
5870 * VarFormatCurrency [OLEAUT32.127]
5871 */
5872HRESULT WINAPI VarFormatCurrency(LPVARIANT var, INT digits, INT lead, INT paren, INT group, ULONG dwFlags, BSTR *out)
5873{
5874 FIXME("%p %d %d %d %d %lx %p\n", var, digits, lead, paren, group, dwFlags, out);
5875 return E_NOTIMPL;
5876}
5877
5878/**********************************************************************
5879 * VarFormatNumber [OLEAUT32.107]
5880 */
5881HRESULT WINAPI VarFormatNumber(LPVARIANT pvarIn, int iNumDig, int iIncLead, int iUseParens, int iGroup, ULONG dwFlags, BSTR* pbstrOut)
5882{
5883 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
5884 return E_NOTIMPL;
5885}
5886
5887
5888/**********************************************************************
5889 * VarFormatPercent [OLEAUT32.117]
5890 */
5891HRESULT WINAPI VarFormatPercent(LPVARIANT pvarIn, int iNumDig, int iIncLead, int iUseParens, int iGroup, ULONG dwFlags, BSTR* pbstrOut)
5892{
5893 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
5894 return E_NOTIMPL;
5895}
5896
5897
5898/**********************************************************************
5899 * VarWeekdayName [OLEAUT32.128]
5900 */
5901HRESULT WINAPI VarWeekdayName(int iWeekday, int fAbbrey, int iFirstDay, ULONG dwFlags, BSTR* pbstrOut)
5902{
5903 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
5904 return E_NOTIMPL;
5905}
5906
5907
5908/**********************************************************************
5909 * VarMonthName [OLEAUT32.129]
5910 */
5911HRESULT WINAPI VarMonthName(int iMonth, int fAbbrey, ULONG dwFlags, BSTR* pbstrOut)
5912{
5913 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
5914 return E_NOTIMPL;
5915}
5916
5917
5918/**********************************************************************
5919 * VariantTimeToDosDateTime [OLEAUT32.13]
5920 * Convert variant representation of time to the date and time representation
5921 * stored in dos.
5922 */
5923INT WINAPI VariantTimeToDosDateTime(DATE pvtime, USHORT *wDosDate, USHORT *wDosTime)
5924{
5925 struct tm t;
5926 *wDosTime = 0;
5927 *wDosDate = 0;
5928
5929 TRACE("( 0x%x, 0x%x, %p ), stub\n", *wDosDate, *wDosTime, &pvtime );
5930
5931 if (DateToTm(pvtime, 0, &t) < 0) return 0;
5932
5933 *wDosTime = *wDosTime | (t.tm_sec / 2);
5934 *wDosTime = *wDosTime | (t.tm_min << 5);
5935 *wDosTime = *wDosTime | (t.tm_hour << 11);
5936
5937 *wDosDate = *wDosDate | t.tm_mday ;
5938 *wDosDate = *wDosDate | t.tm_mon << 5;
5939 *wDosDate = *wDosDate | ((t.tm_year - 1980) << 9) ;
5940
5941 return 1;
5942}
5943
5944
5945/***********************************************************************
5946 * SystemTimeToVariantTime [OLEAUT32.184]
5947 */
5948HRESULT WINAPI SystemTimeToVariantTime( LPSYSTEMTIME lpSystemTime, double *pvtime )
5949{
5950 struct tm t;
5951
5952 TRACE(" %d/%d/%d %d:%d:%d\n",
5953 lpSystemTime->wMonth, lpSystemTime->wDay,
5954 lpSystemTime->wYear, lpSystemTime->wHour,
5955 lpSystemTime->wMinute, lpSystemTime->wSecond);
5956
5957 if (lpSystemTime->wYear >= 1900)
5958 {
5959 t.tm_sec = lpSystemTime->wSecond;
5960 t.tm_min = lpSystemTime->wMinute;
5961 t.tm_hour = lpSystemTime->wHour;
5962
5963 t.tm_mday = lpSystemTime->wDay;
5964 t.tm_mon = lpSystemTime->wMonth - 1; /* tm_mon is 0..11, wMonth is 1..12 */
5965 t.tm_year = lpSystemTime->wYear;
5966
5967 return TmToDATE( &t, pvtime );
5968 }
5969 else
5970 {
5971 double tmpDate;
5972 long firstDayOfNextYear;
5973 long thisDay;
5974 long leftInYear;
5975 long result;
5976
5977 double decimalPart = 0.0;
5978
5979 t.tm_sec = lpSystemTime->wSecond;
5980 t.tm_min = lpSystemTime->wMinute;
5981 t.tm_hour = lpSystemTime->wHour;
5982
5983 /* Step year forward the same number of years before 1900 */
5984 t.tm_year = 1900 + 1899 - lpSystemTime->wYear;
5985 t.tm_mon = lpSystemTime->wMonth - 1;
5986 t.tm_mday = lpSystemTime->wDay;
5987
5988 /* Calculate date */
5989 TmToDATE( &t, pvtime );
5990
5991 thisDay = (double) floor( *pvtime );
5992 decimalPart = fmod( *pvtime, thisDay );
5993
5994 /* Now, calculate the same time for the first of Jan that year */
5995 t.tm_mon = 0;
5996 t.tm_mday = 1;
5997 t.tm_sec = 0;
5998 t.tm_min = 0;
5999 t.tm_hour = 0;
6000 t.tm_year = t.tm_year+1;
6001 TmToDATE( &t, &tmpDate );
6002 firstDayOfNextYear = (long) floor(tmpDate);
6003
6004 /* Finally since we know the size of the year, subtract the two to get
6005 remaining time in the year */
6006 leftInYear = firstDayOfNextYear - thisDay;
6007
6008 /* Now we want full years up to the year in question, and remainder of year
6009 of the year in question */
6010 if (isleap(lpSystemTime->wYear) ) {
6011 TRACE("Extra day due to leap year\n");
6012 result = 2.0 - ((firstDayOfNextYear - 366) + leftInYear - 2.0);
6013 } else {
6014 result = 2.0 - ((firstDayOfNextYear - 365) + leftInYear - 2.0);
6015 }
6016 *pvtime = (double) result + decimalPart;
6017 TRACE("<1899 support: returned %f, 1st day %ld, thisday %ld, left %ld\n", *pvtime, firstDayOfNextYear, thisDay, leftInYear);
6018
6019 return 1;
6020 }
6021
6022 return 0;
6023}
6024
6025/***********************************************************************
6026 * VariantTimeToSystemTime [OLEAUT32.185]
6027 */
6028HRESULT WINAPI VariantTimeToSystemTime( double vtime, LPSYSTEMTIME lpSystemTime )
6029{
6030 double t = 0, timeofday = 0;
6031
6032 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
6033 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
6034
6035 /* The Month_Code is used to find the Day of the Week (LY = LeapYear)*/
6036 static const BYTE Month_Code[] = {0, 1, 4, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
6037 static const BYTE Month_Code_LY[] = {0, 0, 3, 4, 0, 2, 5, 0, 3, 6, 1, 4, 6};
6038
6039 /* The Century_Code is used to find the Day of the Week */
6040 static const BYTE Century_Code[] = {0, 6, 4, 2};
6041
6042 struct tm r;
6043
6044 TRACE(" Variant = %f SYSTEMTIME ptr %p\n", vtime, lpSystemTime);
6045
6046 if (vtime >= 0)
6047 {
6048
6049 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
6050
6051 lpSystemTime->wSecond = r.tm_sec;
6052 lpSystemTime->wMinute = r.tm_min;
6053 lpSystemTime->wHour = r.tm_hour;
6054 lpSystemTime->wDay = r.tm_mday;
6055 lpSystemTime->wMonth = r.tm_mon;
6056
6057 if (lpSystemTime->wMonth == 12)
6058 lpSystemTime->wMonth = 1;
6059 else
6060 lpSystemTime->wMonth++;
6061
6062 lpSystemTime->wYear = r.tm_year;
6063 }
6064 else
6065 {
6066 vtime = -1*vtime;
6067
6068 if (DateToTm(vtime, 0, &r ) <= 0) return 0;
6069
6070 lpSystemTime->wSecond = r.tm_sec;
6071 lpSystemTime->wMinute = r.tm_min;
6072 lpSystemTime->wHour = r.tm_hour;
6073
6074 lpSystemTime->wMonth = 13 - r.tm_mon;
6075
6076 if (lpSystemTime->wMonth == 1)
6077 lpSystemTime->wMonth = 12;
6078 else
6079 lpSystemTime->wMonth--;
6080
6081 lpSystemTime->wYear = 1899 - (r.tm_year - 1900);
6082
6083 if (!isleap(lpSystemTime->wYear) )
6084 lpSystemTime->wDay = Days_Per_Month[13 - lpSystemTime->wMonth] - r.tm_mday;
6085 else
6086 lpSystemTime->wDay = Days_Per_Month_LY[13 - lpSystemTime->wMonth] - r.tm_mday;
6087
6088
6089 }
6090
6091 if (!isleap(lpSystemTime->wYear))
6092 {
6093 /*
6094 (Century_Code+Month_Code+Year_Code+Day) % 7
6095
6096 The century code repeats every 400 years , so the array
6097 works out like this,
6098
6099 Century_Code[0] is for 16th/20th Centry
6100 Century_Code[1] is for 17th/21th Centry
6101 Century_Code[2] is for 18th/22th Centry
6102 Century_Code[3] is for 19th/23th Centry
6103
6104 The year code is found with the formula (year + (year / 4))
6105 the "year" must be between 0 and 99 .
6106
6107 The Month Code (Month_Code[1]) starts with January and
6108 ends with December.
6109 */
6110
6111 lpSystemTime->wDayOfWeek = (
6112 Century_Code[(( (lpSystemTime->wYear+100) - lpSystemTime->wYear%100) /100) %4]+
6113 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
6114 Month_Code[lpSystemTime->wMonth]+
6115 lpSystemTime->wDay) % 7;
6116
6117 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
6118 else lpSystemTime->wDayOfWeek -= 1;
6119 }
6120 else
6121 {
6122 lpSystemTime->wDayOfWeek = (
6123 Century_Code[(((lpSystemTime->wYear+100) - lpSystemTime->wYear%100)/100)%4]+
6124 ((lpSystemTime->wYear%100)+(lpSystemTime->wYear%100)/4)+
6125 Month_Code_LY[lpSystemTime->wMonth]+
6126 lpSystemTime->wDay) % 7;
6127
6128 if (lpSystemTime->wDayOfWeek == 0) lpSystemTime->wDayOfWeek = 7;
6129 else lpSystemTime->wDayOfWeek -= 1;
6130 }
6131
6132 t = floor(vtime);
6133 timeofday = vtime - t;
6134
6135 lpSystemTime->wMilliseconds = (timeofday
6136 - lpSystemTime->wHour*(1/24)
6137 - lpSystemTime->wMinute*(1/1440)
6138 - lpSystemTime->wSecond*(1/86400) )*(1/5184000);
6139
6140 return 1;
6141}
6142
6143/***********************************************************************
6144 * VarUdateFromDate [OLEAUT32.331]
6145 */
6146HRESULT WINAPI VarUdateFromDate( DATE datein, ULONG dwFlags, UDATE *pudateout)
6147{
6148 HRESULT i = 0;
6149 static const BYTE Days_Per_Month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
6150 static const BYTE Days_Per_Month_LY[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
6151
6152 TRACE("DATE = %f\n", (double)datein);
6153 i = VariantTimeToSystemTime(datein, &(pudateout->st) );
6154
6155 if (i)
6156 {
6157 pudateout->wDayOfYear = 0;
6158
6159 if (isleap(pudateout->st.wYear))
6160 {
6161 for (i =1; i<pudateout->st.wMonth; i++)
6162 pudateout->wDayOfYear += Days_Per_Month[i];
6163 }
6164 else
6165 {
6166 for (i =1; i<pudateout->st.wMonth; i++)
6167 pudateout->wDayOfYear += Days_Per_Month_LY[i];
6168 }
6169
6170 pudateout->wDayOfYear += pudateout->st.wDay;
6171 dwFlags = 0; /*VAR_VALIDDATE*/
6172 }
6173 else dwFlags = 0;
6174
6175 return i;
6176}
6177
6178/***********************************************************************
6179 * VarDateFromUdate [OLEAUT32.330]
6180 */
6181HRESULT WINAPI VarDateFromUdate(UDATE *pudateout,
6182 ULONG dwFlags, DATE *datein)
6183{
6184 HRESULT i;
6185 double t = 0;
6186 TRACE(" %d/%d/%d %d:%d:%d\n",
6187 pudateout->st.wMonth, pudateout->st.wDay,
6188 pudateout->st.wYear, pudateout->st.wHour,
6189 pudateout->st.wMinute, pudateout->st.wSecond);
6190
6191
6192 i = SystemTimeToVariantTime(&(pudateout->st), &t);
6193 *datein = t;
6194
6195 if (i) return S_OK;
6196 else return E_INVALIDARG;
6197}
6198
6199
6200/**********************************************************************
6201 * VarBstrCmp [OLEAUT32.314]
6202 *
6203 * flags can be:
6204 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
6205 * NORM_IGNORESTRINGWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
6206 *
6207 */
6208HRESULT WINAPI VarBstrCmp(BSTR left, BSTR right, LCID lcid, DWORD flags)
6209{
6210 INT r;
6211
6212 TRACE("( %s %s %ld %lx ) partial stub\n", debugstr_w(left), debugstr_w(right), lcid, flags);
6213
6214 /* Contrary to the MSDN, this returns eq for null vs null, null vs L"" and L"" vs NULL */
6215 if((!left) || (!right)) {
6216
6217 if (!left && (!right || *right==0)) return VARCMP_EQ;
6218 else if (!right && (!left || *left==0)) return VARCMP_EQ;
6219 else return VARCMP_NULL;
6220 }
6221
6222 if(flags&NORM_IGNORECASE)
6223 r = lstrcmpiW(left,right);
6224 else
6225 r = lstrcmpW(left,right);
6226
6227 if(r<0)
6228 return VARCMP_LT;
6229 if(r>0)
6230 return VARCMP_GT;
6231
6232 return VARCMP_EQ;
6233}
6234
6235/**********************************************************************
6236 * VarBstrCat [OLEAUT32.313]
6237 */
6238HRESULT WINAPI VarBstrCat(BSTR left, BSTR right, BSTR *out)
6239{
6240 BSTR result;
6241 int size = 0;
6242
6243 TRACE("( %s %s %p )\n", debugstr_w(left), debugstr_w(right), out);
6244
6245 /* On Windows, NULL parms are still handled (as empty strings) */
6246 if (left) size=size + lstrlenW(left);
6247 if (right) size=size + lstrlenW(right);
6248
6249 if (out) {
6250 result = SysAllocStringLen(NULL, size);
6251 *out = result;
6252 if (left) lstrcatW(result,left);
6253 if (right) lstrcatW(result,right);
6254 TRACE("result = %s, [%p]\n", debugstr_w(result), result);
6255 }
6256 return S_OK;
6257}
6258
6259/**********************************************************************
6260 * VarCat [OLEAUT32.318]
6261 */
6262HRESULT WINAPI VarCat(LPVARIANT left, LPVARIANT right, LPVARIANT out)
6263{
6264 /* Should we VariantClear out? */
6265 /* Can we handle array, vector, by ref etc. */
6266 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL &&
6267 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
6268 {
6269 V_VT(out) = VT_NULL;
6270 return S_OK;
6271 }
6272 else if (V_VT(left) == VT_BSTR && V_VT(right) == VT_BSTR)
6273 {
6274 V_VT(out) = VT_BSTR;
6275 VarBstrCat (V_BSTR(left), V_BSTR(right), &V_BSTR(out));
6276 return S_OK;
6277 }
6278 else
6279 FIXME ("types not supported\n");
6280 return S_OK;
6281}
6282
6283/**********************************************************************
6284 * VarCmp [OLEAUT32.176]
6285 *
6286 * flags can be:
6287 * NORM_IGNORECASE, NORM_IGNORENONSPACE, NORM_IGNORESYMBOLS
6288 * NORM_IGNOREWIDTH, NORM_IGNOREKANATYPE, NORM_IGNOREKASHIDA
6289 *
6290 */
6291HRESULT WINAPI VarCmp(LPVARIANT left, LPVARIANT right, LCID lcid, DWORD flags)
6292{
6293
6294
6295 BOOL lOk = TRUE;
6296 BOOL rOk = TRUE;
6297 LONGLONG lVal = -1;
6298 LONGLONG rVal = -1;
6299
6300 TRACE("Left Var:\n");
6301 dump_Variant(left);
6302 TRACE("Right Var:\n");
6303 dump_Variant(right);
6304
6305 /* If either are null, then return VARCMP_NULL */
6306 if ((V_VT(left)&VT_TYPEMASK) == VT_NULL ||
6307 (V_VT(right)&VT_TYPEMASK) == VT_NULL)
6308 return VARCMP_NULL;
6309
6310 /* Strings - use VarBstrCmp */
6311 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
6312 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
6313 return VarBstrCmp(V_BSTR(left), V_BSTR(right), lcid, flags);
6314 }
6315
6316 /* Integers - Ideally like to use VarDecCmp, but no Dec support yet
6317 Use LONGLONG to maximize ranges */
6318 lOk = TRUE;
6319 switch (V_VT(left)&VT_TYPEMASK) {
6320 case VT_I1 : lVal = V_UNION(left,cVal); break;
6321 case VT_I2 : lVal = V_UNION(left,iVal); break;
6322 case VT_I4 : lVal = V_UNION(left,lVal); break;
6323 case VT_INT : lVal = V_UNION(left,lVal); break;
6324 case VT_UI1 : lVal = V_UNION(left,bVal); break;
6325 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
6326 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
6327 case VT_UINT : lVal = V_UNION(left,ulVal); break;
6328 default: lOk = FALSE;
6329 }
6330
6331 rOk = TRUE;
6332 switch (V_VT(right)&VT_TYPEMASK) {
6333 case VT_I1 : rVal = V_UNION(right,cVal); break;
6334 case VT_I2 : rVal = V_UNION(right,iVal); break;
6335 case VT_I4 : rVal = V_UNION(right,lVal); break;
6336 case VT_INT : rVal = V_UNION(right,lVal); break;
6337 case VT_UI1 : rVal = V_UNION(right,bVal); break;
6338 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
6339 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
6340 case VT_UINT : rVal = V_UNION(right,ulVal); break;
6341#ifdef __WIN32OS2__
6342 case VT_R8 : rVal = V_UNION(right,dblVal); break;
6343#endif
6344 default: rOk = FALSE;
6345 }
6346
6347 if (lOk && rOk) {
6348 if (lVal < rVal) {
6349 return VARCMP_LT;
6350 } else if (lVal > rVal) {
6351 return VARCMP_GT;
6352 } else {
6353 return VARCMP_EQ;
6354 }
6355 }
6356
6357 /* Strings - use VarBstrCmp */
6358 if ((V_VT(left)&VT_TYPEMASK) == VT_DATE &&
6359 (V_VT(right)&VT_TYPEMASK) == VT_DATE) {
6360
6361 if (floor(V_UNION(left,date)) == floor(V_UNION(right,date))) {
6362 /* Due to floating point rounding errors, calculate varDate in whole numbers) */
6363 double wholePart = 0.0;
6364 double leftR;
6365 double rightR;
6366
6367 /* Get the fraction * 24*60*60 to make it into whole seconds */
6368 wholePart = (double) floor( V_UNION(left,date) );
6369 if (wholePart == 0) wholePart = 1;
6370 leftR = floor(fmod( V_UNION(left,date), wholePart ) * (24*60*60));
6371
6372 wholePart = (double) floor( V_UNION(right,date) );
6373 if (wholePart == 0) wholePart = 1;
6374 rightR = floor(fmod( V_UNION(right,date), wholePart ) * (24*60*60));
6375
6376 if (leftR < rightR) {
6377 return VARCMP_LT;
6378 } else if (leftR > rightR) {
6379 return VARCMP_GT;
6380 } else {
6381 return VARCMP_EQ;
6382 }
6383
6384 } else if (V_UNION(left,date) < V_UNION(right,date)) {
6385 return VARCMP_LT;
6386 } else if (V_UNION(left,date) > V_UNION(right,date)) {
6387 return VARCMP_GT;
6388 }
6389 }
6390
6391
6392 FIXME("VarCmp partial implementation, doesnt support these pair of variant types");
6393 return E_FAIL;
6394}
6395
6396/**********************************************************************
6397 * VarAnd [OLEAUT32.142]
6398 *
6399 */
6400HRESULT WINAPI VarAnd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
6401{
6402 HRESULT rc = E_FAIL;
6403
6404
6405 TRACE("Left Var:\n");
6406 dump_Variant(left);
6407 TRACE("Right Var:\n");
6408 dump_Variant(right);
6409
6410 if ((V_VT(left)&VT_TYPEMASK) == VT_BOOL &&
6411 (V_VT(right)&VT_TYPEMASK) == VT_BOOL) {
6412
6413 V_VT(result) = VT_BOOL;
6414 if (V_BOOL(left) && V_BOOL(right)) {
6415 V_BOOL(result) = VARIANT_TRUE;
6416 } else {
6417 V_BOOL(result) = VARIANT_FALSE;
6418 }
6419 rc = S_OK;
6420
6421 } else {
6422 FIXME("VarAnd stub\n");
6423 }
6424
6425 TRACE("rc=%d, Result:\n", (int) rc);
6426 dump_Variant(result);
6427 return rc;
6428}
6429
6430/**********************************************************************
6431 * VarOr [OLEAUT32.157]
6432 *
6433 * Perform a logical or (OR) operation on two variants.
6434 *
6435 * PARAMS
6436 * pVarLeft [I] First variant
6437 * pVarRight [I] Variant to OR with pVarLeft
6438 * pVarOut [O] Destination for OR result
6439 *
6440 * RETURNS
6441 * Success: S_OK. pVarOut contains the result of the operation with its type
6442 * taken from the table listed under VarXor().
6443 * Failure: An HRESULT error code indicating the error.
6444 *
6445 * NOTES
6446 * See the Notes section of VarXor() for further information.
6447 */
6448HRESULT WINAPI VarOr(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut)
6449{
6450 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6451 return E_NOTIMPL;
6452
6453
6454#if 0
6455 VARTYPE vt = VT_I4;
6456 VARIANT varLeft, varRight, varStr;
6457 HRESULT hRet;
6458
6459#if 0
6460 TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", pVarLeft, debugstr_VT(pVarLeft),
6461 debugstr_VF(pVarLeft), pVarRight, debugstr_VT(pVarRight),
6462 debugstr_VF(pVarRight), pVarOut);
6463#endif
6464 if (V_EXTRA_TYPE(pVarLeft) || V_EXTRA_TYPE(pVarRight) ||
6465 V_VT(pVarLeft) == VT_UNKNOWN || V_VT(pVarRight) == VT_UNKNOWN ||
6466 V_VT(pVarLeft) == VT_DISPATCH || V_VT(pVarRight) == VT_DISPATCH ||
6467 V_VT(pVarLeft) == VT_RECORD || V_VT(pVarRight) == VT_RECORD)
6468 return DISP_E_BADVARTYPE;
6469
6470 V_VT(&varLeft) = V_VT(&varRight) = V_VT(&varStr) = VT_EMPTY;
6471
6472 if (V_VT(pVarLeft) == VT_NULL || V_VT(pVarRight) == VT_NULL)
6473 {
6474 /* NULL OR Zero is NULL, NULL OR value is value */
6475 if (V_VT(pVarLeft) == VT_NULL)
6476 pVarLeft = pVarRight; /* point to the non-NULL var */
6477
6478 V_VT(pVarOut) = VT_NULL;
6479 V_I4(pVarOut) = 0;
6480
6481 switch (V_VT(pVarLeft))
6482 {
6483 case VT_DATE: case VT_R8:
6484 if (V_R8(pVarLeft))
6485 goto VarOr_AsEmpty;
6486 return S_OK;
6487 case VT_BOOL:
6488 if (V_BOOL(pVarLeft))
6489 *pVarOut = *pVarLeft;
6490 return S_OK;
6491 case VT_I2: case VT_UI2:
6492 if (V_I2(pVarLeft))
6493 goto VarOr_AsEmpty;
6494 return S_OK;
6495 case VT_I1:
6496 if (V_I1(pVarLeft))
6497 goto VarOr_AsEmpty;
6498 return S_OK;
6499 case VT_UI1:
6500 if (V_UI1(pVarLeft))
6501 *pVarOut = *pVarLeft;
6502 return S_OK;
6503 case VT_R4:
6504 if (V_R4(pVarLeft))
6505 goto VarOr_AsEmpty;
6506 return S_OK;
6507 case VT_I4: case VT_UI4: case VT_INT: case VT_UINT:
6508 if (V_I4(pVarLeft))
6509 goto VarOr_AsEmpty;
6510 return S_OK;
6511 case VT_CY:
6512 if (V_CY(pVarLeft).int64)
6513 goto VarOr_AsEmpty;
6514 return S_OK;
6515 case VT_I8: case VT_UI8:
6516 if (V_I8(pVarLeft))
6517 goto VarOr_AsEmpty;
6518 return S_OK;
6519 case VT_DECIMAL:
6520 if (DEC_HI32(&V_DECIMAL(pVarLeft)) || DEC_LO64(&V_DECIMAL(pVarLeft)))
6521 goto VarOr_AsEmpty;
6522 return S_OK;
6523 case VT_BSTR:
6524 {
6525 VARIANT_BOOL b;
6526
6527 if (!V_BSTR(pVarLeft))
6528 return DISP_E_BADVARTYPE;
6529
6530 hRet = VarBoolFromStr(V_BSTR(pVarLeft), LOCALE_USER_DEFAULT, VAR_LOCALBOOL, &b);
6531 if (SUCCEEDED(hRet) && b)
6532 {
6533 V_VT(pVarOut) = VT_BOOL;
6534 V_BOOL(pVarOut) = b;
6535 }
6536 return hRet;
6537 }
6538 case VT_NULL: case VT_EMPTY:
6539 V_VT(pVarOut) = VT_NULL;
6540 return S_OK;
6541 default:
6542 return DISP_E_BADVARTYPE;
6543 }
6544 }
6545
6546 if (V_VT(pVarLeft) == VT_EMPTY || V_VT(pVarRight) == VT_EMPTY)
6547 {
6548 if (V_VT(pVarLeft) == VT_EMPTY)
6549 pVarLeft = pVarRight; /* point to the non-EMPTY var */
6550
6551VarOr_AsEmpty:
6552 /* Since one argument is empty (0), OR'ing it with the other simply
6553 * gives the others value (as 0|x => x). So just convert the other
6554 * argument to the required result type.
6555 */
6556 switch (V_VT(pVarLeft))
6557 {
6558 case VT_BSTR:
6559 if (!V_BSTR(pVarLeft))
6560 return DISP_E_BADVARTYPE;
6561
6562 hRet = VariantCopy(&varStr, pVarLeft);
6563 if (FAILED(hRet))
6564 goto VarOr_Exit;
6565 pVarLeft = &varStr;
6566 hRet = VariantChangeType(pVarLeft, pVarLeft, 0, VT_BOOL);
6567 if (FAILED(hRet))
6568 goto VarOr_Exit;
6569 /* Fall Through ... */
6570 case VT_EMPTY: case VT_UI1: case VT_BOOL: case VT_I2:
6571 V_VT(pVarOut) = VT_I2;
6572 break;
6573 case VT_DATE: case VT_CY: case VT_DECIMAL: case VT_R4: case VT_R8:
6574 case VT_I1: case VT_UI2: case VT_I4: case VT_UI4:
6575 case VT_INT: case VT_UINT: case VT_UI8:
6576 V_VT(pVarOut) = VT_I4;
6577 break;
6578 case VT_I8:
6579 V_VT(pVarOut) = VT_I8;
6580 break;
6581 default:
6582 return DISP_E_BADVARTYPE;
6583 }
6584 hRet = VariantCopy(&varLeft, pVarLeft);
6585 if (FAILED(hRet))
6586 goto VarOr_Exit;
6587 pVarLeft = &varLeft;
6588 hRet = VariantChangeType(pVarOut, pVarLeft, 0, V_VT(pVarOut));
6589 goto VarOr_Exit;
6590 }
6591
6592 if (V_VT(pVarLeft) == VT_BOOL && V_VT(pVarRight) == VT_BOOL)
6593 {
6594 V_VT(pVarOut) = VT_BOOL;
6595 V_BOOL(pVarOut) = V_BOOL(pVarLeft) | V_BOOL(pVarRight);
6596 return S_OK;
6597 }
6598
6599 if (V_VT(pVarLeft) == VT_UI1 && V_VT(pVarRight) == VT_UI1)
6600 {
6601 V_VT(pVarOut) = VT_UI1;
6602 V_UI1(pVarOut) = V_UI1(pVarLeft) | V_UI1(pVarRight);
6603 return S_OK;
6604 }
6605
6606 if (V_VT(pVarLeft) == VT_BSTR)
6607 {
6608 hRet = VariantCopy(&varStr, pVarLeft);
6609 if (FAILED(hRet))
6610 goto VarOr_Exit;
6611 pVarLeft = &varStr;
6612 hRet = VariantChangeType(pVarLeft, pVarLeft, 0, VT_BOOL);
6613 if (FAILED(hRet))
6614 goto VarOr_Exit;
6615 }
6616
6617 if (V_VT(pVarLeft) == VT_BOOL &&
6618 (V_VT(pVarRight) == VT_BOOL || V_VT(pVarRight) == VT_BSTR))
6619 {
6620 vt = VT_BOOL;
6621 }
6622 else if ((V_VT(pVarLeft) == VT_BOOL || V_VT(pVarLeft) == VT_UI1 ||
6623 V_VT(pVarLeft) == VT_I2 || V_VT(pVarLeft) == VT_BSTR) &&
6624 (V_VT(pVarRight) == VT_BOOL || V_VT(pVarRight) == VT_UI1 ||
6625 V_VT(pVarRight) == VT_I2 || V_VT(pVarRight) == VT_BSTR))
6626 {
6627 vt = VT_I2;
6628 }
6629 else if (V_VT(pVarLeft) == VT_I8 || V_VT(pVarRight) == VT_I8)
6630 {
6631 if (V_VT(pVarLeft) == VT_INT || V_VT(pVarRight) == VT_INT)
6632 return DISP_E_TYPEMISMATCH;
6633 vt = VT_I8;
6634 }
6635
6636 hRet = VariantCopy(&varLeft, pVarLeft);
6637 if (FAILED(hRet))
6638 goto VarOr_Exit;
6639
6640 hRet = VariantCopy(&varRight, pVarRight);
6641 if (FAILED(hRet))
6642 goto VarOr_Exit;
6643
6644 if (vt == VT_I4 && V_VT(&varLeft) == VT_UI4)
6645 V_VT(&varLeft) = VT_I4; /* Don't overflow */
6646 else
6647 {
6648 double d;
6649
6650 if (V_VT(&varLeft) == VT_BSTR &&
6651 FAILED(VarR8FromStr(V_BSTR(&varLeft), LOCALE_USER_DEFAULT, 0, &d)))
6652 hRet = VariantChangeType(&varLeft, &varLeft, VARIANT_LOCALBOOL, VT_BOOL);
6653 if (SUCCEEDED(hRet) && V_VT(&varLeft) != vt)
6654 hRet = VariantChangeType(&varLeft, &varLeft, 0, vt);
6655 if (FAILED(hRet))
6656 goto VarOr_Exit;
6657 }
6658
6659 if (vt == VT_I4 && V_VT(&varRight) == VT_UI4)
6660 V_VT(&varRight) = VT_I4; /* Don't overflow */
6661 else
6662 {
6663 double d;
6664
6665 if (V_VT(&varRight) == VT_BSTR &&
6666 FAILED(VarR8FromStr(V_BSTR(&varRight), LOCALE_USER_DEFAULT, 0, &d)))
6667 hRet = VariantChangeType(&varRight, &varRight, VARIANT_LOCALBOOL, VT_BOOL);
6668 if (SUCCEEDED(hRet) && V_VT(&varRight) != vt)
6669 hRet = VariantChangeType(&varRight, &varRight, 0, vt);
6670 if (FAILED(hRet))
6671 goto VarOr_Exit;
6672 }
6673
6674 V_VT(pVarOut) = vt;
6675 if (vt == VT_I8)
6676 {
6677 V_I8(pVarOut) = V_I8(&varLeft) | V_I8(&varRight);
6678 }
6679 else if (vt == VT_I4)
6680 {
6681 V_I4(pVarOut) = V_I4(&varLeft) | V_I4(&varRight);
6682 }
6683 else
6684 {
6685 V_I2(pVarOut) = V_I2(&varLeft) | V_I2(&varRight);
6686 }
6687
6688VarOr_Exit:
6689 VariantClear(&varStr);
6690 VariantClear(&varLeft);
6691 VariantClear(&varRight);
6692 return hRet;
6693#endif
6694}
6695
6696
6697/**********************************************************************
6698 * VarXor [OLEAUT32.167]
6699 */
6700HRESULT WINAPI VarXor(LPVARIANT pvarLeft, LPVARIANT pvarRight, LPVARIANT pvarResult)
6701{
6702 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6703
6704 return E_NOTIMPL;
6705}
6706
6707/**********************************************************************
6708 * VarNot [OLEAUT32.174]
6709 *
6710 */
6711HRESULT WINAPI VarNot(LPVARIANT in, LPVARIANT result)
6712{
6713 HRESULT rc = E_FAIL;
6714
6715 TRACE("Var In:\n");
6716 dump_Variant(in);
6717
6718 if ((V_VT(in)&VT_TYPEMASK) == VT_BOOL) {
6719
6720 V_VT(result) = VT_BOOL;
6721 if (V_BOOL(in)) {
6722 V_BOOL(result) = VARIANT_FALSE;
6723 } else {
6724 V_BOOL(result) = VARIANT_TRUE;
6725 }
6726 rc = S_OK;
6727
6728 } else {
6729 FIXME("VarNot stub\n");
6730 }
6731
6732 TRACE("rc=%d, Result:\n", (int) rc);
6733 dump_Variant(result);
6734 return rc;
6735}
6736
6737/**********************************************************************
6738 * VarNeg [OLEAUT32.173]
6739 *
6740 * Negate the value of a variant.
6741 *
6742 * PARAMS
6743 * pVarIn [I] Source variant
6744 * pVarOut [O] Destination for converted value
6745 *
6746 * RETURNS
6747 * Success: S_OK. pVarOut contains the converted value.
6748 * Failure: An HRESULT error code indicating the error.
6749 *
6750 * NOTES
6751 * - The type of the value stored in pVarOut depends on the type of pVarIn,
6752 * according to the following table:
6753 *| Input Type Output Type
6754 *| ---------- -----------
6755 *| VT_EMPTY VT_I2
6756 *| VT_UI1 VT_I2
6757 *| VT_BOOL VT_I2
6758 *| VT_BSTR VT_R8
6759 *| All Others Unchanged (unless promoted)
6760 * - Where the negated value of a variant does not fit in its base type, the type
6761 * is promoted according to the following table:
6762 *| Input Type Promoted To
6763 *| ---------- -----------
6764 *| VT_I2 VT_I4
6765 *| VT_I4 VT_R8
6766 *| VT_I8 VT_R8
6767 * - The native version of this function returns DISP_E_BADVARTYPE for valid
6768 * variant types that cannot be negated, and returns DISP_E_TYPEMISMATCH
6769 * for types which are not valid. Since this is in contravention of the
6770 * meaning of those error codes and unlikely to be relied on by applications,
6771 * this implementation returns errors consistent with the other high level
6772 * variant math functions.
6773 */
6774HRESULT WINAPI VarNeg(LPVARIANT pVarIn, LPVARIANT pVarOut)
6775{
6776 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6777 return E_NOTIMPL;
6778}
6779
6780/**********************************************************************
6781 * VarAbs [OLEAUT32.168]
6782 *
6783 * Convert a variant to its absolute value.
6784 *
6785 * PARAMS
6786 * pVarIn [I] Source variant
6787 * pVarOut [O] Destination for converted value
6788 *
6789 * RETURNS
6790 * Success: S_OK. pVarOut contains the absolute value of pVarIn.
6791 * Failure: An HRESULT error code indicating the error.
6792 *
6793 * NOTES
6794 * - This function does not process by-reference variants.
6795 * - The type of the value stored in pVarOut depends on the type of pVarIn,
6796 * according to the following table:
6797 *| Input Type Output Type
6798 *| ---------- -----------
6799 *| VT_BOOL VT_I2
6800 *| VT_BSTR VT_R8
6801 *| (All others) Unchanged
6802 */
6803HRESULT WINAPI VarAbs(LPVARIANT pVarIn, LPVARIANT pVarOut)
6804{
6805 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6806 return E_NOTIMPL;
6807}
6808
6809/**********************************************************************
6810 * VarFix [OLEAUT32.169]
6811 */
6812HRESULT WINAPI VarFix(LPVARIANT pvarIn, LPVARIANT pvarResult)
6813{
6814 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6815 return E_NOTIMPL;
6816}
6817
6818/**********************************************************************
6819 * VarInt [OLEAUT32.172]
6820 */
6821HRESULT WINAPI VarInt(LPVARIANT pvarIn, LPVARIANT pvarResult)
6822{
6823 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6824 return E_NOTIMPL;
6825}
6826
6827/**********************************************************************
6828 * VarImp [OLEAUT32.154]
6829 */
6830HRESULT WINAPI VarImp(LPVARIANT pvarLeft, LPVARIANT pvarRight, LPVARIANT pvarResult)
6831{
6832 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6833 return E_NOTIMPL;
6834}
6835
6836/**********************************************************************
6837 * VarMod [OLEAUT32.155]
6838 */
6839HRESULT WINAPI VarMod(LPVARIANT pvarLeft, LPVARIANT pvarRight, LPVARIANT pvarResult)
6840{
6841 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6842 return E_NOTIMPL;
6843}
6844
6845/**********************************************************************
6846 * VarEqv [OLEAUT32.152]
6847 *
6848 * Determine if two variants contain the same value.
6849 *
6850 * PARAMS
6851 * pVarLeft [I] First variant to compare
6852 * pVarRight [I] Variant to compare to pVarLeft
6853 * pVarOut [O] Destination for comparison result
6854 *
6855 * RETURNS
6856 * Success: S_OK. pVarOut contains the result of the comparison (VARIANT_TRUE
6857 * if equivalent or non-zero otherwise.
6858 * Failure: An HRESULT error code indicating the error.
6859 *
6860 * NOTES
6861 * - This function simply calls VarXor() on pVarLeft and pVarRight and inverts
6862 * the result.
6863 */
6864HRESULT WINAPI VarEqv(LPVARIANT pVarLeft, LPVARIANT pVarRight, LPVARIANT pVarOut)
6865{
6866 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6867 return E_NOTIMPL;
6868}
6869
6870
6871/**********************************************************************
6872 * VarIdiv [OLEAUT32.153]
6873 */
6874HRESULT WINAPI VarIdiv(LPVARIANT pvarLeft, LPVARIANT pvarRight, LPVARIANT pvarResult)
6875{
6876 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6877
6878 return E_NOTIMPL;
6879}
6880
6881/**********************************************************************
6882 * VarRound [OLEAUT32.175]
6883 */
6884HRESULT VarRound(LPVARIANT pvarIn, INT cDecimals, LPVARIANT pvarResult)
6885{
6886 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
6887
6888 return E_NOTIMPL;
6889}
6890
6891/**********************************************************************
6892 * VarPow [OLEAUT32.158]
6893 *
6894 */
6895HRESULT WINAPI VarPow(LPVARIANT left, LPVARIANT right, LPVARIANT result)
6896{
6897 HRESULT hr;
6898 VARIANT dl,dr;
6899
6900#if 0
6901 TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left), debugstr_VF(left),
6902 right, debugstr_VT(right), debugstr_VF(right), result);
6903#endif
6904
6905 hr = VariantChangeType(&dl,left,0,VT_R8);
6906 if (!SUCCEEDED(hr)) {
6907 ERR("Could not change passed left argument to VT_R8, handle it differently.\n");
6908 return E_FAIL;
6909 }
6910 hr = VariantChangeType(&dr,right,0,VT_R8);
6911 if (!SUCCEEDED(hr)) {
6912 ERR("Could not change passed right argument to VT_R8, handle it differently.\n");
6913 return E_FAIL;
6914 }
6915 V_VT(result) = VT_R8;
6916 V_R8(result) = pow(V_R8(&dl),V_R8(&dr));
6917 return S_OK;
6918}
6919
6920/**********************************************************************
6921 * VarAdd [OLEAUT32.141]
6922 * FIXME: From MSDN: If ... Then
6923 * Both expressions are of the string type Concatenated.
6924 * One expression is a string type and the other a character Addition.
6925 * One expression is numeric and the other is a string Addition.
6926 * Both expressions are numeric Addition.
6927 * Either expression is NULL NULL is returned.
6928 * Both expressions are empty Integer subtype is returned.
6929 *
6930 */
6931HRESULT WINAPI VarAdd(LPVARIANT left, LPVARIANT right, LPVARIANT result)
6932{
6933 HRESULT rc = E_FAIL;
6934
6935#if 0
6936 TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
6937 debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);
6938#endif
6939
6940 if ((V_VT(left)&VT_TYPEMASK) == VT_EMPTY)
6941 return VariantCopy(result,right);
6942
6943 if ((V_VT(right)&VT_TYPEMASK) == VT_EMPTY)
6944 return VariantCopy(result,left);
6945
6946 /* check if we add doubles */
6947 if (((V_VT(left)&VT_TYPEMASK) == VT_R8) || ((V_VT(right)&VT_TYPEMASK) == VT_R8)) {
6948 BOOL lOk = TRUE;
6949 BOOL rOk = TRUE;
6950 double lVal = -1;
6951 double rVal = -1;
6952 double res = -1;
6953
6954 lOk = TRUE;
6955 switch (V_VT(left)&VT_TYPEMASK) {
6956 case VT_I1 : lVal = V_UNION(left,cVal); break;
6957 case VT_I2 : lVal = V_UNION(left,iVal); break;
6958 case VT_I4 : lVal = V_UNION(left,lVal); break;
6959 case VT_INT : lVal = V_UNION(left,lVal); break;
6960 case VT_UI1 : lVal = V_UNION(left,bVal); break;
6961 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
6962 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
6963 case VT_UINT : lVal = V_UNION(left,ulVal); break;
6964 case VT_R4 : lVal = V_UNION(left,fltVal); break;
6965 case VT_R8 : lVal = V_UNION(left,dblVal); break;
6966 case VT_NULL : lVal = 0.0; break;
6967 default: lOk = FALSE;
6968 }
6969
6970 rOk = TRUE;
6971 switch (V_VT(right)&VT_TYPEMASK) {
6972 case VT_I1 : rVal = V_UNION(right,cVal); break;
6973 case VT_I2 : rVal = V_UNION(right,iVal); break;
6974 case VT_I4 : rVal = V_UNION(right,lVal); break;
6975 case VT_INT : rVal = V_UNION(right,lVal); break;
6976 case VT_UI1 : rVal = V_UNION(right,bVal); break;
6977 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
6978 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
6979 case VT_UINT : rVal = V_UNION(right,ulVal); break;
6980 case VT_R4 : rVal = V_UNION(right,fltVal);break;
6981 case VT_R8 : rVal = V_UNION(right,dblVal);break;
6982 case VT_NULL : rVal = 0.0; break;
6983 default: rOk = FALSE;
6984 }
6985
6986 if (lOk && rOk) {
6987 res = (lVal + rVal);
6988 V_VT(result) = VT_R8;
6989 V_UNION(result,dblVal) = res;
6990 rc = S_OK;
6991 } else {
6992 FIXME("Unhandled type pair %d / %d in double addition.\n",
6993 (V_VT(left)&VT_TYPEMASK),
6994 (V_VT(right)&VT_TYPEMASK)
6995 );
6996 }
6997 return rc;
6998 }
6999
7000 /* now check if we add floats. VT_R8 can no longer happen here! */
7001 if (((V_VT(left)&VT_TYPEMASK) == VT_R4) || ((V_VT(right)&VT_TYPEMASK) == VT_R4)) {
7002 BOOL lOk = TRUE;
7003 BOOL rOk = TRUE;
7004 float lVal = -1;
7005 float rVal = -1;
7006 float res = -1;
7007
7008 lOk = TRUE;
7009 switch (V_VT(left)&VT_TYPEMASK) {
7010 case VT_I1 : lVal = V_UNION(left,cVal); break;
7011 case VT_I2 : lVal = V_UNION(left,iVal); break;
7012 case VT_I4 : lVal = V_UNION(left,lVal); break;
7013 case VT_INT : lVal = V_UNION(left,lVal); break;
7014 case VT_UI1 : lVal = V_UNION(left,bVal); break;
7015 case VT_UI2 : lVal = V_UNION(left,uiVal); break;
7016 case VT_UI4 : lVal = V_UNION(left,ulVal); break;
7017 case VT_UINT : lVal = V_UNION(left,ulVal); break;
7018 case VT_R4 : lVal = V_UNION(left,fltVal); break;
7019 case VT_NULL : lVal = 0.0; break;
7020 default: lOk = FALSE;
7021 }
7022
7023 rOk = TRUE;
7024 switch (V_VT(right)&VT_TYPEMASK) {
7025 case VT_I1 : rVal = V_UNION(right,cVal); break;
7026 case VT_I2 : rVal = V_UNION(right,iVal); break;
7027 case VT_I4 : rVal = V_UNION(right,lVal); break;
7028 case VT_INT : rVal = V_UNION(right,lVal); break;
7029 case VT_UI1 : rVal = V_UNION(right,bVal); break;
7030 case VT_UI2 : rVal = V_UNION(right,uiVal); break;
7031 case VT_UI4 : rVal = V_UNION(right,ulVal); break;
7032 case VT_UINT : rVal = V_UNION(right,ulVal); break;
7033 case VT_R4 : rVal = V_UNION(right,fltVal);break;
7034 case VT_NULL : rVal = 0.0; break;
7035 default: rOk = FALSE;
7036 }
7037
7038 if (lOk && rOk) {
7039 res = (lVal + rVal);
7040 V_VT(result) = VT_R4;
7041 V_UNION(result,fltVal) = res;
7042 rc = S_OK;
7043 } else {
7044 FIXME("Unhandled type pair %d / %d in float addition.\n",
7045 (V_VT(left)&VT_TYPEMASK),
7046 (V_VT(right)&VT_TYPEMASK)
7047 );
7048 }
7049 return rc;
7050 }
7051
7052 /* Handle strings as concat */
7053 if ((V_VT(left)&VT_TYPEMASK) == VT_BSTR &&
7054 (V_VT(right)&VT_TYPEMASK) == VT_BSTR) {
7055 V_VT(result) = VT_BSTR;
7056 return VarBstrCat(V_BSTR(left), V_BSTR(right), &V_BSTR(result));
7057 } else {
7058
7059 /* Integers */
7060 BOOL lOk = TRUE;
7061 BOOL rOk = TRUE;
7062 LONGLONG lVal = -1;
7063 LONGLONG rVal = -1;
7064 LONGLONG res = -1;
7065 int resT = 0; /* Testing has shown I2 + I2 == I2, all else
7066 becomes I4 */
7067
7068 lOk = TRUE;
7069 switch (V_VT(left)&VT_TYPEMASK) {
7070 case VT_I1 : lVal = V_UNION(left,cVal); resT=VT_I4; break;
7071 case VT_I2 : lVal = V_UNION(left,iVal); resT=VT_I2; break;
7072 case VT_I4 : lVal = V_UNION(left,lVal); resT=VT_I4; break;
7073 case VT_INT : lVal = V_UNION(left,lVal); resT=VT_I4; break;
7074 case VT_UI1 : lVal = V_UNION(left,bVal); resT=VT_I4; break;
7075 case VT_UI2 : lVal = V_UNION(left,uiVal); resT=VT_I4; break;
7076 case VT_UI4 : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
7077 case VT_UINT : lVal = V_UNION(left,ulVal); resT=VT_I4; break;
7078 case VT_NULL : lVal = 0; resT = VT_I4; break;
7079 default: lOk = FALSE;
7080 }
7081
7082 rOk = TRUE;
7083 switch (V_VT(right)&VT_TYPEMASK) {
7084 case VT_I1 : rVal = V_UNION(right,cVal); resT=VT_I4; break;
7085 case VT_I2 : rVal = V_UNION(right,iVal); resT=max(VT_I2, resT); break;
7086 case VT_I4 : rVal = V_UNION(right,lVal); resT=VT_I4; break;
7087 case VT_INT : rVal = V_UNION(right,lVal); resT=VT_I4; break;
7088 case VT_UI1 : rVal = V_UNION(right,bVal); resT=VT_I4; break;
7089 case VT_UI2 : rVal = V_UNION(right,uiVal); resT=VT_I4; break;
7090 case VT_UI4 : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
7091 case VT_UINT : rVal = V_UNION(right,ulVal); resT=VT_I4; break;
7092 case VT_NULL : rVal = 0; resT=VT_I4; break;
7093 default: rOk = FALSE;
7094 }
7095
7096 if (lOk && rOk) {
7097 res = (lVal + rVal);
7098 V_VT(result) = resT;
7099 switch (resT) {
7100 case VT_I2 : V_UNION(result,iVal) = res; break;
7101 case VT_I4 : V_UNION(result,lVal) = res; break;
7102 default:
7103 FIXME("Unexpected result variant type %x\n", resT);
7104 V_UNION(result,lVal) = res;
7105 }
7106 rc = S_OK;
7107
7108 } else {
7109 FIXME("unimplemented part (0x%x + 0x%x)\n",V_VT(left), V_VT(right));
7110 }
7111 }
7112#if 0
7113 TRACE("returning 0x%8lx (%s%s),%ld\n", rc, debugstr_VT(result),
7114 debugstr_VF(result), V_VT(result) == VT_I4 ? V_I4(result) : V_I2(result));
7115#endif
7116 return rc;
7117}
7118
7119/**********************************************************************
7120 * VarSub [OLEAUT32.159]
7121 *
7122 */
7123HRESULT WINAPI VarSub(LPVARIANT left, LPVARIANT right, LPVARIANT result)
7124{
7125 HRESULT rc = E_FAIL;
7126 VARTYPE lvt,rvt,resvt;
7127 VARIANT lv,rv;
7128 BOOL found;
7129
7130#if 0
7131 TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
7132 debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);
7133#endif
7134
7135 VariantInit(&lv);VariantInit(&rv);
7136 lvt = V_VT(left)&VT_TYPEMASK;
7137 rvt = V_VT(right)&VT_TYPEMASK;
7138 found = FALSE;resvt = VT_VOID;
7139 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_DATE)|(1<<VT_R4)|(1<<VT_R8))) {
7140 found = TRUE;
7141 resvt = VT_R8;
7142 }
7143 if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
7144 found = TRUE;
7145 resvt = VT_I4;
7146 }
7147 if (!found) {
7148 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
7149 return E_FAIL;
7150 }
7151 rc = VariantChangeType(&lv, left, 0, resvt);
7152 if (FAILED(rc)) {
7153 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
7154 return rc;
7155 }
7156 rc = VariantChangeType(&rv, right, 0, resvt);
7157 if (FAILED(rc)) {
7158 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
7159 return rc;
7160 }
7161 switch (resvt) {
7162 case VT_R8:
7163 V_VT(result) = resvt;
7164 V_R8(result) = V_R8(&lv) - V_R8(&rv);
7165 rc = S_OK;
7166 break;
7167 case VT_I4:
7168 V_VT(result) = resvt;
7169 V_I4(result) = V_I4(&lv) - V_I4(&rv);
7170 rc = S_OK;
7171 break;
7172 }
7173#if 0
7174 TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result),
7175 debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result));
7176#endif
7177 return rc;
7178}
7179
7180
7181/**********************************************************************
7182 * VarDiv [OLEAUT32.143]
7183 *
7184 */
7185HRESULT WINAPI VarDiv(LPVARIANT left, LPVARIANT right, LPVARIANT result)
7186{
7187 HRESULT rc = E_FAIL;
7188 VARTYPE lvt,rvt,resvt;
7189 VARIANT lv,rv;
7190 BOOL found;
7191
7192#if 0
7193 TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
7194 debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);
7195#endif
7196
7197 VariantInit(&lv);VariantInit(&rv);
7198 lvt = V_VT(left)&VT_TYPEMASK;
7199 rvt = V_VT(right)&VT_TYPEMASK;
7200 found = FALSE;resvt = VT_VOID;
7201 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
7202 found = TRUE;
7203 resvt = VT_R8;
7204 }
7205 if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
7206 found = TRUE;
7207 resvt = VT_I4;
7208 }
7209 if (!found) {
7210 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
7211 return E_FAIL;
7212 }
7213 rc = VariantChangeType(&lv, left, 0, resvt);
7214 if (FAILED(rc)) {
7215 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
7216 return rc;
7217 }
7218 rc = VariantChangeType(&rv, right, 0, resvt);
7219 if (FAILED(rc)) {
7220 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
7221 return rc;
7222 }
7223 switch (resvt) {
7224 case VT_R8:
7225 V_VT(result) = resvt;
7226 V_R8(result) = V_R8(&lv) / V_R8(&rv);
7227 rc = S_OK;
7228 break;
7229 case VT_I4:
7230 V_VT(result) = resvt;
7231 V_I4(result) = V_I4(&lv) / V_I4(&rv);
7232 rc = S_OK;
7233 break;
7234 }
7235#if 0
7236 TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result),
7237 debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result));
7238#endif
7239 return rc;
7240}
7241
7242/**********************************************************************
7243 * VarMul [OLEAUT32.156]
7244 *
7245 */
7246HRESULT WINAPI VarMul(LPVARIANT left, LPVARIANT right, LPVARIANT result)
7247{
7248 HRESULT rc = E_FAIL;
7249 VARTYPE lvt,rvt,resvt;
7250 VARIANT lv,rv;
7251 BOOL found;
7252#if 0
7253 TRACE("(%p->(%s%s),%p->(%s%s),%p)\n", left, debugstr_VT(left),
7254 debugstr_VF(left), right, debugstr_VT(right), debugstr_VF(right), result);
7255#endif
7256 VariantInit(&lv);VariantInit(&rv);
7257 lvt = V_VT(left)&VT_TYPEMASK;
7258 rvt = V_VT(right)&VT_TYPEMASK;
7259 found = FALSE;resvt=VT_VOID;
7260 if (((1<<lvt) | (1<<rvt)) & ((1<<VT_R4)|(1<<VT_R8))) {
7261 found = TRUE;
7262 resvt = VT_R8;
7263 }
7264 if (!found && (((1<<lvt) | (1<<rvt)) & ((1<<VT_I1)|(1<<VT_I2)|(1<<VT_UI1)|(1<<VT_UI2)|(1<<VT_I4)|(1<<VT_UI4)|(1<<VT_INT)|(1<<VT_UINT)))) {
7265 found = TRUE;
7266 resvt = VT_I4;
7267 }
7268 if (!found) {
7269 FIXME("can't expand vt %d vs %d to a target type.\n",lvt,rvt);
7270 return E_FAIL;
7271 }
7272 rc = VariantChangeType(&lv, left, 0, resvt);
7273 if (FAILED(rc)) {
7274 FIXME("Could not convert 0x%x to %d?\n",V_VT(left),resvt);
7275 return rc;
7276 }
7277 rc = VariantChangeType(&rv, right, 0, resvt);
7278 if (FAILED(rc)) {
7279 FIXME("Could not convert 0x%x to %d?\n",V_VT(right),resvt);
7280 return rc;
7281 }
7282 switch (resvt) {
7283 case VT_R8:
7284 V_VT(result) = resvt;
7285 V_R8(result) = V_R8(&lv) * V_R8(&rv);
7286 rc = S_OK;
7287 break;
7288 case VT_I4:
7289 V_VT(result) = resvt;
7290 V_I4(result) = V_I4(&lv) * V_I4(&rv);
7291 rc = S_OK;
7292 break;
7293 }
7294#if 0
7295 TRACE("returning 0x%8lx (%s%s),%g\n", rc, debugstr_VT(result),
7296 debugstr_VF(result), V_VT(result) == VT_R8 ? V_R8(result) : (double)V_I4(result));
7297#endif
7298 return rc;
7299}
7300
7301/**********************************************************************
7302 * VarTokenizeFormatString [OLEAUT32.140]
7303 *
7304 * From investigation on W2K, a list is built up which is:
7305 *
7306 * <0x00> AA BB - Copy from AA for BB chars (Note 1 byte with wrap!)
7307 * <token> - Insert appropriate token
7308 *
7309 */
7310HRESULT WINAPI VarTokenizeFormatString(LPOLESTR format, LPBYTE rgbTok,
7311 int cbTok, int iFirstDay, int iFirstWeek,
7312 LCID lcid, int *pcbActual) {
7313
7314 FORMATHDR *hdr;
7315 int realLen, formatLeft;
7316 BYTE *pData;
7317 LPSTR pFormatA, pStart;
7318 int checkStr;
7319 BOOL insertCopy = FALSE;
7320 LPSTR copyFrom = NULL;
7321
7322 TRACE("'%s', %p %d %d %d only date support\n", debugstr_w(format), rgbTok, cbTok,
7323 iFirstDay, iFirstWeek);
7324
7325 /* Big enough for header? */
7326 if (cbTok < sizeof(FORMATHDR)) {
7327 return TYPE_E_BUFFERTOOSMALL;
7328 }
7329
7330 /* Insert header */
7331 hdr = (FORMATHDR *) rgbTok;
7332 memset(hdr, 0x00, sizeof(FORMATHDR));
7333 hdr->hex3 = 0x03; /* No idea what these are */
7334 hdr->hex6 = 0x06;
7335
7336 /* Start parsing string */
7337 realLen = sizeof(FORMATHDR);
7338 pData = rgbTok + realLen;
7339 pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
7340 pStart = pFormatA;
7341 formatLeft = strlen(pFormatA);
7342
7343 /* Work through the format */
7344 while (*pFormatA != 0x00) {
7345
7346 checkStr = 0;
7347 while (checkStr>=0 && (formatTokens[checkStr].tokenSize != 0x00)) {
7348 if (formatLeft >= formatTokens[checkStr].tokenSize &&
7349 strncmp(formatTokens[checkStr].str, pFormatA,
7350 formatTokens[checkStr].tokenSize) == 0) {
7351 TRACE("match on '%s'\n", formatTokens[checkStr].str);
7352
7353 /* Found Match! */
7354
7355 /* If we have skipped chars, insert the copy */
7356 if (insertCopy == TRUE) {
7357
7358 if ((realLen + 3) > cbTok) {
7359 HeapFree( GetProcessHeap(), 0, pFormatA );
7360 return TYPE_E_BUFFERTOOSMALL;
7361 }
7362 insertCopy = FALSE;
7363 *pData = TOK_COPY;
7364 pData++;
7365 *pData = (BYTE)(copyFrom - pStart);
7366 pData++;
7367 *pData = (BYTE)(pFormatA - copyFrom);
7368 pData++;
7369 realLen = realLen + 3;
7370 }
7371
7372
7373 /* Now insert the token itself */
7374 if ((realLen + 1) > cbTok) {
7375 HeapFree( GetProcessHeap(), 0, pFormatA );
7376 return TYPE_E_BUFFERTOOSMALL;
7377 }
7378 *pData = formatTokens[checkStr].tokenId;
7379 pData = pData + 1;
7380 realLen = realLen + 1;
7381
7382 pFormatA = pFormatA + formatTokens[checkStr].tokenSize;
7383 formatLeft = formatLeft - formatTokens[checkStr].tokenSize;
7384 checkStr = -1; /* Flag as found and break out of while loop */
7385 } else {
7386 checkStr++;
7387 }
7388 }
7389
7390 /* Did we ever match a token? */
7391 if (checkStr != -1 && insertCopy == FALSE) {
7392 TRACE("No match - need to insert copy from %p [%p]\n", pFormatA, pStart);
7393 insertCopy = TRUE;
7394 copyFrom = pFormatA;
7395 } else if (checkStr != -1) {
7396 pFormatA = pFormatA + 1;
7397 }
7398
7399 }
7400
7401 /* Finally, if we have skipped chars, insert the copy */
7402 if (insertCopy == TRUE) {
7403
7404 TRACE("Chars left over, so still copy %p,%p,%p\n", copyFrom, pStart, pFormatA);
7405 if ((realLen + 3) > cbTok) {
7406 HeapFree( GetProcessHeap(), 0, pFormatA );
7407 return TYPE_E_BUFFERTOOSMALL;
7408 }
7409 insertCopy = FALSE;
7410 *pData = TOK_COPY;
7411 pData++;
7412 *pData = (BYTE)(copyFrom - pStart);
7413 pData++;
7414 *pData = (BYTE)(pFormatA - copyFrom);
7415 pData++;
7416 realLen = realLen + 3;
7417 }
7418
7419 /* Finally insert the terminator */
7420 if ((realLen + 1) > cbTok) {
7421 HeapFree( GetProcessHeap(), 0, pFormatA );
7422 return TYPE_E_BUFFERTOOSMALL;
7423 }
7424 *pData++ = TOK_END;
7425 realLen = realLen + 1;
7426
7427 /* Finally fill in the length */
7428 hdr->len = realLen;
7429 *pcbActual = realLen;
7430
7431#if 0
7432 { int i,j;
7433 for (i=0; i<realLen; i=i+0x10) {
7434 printf(" %4.4x : ", i);
7435 for (j=0; j<0x10 && (i+j < realLen); j++) {
7436 printf("%2.2x ", rgbTok[i+j]);
7437 }
7438 printf("\n");
7439 }
7440 }
7441#endif
7442 HeapFree( GetProcessHeap(), 0, pFormatA );
7443
7444 return S_OK;
7445}
7446
7447/**********************************************************************
7448 * VarFormatFromTokens [OLEAUT32.139]
7449 * FIXME: No account of flags or iFirstDay etc
7450 */
7451HRESULT WINAPI VarFormatFromTokens(LPVARIANT varIn, LPOLESTR format,
7452 LPBYTE pbTokCur, ULONG dwFlags, BSTR *pbstrOut,
7453 LCID lcid) {
7454
7455 FORMATHDR *hdr = (FORMATHDR *)pbTokCur;
7456 BYTE *pData = pbTokCur + sizeof (FORMATHDR);
7457 LPSTR pFormatA = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
7458 char output[BUFFER_MAX];
7459 char *pNextPos;
7460 int size, whichToken;
7461 VARIANTARG Variant;
7462 struct tm TM;
7463
7464
7465
7466 TRACE("'%s', %p %lx %p only date support\n", pFormatA, pbTokCur, dwFlags, pbstrOut);
7467 TRACE("varIn:\n");
7468 dump_Variant(varIn);
7469
7470 memset(output, 0x00, BUFFER_MAX);
7471 pNextPos = output;
7472
7473 while (*pData != TOK_END && ((pData - pbTokCur) <= (hdr->len))) {
7474
7475 TRACE("Output looks like : '%s'\n", output);
7476
7477 /* Convert varient to appropriate data type */
7478 whichToken = 0;
7479 while ((formatTokens[whichToken].tokenSize != 0x00) &&
7480 (formatTokens[whichToken].tokenId != *pData)) {
7481 whichToken++;
7482 }
7483
7484 /* Use Variant local from here downwards as always correct type */
7485 if (formatTokens[whichToken].tokenSize > 0 &&
7486 formatTokens[whichToken].varTypeRequired != 0) {
7487 VariantInit( &Variant );
7488 if (Coerce( &Variant, lcid, dwFlags, varIn,
7489 formatTokens[whichToken].varTypeRequired ) != S_OK) {
7490 HeapFree( GetProcessHeap(), 0, pFormatA );
7491 return DISP_E_TYPEMISMATCH;
7492 } else if (formatTokens[whichToken].varTypeRequired == VT_DATE) {
7493 if( DateToTm( V_UNION(&Variant,date), dwFlags, &TM ) == FALSE ) {
7494 HeapFree( GetProcessHeap(), 0, pFormatA );
7495 return E_INVALIDARG;
7496 }
7497 }
7498 }
7499
7500 TRACE("Looking for match on token '%x'\n", *pData);
7501 switch (*pData) {
7502 case TOK_COPY:
7503 TRACE("Copy from %d for %d bytes\n", *(pData+1), *(pData+2));
7504 memcpy(pNextPos, &pFormatA[*(pData+1)], *(pData+2));
7505 pNextPos = pNextPos + *(pData+2);
7506 pData = pData + 3;
7507 break;
7508
7509 case TOK_COLON :
7510 /* Get locale information - Time Seperator */
7511 size = GetLocaleInfoA(lcid, LOCALE_STIME, NULL, 0);
7512 GetLocaleInfoA(lcid, LOCALE_STIME, pNextPos, size);
7513 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
7514 pNextPos = pNextPos + size;
7515 pData = pData + 1;
7516 break;
7517
7518 case TOK_SLASH :
7519 /* Get locale information - Date Seperator */
7520 size = GetLocaleInfoA(lcid, LOCALE_SDATE, NULL, 0);
7521 GetLocaleInfoA(lcid, LOCALE_SDATE, pNextPos, size);
7522 TRACE("TOK_COLON Time seperator is '%s'\n", pNextPos);
7523 pNextPos = pNextPos + size;
7524 pData = pData + 1;
7525 break;
7526
7527 case TOK_d :
7528 sprintf(pNextPos, "%d", TM.tm_mday);
7529 pNextPos = pNextPos + strlen(pNextPos);
7530 pData = pData + 1;
7531 break;
7532
7533 case TOK_dd :
7534 sprintf(pNextPos, "%2.2d", TM.tm_mday);
7535 pNextPos = pNextPos + strlen(pNextPos);
7536 pData = pData + 1;
7537 break;
7538
7539 case TOK_w :
7540 sprintf(pNextPos, "%d", TM.tm_wday+1);
7541 pNextPos = pNextPos + strlen(pNextPos);
7542 pData = pData + 1;
7543 break;
7544
7545 case TOK_m :
7546 sprintf(pNextPos, "%d", TM.tm_mon+1);
7547 pNextPos = pNextPos + strlen(pNextPos);
7548 pData = pData + 1;
7549 break;
7550
7551 case TOK_mm :
7552 sprintf(pNextPos, "%2.2d", TM.tm_mon+1);
7553 pNextPos = pNextPos + strlen(pNextPos);
7554 pData = pData + 1;
7555 break;
7556
7557 case TOK_q :
7558 sprintf(pNextPos, "%d", ((TM.tm_mon+1)/4)+1);
7559 pNextPos = pNextPos + strlen(pNextPos);
7560 pData = pData + 1;
7561 break;
7562
7563 case TOK_y :
7564 sprintf(pNextPos, "%2.2d", TM.tm_yday+1);
7565 pNextPos = pNextPos + strlen(pNextPos);
7566 pData = pData + 1;
7567 break;
7568
7569 case TOK_yy :
7570 sprintf(pNextPos, "%2.2d", TM.tm_year);
7571 pNextPos = pNextPos + strlen(pNextPos);
7572 pData = pData + 1;
7573 break;
7574
7575 case TOK_yyyy :
7576 sprintf(pNextPos, "%4.4d", TM.tm_year);
7577 pNextPos = pNextPos + strlen(pNextPos);
7578 pData = pData + 1;
7579 break;
7580
7581 case TOK_h :
7582 sprintf(pNextPos, "%d", TM.tm_hour);
7583 pNextPos = pNextPos + strlen(pNextPos);
7584 pData = pData + 1;
7585 break;
7586
7587 case TOK_Hh :
7588 sprintf(pNextPos, "%2.2d", TM.tm_hour);
7589 pNextPos = pNextPos + strlen(pNextPos);
7590 pData = pData + 1;
7591 break;
7592
7593 case TOK_N :
7594 sprintf(pNextPos, "%d", TM.tm_min);
7595 pNextPos = pNextPos + strlen(pNextPos);
7596 pData = pData + 1;
7597 break;
7598
7599 case TOK_Nn :
7600 sprintf(pNextPos, "%2.2d", TM.tm_min);
7601 pNextPos = pNextPos + strlen(pNextPos);
7602 pData = pData + 1;
7603 break;
7604
7605 case TOK_S :
7606 sprintf(pNextPos, "%d", TM.tm_sec);
7607 pNextPos = pNextPos + strlen(pNextPos);
7608 pData = pData + 1;
7609 break;
7610
7611 case TOK_Ss :
7612 sprintf(pNextPos, "%2.2d", TM.tm_sec);
7613 pNextPos = pNextPos + strlen(pNextPos);
7614 pData = pData + 1;
7615 break;
7616
7617 /* FIXME: To Do! */
7618 case TOK_ttttt :
7619 case TOK_AMsPM :
7620 case TOK_amspm :
7621 case TOK_AsP :
7622 case TOK_asp :
7623 case TOK_AMPM :
7624 case TOK_c :
7625 case TOK_ddd :
7626 case TOK_dddd :
7627 case TOK_ddddd :
7628 case TOK_dddddd :
7629 case TOK_ww :
7630 case TOK_mmm :
7631 case TOK_mmmm :
7632 default:
7633 FIXME("Unhandled token for VarFormat %d\n", *pData);
7634 HeapFree( GetProcessHeap(), 0, pFormatA );
7635 return E_INVALIDARG;
7636 }
7637
7638 }
7639
7640 *pbstrOut = StringDupAtoBstr( output );
7641 HeapFree( GetProcessHeap(), 0, pFormatA );
7642 return S_OK;
7643}
7644
7645/**********************************************************************
7646 * VarFormat [OLEAUT32.87]
7647 *
7648 */
7649HRESULT WINAPI VarFormat(LPVARIANT varIn, LPOLESTR format,
7650 int firstDay, int firstWeek, ULONG dwFlags,
7651 BSTR *pbstrOut) {
7652
7653 LPSTR pNewString = NULL;
7654 HRESULT rc = S_OK;
7655
7656 TRACE("mostly stub! format='%s' day=%d, wk=%d, flags=%ld\n",
7657 debugstr_w(format), firstDay, firstWeek, dwFlags);
7658 TRACE("varIn:\n");
7659 dump_Variant(varIn);
7660
7661 /* Note: Must Handle references type Variants (contain ptrs
7662 to values rather than values */
7663
7664 /* Get format string */
7665 pNewString = HEAP_strdupWtoA( GetProcessHeap(), 0, format );
7666
7667 /* FIXME: Handle some simple pre-definted format strings : */
7668 if (((V_VT(varIn)&VT_TYPEMASK) == VT_CY) && (lstrcmpiA(pNewString, "Currency") == 0)) {
7669
7670 /* Can't use VarBstrFromCy as it does not put currency sign on nor decimal places */
7671 double curVal;
7672
7673
7674 /* Handle references type Variants (contain ptrs to values rather than values */
7675 if (V_VT(varIn)&VT_BYREF) {
7676 rc = VarR8FromCy(*(CY *)V_UNION(varIn,byref), &curVal);
7677 } else {
7678 rc = VarR8FromCy(V_UNION(varIn,cyVal), &curVal);
7679 }
7680
7681 if (rc == S_OK) {
7682 char tmpStr[BUFFER_MAX];
7683 sprintf(tmpStr, "%f", curVal);
7684 if (GetCurrencyFormatA(GetUserDefaultLCID(), dwFlags, tmpStr, NULL, pBuffer, BUFFER_MAX) == 0) {
7685 return E_FAIL;
7686 } else {
7687 *pbstrOut = StringDupAtoBstr( pBuffer );
7688 }
7689 }
7690
7691 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_DATE) {
7692
7693 /* Attempt to do proper formatting! */
7694 int firstToken = -1;
7695
7696 rc = VarTokenizeFormatString(format, pBuffer, sizeof(pBuffer), firstDay,
7697 firstWeek, GetUserDefaultLCID(), &firstToken);
7698 if (rc==S_OK) {
7699 rc = VarFormatFromTokens(varIn, format, pBuffer, dwFlags, pbstrOut, GetUserDefaultLCID());
7700 }
7701
7702 } else if ((V_VT(varIn)&VT_TYPEMASK) == VT_R8) {
7703 if (V_VT(varIn)&VT_BYREF) {
7704 sprintf(pBuffer, "%f", *(double *)V_UNION(varIn,byref));
7705 } else {
7706 sprintf(pBuffer, "%f", V_UNION(varIn,dblVal));
7707 }
7708
7709 *pbstrOut = StringDupAtoBstr( pBuffer );
7710
7711 } else {
7712 FIXME("VarFormat: Unsupported format %d!\n", V_VT(varIn)&VT_TYPEMASK);
7713 *pbstrOut = StringDupAtoBstr( "??" );
7714 }
7715
7716 /* Free allocated storage */
7717 HeapFree( GetProcessHeap(), 0, pNewString );
7718 TRACE("result: '%s'\n", debugstr_w(*pbstrOut));
7719 return rc;
7720}
7721
7722/**********************************************************************
7723 * VarCyMulI4 [OLEAUT32.304]
7724 * Multiply currency value by integer
7725 */
7726HRESULT WINAPI VarCyMulI4(CY cyIn, LONG mulBy, CY *pcyOut) {
7727
7728 double cyVal = 0;
7729 HRESULT rc = S_OK;
7730
7731 rc = VarR8FromCy(cyIn, &cyVal);
7732 if (rc == S_OK) {
7733 rc = VarCyFromR8((cyVal * (double) mulBy), pcyOut);
7734 TRACE("Multiply %f by %ld = %f [%ld,%lu]\n", cyVal, mulBy, (cyVal * (double) mulBy),
7735 pcyOut->s.Hi, pcyOut->s.Lo);
7736 }
7737 return rc;
7738}
7739
7740
7741/**********************************************************************
7742 * VarDecAdd [OLEAUT32.177]
7743 */
7744HRESULT WINAPI VarDecAdd(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult)
7745{
7746 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7747 return E_NOTIMPL;
7748}
7749
7750/**********************************************************************
7751 * VarDecSub [OLEAUT32.181]
7752 */
7753HRESULT WINAPI VarDecSub(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult)
7754{
7755 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7756 return E_NOTIMPL;
7757}
7758
7759/**********************************************************************
7760 * VarDecMul [OLEAUT32.179]
7761 */
7762HRESULT WINAPI VarDecMul(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult)
7763{
7764 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7765 return E_NOTIMPL;
7766}
7767
7768/**********************************************************************
7769 * VarDecRound [OLEAUT32.203]
7770 */
7771HRESULT WINAPI VarDecRound(LPDECIMAL pdecIn, int iDecimals, LPDECIMAL pdecResult)
7772{
7773 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7774 return E_NOTIMPL;
7775}
7776
7777/**********************************************************************
7778 * VarDecDiv [OLEAUT32.178]
7779 */
7780HRESULT WINAPI VarDecDiv(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult)
7781{
7782 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7783 return E_NOTIMPL;
7784}
7785
7786/**********************************************************************
7787 * VarDecCmp [OLEAUT32.204]
7788 */
7789HRESULT WINAPI VarDecCmp(LPDECIMAL pdecLeft, LPDECIMAL pdecRight)
7790{
7791 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7792 return E_NOTIMPL;
7793}
7794
7795/**********************************************************************
7796 * VarDecAbs [OLEAUT32.182]
7797 */
7798HRESULT WINAPI VarDecAbs(LPDECIMAL pdecIn, LPDECIMAL pdecResult)
7799{
7800 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7801 return E_NOTIMPL;
7802}
7803
7804/**********************************************************************
7805 * VarDecFix [OLEAUT32.187]
7806 */
7807HRESULT WINAPI VarDecFix(LPDECIMAL pdecIn, LPDECIMAL pdecResult)
7808{
7809 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7810 return E_NOTIMPL;
7811}
7812
7813/**********************************************************************
7814 * VarDecInt [OLEAUT32.188]
7815 */
7816HRESULT WINAPI VarDecInt(LPDECIMAL pdecIn, LPDECIMAL pdecResult)
7817{
7818 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7819 return E_NOTIMPL;
7820}
7821
7822
7823/**********************************************************************
7824 * VarDecNeg [OLEAUT32.189]
7825 */
7826HRESULT WINAPI VarDecNeg(LPDECIMAL pdecIn, LPDECIMAL pdecResult)
7827{
7828 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7829 return E_NOTIMPL;
7830}
7831
7832/**********************************************************************
7833 * VarDecCmpR8 [OLEAUT32.298]
7834 */
7835HRESULT WINAPI VarDecCmpR8(LPDECIMAL pdecLeft, LPDECIMAL pdecRight)
7836{
7837 FIXME("%s: Not implemented! (returning E_NOTIMPL)", __FUNCTION__);
7838 return E_NOTIMPL;
7839}
7840
7841/************************************************************************
7842 * VarDecFromStr (OLEAUT32.197)
7843 *
7844 * Convert a VT_BSTR to a DECIMAL.
7845 *
7846 * PARAMS
7847 * strIn [I] Source
7848 * lcid [I] LCID for the conversion
7849 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7850 * pDecOut [O] Destination
7851 *
7852 * RETURNS
7853 * Success: S_OK.
7854 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
7855 */
7856HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
7857{
7858 TRACE("%s: now calling VARIANT_NumberFromBstr\n", __FUNCTION__);
7859 return _VarDecFromStr(strIn, lcid, dwFlags, pDecOut);
7860}
7861
Note: See TracBrowser for help on using the repository browser.