70b1b63dd90f59c6e575f30161c142cc7f43f39b
[reactos.git] / dll / win32 / oleaut32 / vartype.c
1 /*
2 * Low level variant functions
3 *
4 * Copyright 2003 Jon Griffiths
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(variant);
24
25 extern HMODULE hProxyDll DECLSPEC_HIDDEN;
26
27 #define CY_MULTIPLIER 10000 /* 4 dp of precision */
28 #define CY_MULTIPLIER_F 10000.0
29 #define CY_HALF (CY_MULTIPLIER/2) /* 0.5 */
30 #define CY_HALF_F (CY_MULTIPLIER_F/2.0)
31
32 static const WCHAR szFloatFormatW[] = { '%','.','7','G','\0' };
33 static const WCHAR szDoubleFormatW[] = { '%','.','1','5','G','\0' };
34
35 /* Copy data from one variant to another. */
36 static inline void VARIANT_CopyData(const VARIANT *srcVar, VARTYPE vt, void *pOut)
37 {
38 switch (vt)
39 {
40 case VT_I1:
41 case VT_UI1: memcpy(pOut, &V_UI1(srcVar), sizeof(BYTE)); break;
42 case VT_BOOL:
43 case VT_I2:
44 case VT_UI2: memcpy(pOut, &V_UI2(srcVar), sizeof(SHORT)); break;
45 case VT_R4:
46 case VT_INT:
47 case VT_I4:
48 case VT_UINT:
49 case VT_UI4: memcpy(pOut, &V_UI4(srcVar), sizeof (LONG)); break;
50 case VT_R8:
51 case VT_DATE:
52 case VT_CY:
53 case VT_I8:
54 case VT_UI8: memcpy(pOut, &V_UI8(srcVar), sizeof (LONG64)); break;
55 case VT_INT_PTR: memcpy(pOut, &V_INT_PTR(srcVar), sizeof (INT_PTR)); break;
56 case VT_DECIMAL: memcpy(pOut, &V_DECIMAL(srcVar), sizeof (DECIMAL)); break;
57 case VT_BSTR: memcpy(pOut, &V_BSTR(srcVar), sizeof(BSTR)); break;
58 default:
59 FIXME("VT_ type %d unhandled, please report!\n", vt);
60 }
61 }
62
63 /* Macro to inline conversion from a float or double to any integer type,
64 * rounding according to the 'dutch' convention.
65 */
66 #define VARIANT_DutchRound(typ, value, res) do { \
67 double whole = value < 0 ? ceil(value) : floor(value); \
68 double fract = value - whole; \
69 if (fract > 0.5) res = (typ)whole + (typ)1; \
70 else if (fract == 0.5) { typ is_odd = (typ)whole & 1; res = whole + is_odd; } \
71 else if (fract >= 0.0) res = (typ)whole; \
72 else if (fract == -0.5) { typ is_odd = (typ)whole & 1; res = whole - is_odd; } \
73 else if (fract > -0.5) res = (typ)whole; \
74 else res = (typ)whole - (typ)1; \
75 } while(0)
76
77
78 /* Coerce VT_BSTR to a numeric type */
79 static HRESULT VARIANT_NumberFromBstr(OLECHAR* pStrIn, LCID lcid, ULONG ulFlags,
80 void* pOut, VARTYPE vt)
81 {
82 VARIANTARG dstVar;
83 HRESULT hRet;
84 NUMPARSE np;
85 BYTE rgb[1024];
86
87 /* Use VarParseNumFromStr/VarNumFromParseNum as MSDN indicates */
88 np.cDig = sizeof(rgb) / sizeof(BYTE);
89 np.dwInFlags = NUMPRS_STD;
90
91 hRet = VarParseNumFromStr(pStrIn, lcid, ulFlags, &np, rgb);
92
93 if (SUCCEEDED(hRet))
94 {
95 /* 1 << vt gives us the VTBIT constant for the destination number type */
96 hRet = VarNumFromParseNum(&np, rgb, 1 << vt, &dstVar);
97 if (SUCCEEDED(hRet))
98 VARIANT_CopyData(&dstVar, vt, pOut);
99 }
100 return hRet;
101 }
102
103 /* Coerce VT_DISPATCH to another type */
104 static HRESULT VARIANT_FromDisp(IDispatch* pdispIn, LCID lcid, void* pOut,
105 VARTYPE vt, DWORD dwFlags)
106 {
107 static DISPPARAMS emptyParams = { NULL, NULL, 0, 0 };
108 VARIANTARG srcVar, dstVar;
109 HRESULT hRet;
110
111 if (!pdispIn)
112 return DISP_E_BADVARTYPE;
113
114 /* Get the default 'value' property from the IDispatch */
115 VariantInit(&srcVar);
116 hRet = IDispatch_Invoke(pdispIn, DISPID_VALUE, &IID_NULL, lcid, DISPATCH_PROPERTYGET,
117 &emptyParams, &srcVar, NULL, NULL);
118
119 if (SUCCEEDED(hRet))
120 {
121 /* Convert the property to the requested type */
122 VariantInit(&dstVar);
123 hRet = VariantChangeTypeEx(&dstVar, &srcVar, lcid, dwFlags, vt);
124 VariantClear(&srcVar);
125
126 if (SUCCEEDED(hRet))
127 VARIANT_CopyData(&dstVar, vt, pOut);
128 }
129 else
130 hRet = DISP_E_TYPEMISMATCH;
131 return hRet;
132 }
133
134 /* Inline return type */
135 #define RETTYP static inline HRESULT
136
137
138 /* Simple compiler cast from one type to another */
139 #define SIMPLE(dest, src, func) RETTYP _##func(src in, dest* out) { \
140 *out = in; return S_OK; }
141
142 /* Compiler cast where input cannot be negative */
143 #define NEGTST(dest, src, func) RETTYP _##func(src in, dest* out) { \
144 if (in < 0) return DISP_E_OVERFLOW; *out = in; return S_OK; }
145
146 /* Compiler cast where input cannot be > some number */
147 #define POSTST(dest, src, func, tst) RETTYP _##func(src in, dest* out) { \
148 if (in > (dest)tst) return DISP_E_OVERFLOW; *out = in; return S_OK; }
149
150 /* Compiler cast where input cannot be < some number or >= some other number */
151 #define BOTHTST(dest, src, func, lo, hi) RETTYP _##func(src in, dest* out) { \
152 if (in < (dest)lo || in > hi) return DISP_E_OVERFLOW; *out = in; return S_OK; }
153
154 /* I1 */
155 POSTST(signed char, BYTE, VarI1FromUI1, I1_MAX)
156 BOTHTST(signed char, SHORT, VarI1FromI2, I1_MIN, I1_MAX)
157 BOTHTST(signed char, LONG, VarI1FromI4, I1_MIN, I1_MAX)
158 SIMPLE(signed char, VARIANT_BOOL, VarI1FromBool)
159 POSTST(signed char, USHORT, VarI1FromUI2, I1_MAX)
160 POSTST(signed char, ULONG, VarI1FromUI4, I1_MAX)
161 BOTHTST(signed char, LONG64, VarI1FromI8, I1_MIN, I1_MAX)
162 POSTST(signed char, ULONG64, VarI1FromUI8, I1_MAX)
163
164 /* UI1 */
165 BOTHTST(BYTE, SHORT, VarUI1FromI2, UI1_MIN, UI1_MAX)
166 SIMPLE(BYTE, VARIANT_BOOL, VarUI1FromBool)
167 NEGTST(BYTE, signed char, VarUI1FromI1)
168 POSTST(BYTE, USHORT, VarUI1FromUI2, UI1_MAX)
169 BOTHTST(BYTE, LONG, VarUI1FromI4, UI1_MIN, UI1_MAX)
170 POSTST(BYTE, ULONG, VarUI1FromUI4, UI1_MAX)
171 BOTHTST(BYTE, LONG64, VarUI1FromI8, UI1_MIN, UI1_MAX)
172 POSTST(BYTE, ULONG64, VarUI1FromUI8, UI1_MAX)
173
174 /* I2 */
175 SIMPLE(SHORT, BYTE, VarI2FromUI1)
176 BOTHTST(SHORT, LONG, VarI2FromI4, I2_MIN, I2_MAX)
177 SIMPLE(SHORT, VARIANT_BOOL, VarI2FromBool)
178 SIMPLE(SHORT, signed char, VarI2FromI1)
179 POSTST(SHORT, USHORT, VarI2FromUI2, I2_MAX)
180 POSTST(SHORT, ULONG, VarI2FromUI4, I2_MAX)
181 BOTHTST(SHORT, LONG64, VarI2FromI8, I2_MIN, I2_MAX)
182 POSTST(SHORT, ULONG64, VarI2FromUI8, I2_MAX)
183
184 /* UI2 */
185 SIMPLE(USHORT, BYTE, VarUI2FromUI1)
186 NEGTST(USHORT, SHORT, VarUI2FromI2)
187 BOTHTST(USHORT, LONG, VarUI2FromI4, UI2_MIN, UI2_MAX)
188 SIMPLE(USHORT, VARIANT_BOOL, VarUI2FromBool)
189 NEGTST(USHORT, signed char, VarUI2FromI1)
190 POSTST(USHORT, ULONG, VarUI2FromUI4, UI2_MAX)
191 BOTHTST(USHORT, LONG64, VarUI2FromI8, UI2_MIN, UI2_MAX)
192 POSTST(USHORT, ULONG64, VarUI2FromUI8, UI2_MAX)
193
194 /* I4 */
195 SIMPLE(LONG, BYTE, VarI4FromUI1)
196 SIMPLE(LONG, SHORT, VarI4FromI2)
197 SIMPLE(LONG, VARIANT_BOOL, VarI4FromBool)
198 SIMPLE(LONG, signed char, VarI4FromI1)
199 SIMPLE(LONG, USHORT, VarI4FromUI2)
200 POSTST(LONG, ULONG, VarI4FromUI4, I4_MAX)
201 BOTHTST(LONG, LONG64, VarI4FromI8, I4_MIN, I4_MAX)
202 POSTST(LONG, ULONG64, VarI4FromUI8, I4_MAX)
203
204 /* UI4 */
205 SIMPLE(ULONG, BYTE, VarUI4FromUI1)
206 NEGTST(ULONG, SHORT, VarUI4FromI2)
207 NEGTST(ULONG, LONG, VarUI4FromI4)
208 SIMPLE(ULONG, VARIANT_BOOL, VarUI4FromBool)
209 NEGTST(ULONG, signed char, VarUI4FromI1)
210 SIMPLE(ULONG, USHORT, VarUI4FromUI2)
211 BOTHTST(ULONG, LONG64, VarUI4FromI8, UI4_MIN, UI4_MAX)
212 POSTST(ULONG, ULONG64, VarUI4FromUI8, UI4_MAX)
213
214 /* I8 */
215 SIMPLE(LONG64, BYTE, VarI8FromUI1)
216 SIMPLE(LONG64, SHORT, VarI8FromI2)
217 SIMPLE(LONG64, signed char, VarI8FromI1)
218 SIMPLE(LONG64, USHORT, VarI8FromUI2)
219 SIMPLE(LONG64, ULONG, VarI8FromUI4)
220 POSTST(LONG64, ULONG64, VarI8FromUI8, I8_MAX)
221
222 /* UI8 */
223 SIMPLE(ULONG64, BYTE, VarUI8FromUI1)
224 NEGTST(ULONG64, SHORT, VarUI8FromI2)
225 NEGTST(ULONG64, signed char, VarUI8FromI1)
226 SIMPLE(ULONG64, USHORT, VarUI8FromUI2)
227 SIMPLE(ULONG64, ULONG, VarUI8FromUI4)
228 NEGTST(ULONG64, LONG64, VarUI8FromI8)
229
230 /* R4 (float) */
231 SIMPLE(float, BYTE, VarR4FromUI1)
232 SIMPLE(float, SHORT, VarR4FromI2)
233 SIMPLE(float, signed char, VarR4FromI1)
234 SIMPLE(float, USHORT, VarR4FromUI2)
235 SIMPLE(float, LONG, VarR4FromI4)
236 SIMPLE(float, ULONG, VarR4FromUI4)
237 SIMPLE(float, LONG64, VarR4FromI8)
238 SIMPLE(float, ULONG64, VarR4FromUI8)
239
240 /* R8 (double) */
241 SIMPLE(double, BYTE, VarR8FromUI1)
242 SIMPLE(double, SHORT, VarR8FromI2)
243 SIMPLE(double, float, VarR8FromR4)
244 RETTYP _VarR8FromCy(CY i, double* o) { *o = (double)i.int64 / CY_MULTIPLIER_F; return S_OK; }
245 SIMPLE(double, DATE, VarR8FromDate)
246 SIMPLE(double, signed char, VarR8FromI1)
247 SIMPLE(double, USHORT, VarR8FromUI2)
248 SIMPLE(double, LONG, VarR8FromI4)
249 SIMPLE(double, ULONG, VarR8FromUI4)
250 SIMPLE(double, LONG64, VarR8FromI8)
251 SIMPLE(double, ULONG64, VarR8FromUI8)
252
253
254 /* I1
255 */
256
257 /************************************************************************
258 * VarI1FromUI1 (OLEAUT32.244)
259 *
260 * Convert a VT_UI1 to a VT_I1.
261 *
262 * PARAMS
263 * bIn [I] Source
264 * pcOut [O] Destination
265 *
266 * RETURNS
267 * Success: S_OK.
268 * Failure: E_INVALIDARG, if the source value is invalid
269 * DISP_E_OVERFLOW, if the value will not fit in the destination
270 */
271 HRESULT WINAPI VarI1FromUI1(BYTE bIn, signed char* pcOut)
272 {
273 return _VarI1FromUI1(bIn, pcOut);
274 }
275
276 /************************************************************************
277 * VarI1FromI2 (OLEAUT32.245)
278 *
279 * Convert a VT_I2 to a VT_I1.
280 *
281 * PARAMS
282 * sIn [I] Source
283 * pcOut [O] Destination
284 *
285 * RETURNS
286 * Success: S_OK.
287 * Failure: E_INVALIDARG, if the source value is invalid
288 * DISP_E_OVERFLOW, if the value will not fit in the destination
289 */
290 HRESULT WINAPI VarI1FromI2(SHORT sIn, signed char* pcOut)
291 {
292 return _VarI1FromI2(sIn, pcOut);
293 }
294
295 /************************************************************************
296 * VarI1FromI4 (OLEAUT32.246)
297 *
298 * Convert a VT_I4 to a VT_I1.
299 *
300 * PARAMS
301 * iIn [I] Source
302 * pcOut [O] Destination
303 *
304 * RETURNS
305 * Success: S_OK.
306 * Failure: E_INVALIDARG, if the source value is invalid
307 * DISP_E_OVERFLOW, if the value will not fit in the destination
308 */
309 HRESULT WINAPI VarI1FromI4(LONG iIn, signed char* pcOut)
310 {
311 return _VarI1FromI4(iIn, pcOut);
312 }
313
314 /************************************************************************
315 * VarI1FromR4 (OLEAUT32.247)
316 *
317 * Convert a VT_R4 to a VT_I1.
318 *
319 * PARAMS
320 * fltIn [I] Source
321 * pcOut [O] Destination
322 *
323 * RETURNS
324 * Success: S_OK.
325 * Failure: E_INVALIDARG, if the source value is invalid
326 * DISP_E_OVERFLOW, if the value will not fit in the destination
327 */
328 HRESULT WINAPI VarI1FromR4(FLOAT fltIn, signed char* pcOut)
329 {
330 return VarI1FromR8(fltIn, pcOut);
331 }
332
333 /************************************************************************
334 * VarI1FromR8 (OLEAUT32.248)
335 *
336 * Convert a VT_R8 to a VT_I1.
337 *
338 * PARAMS
339 * dblIn [I] Source
340 * pcOut [O] Destination
341 *
342 * RETURNS
343 * Success: S_OK.
344 * Failure: E_INVALIDARG, if the source value is invalid
345 * DISP_E_OVERFLOW, if the value will not fit in the destination
346 *
347 * NOTES
348 * See VarI8FromR8() for details concerning rounding.
349 */
350 HRESULT WINAPI VarI1FromR8(double dblIn, signed char* pcOut)
351 {
352 if (dblIn < I1_MIN - 0.5 || dblIn >= I1_MAX + 0.5)
353 return DISP_E_OVERFLOW;
354 VARIANT_DutchRound(CHAR, dblIn, *pcOut);
355 return S_OK;
356 }
357
358 /************************************************************************
359 * VarI1FromDate (OLEAUT32.249)
360 *
361 * Convert a VT_DATE to a VT_I1.
362 *
363 * PARAMS
364 * dateIn [I] Source
365 * pcOut [O] Destination
366 *
367 * RETURNS
368 * Success: S_OK.
369 * Failure: E_INVALIDARG, if the source value is invalid
370 * DISP_E_OVERFLOW, if the value will not fit in the destination
371 */
372 HRESULT WINAPI VarI1FromDate(DATE dateIn, signed char* pcOut)
373 {
374 return VarI1FromR8(dateIn, pcOut);
375 }
376
377 /************************************************************************
378 * VarI1FromCy (OLEAUT32.250)
379 *
380 * Convert a VT_CY to a VT_I1.
381 *
382 * PARAMS
383 * cyIn [I] Source
384 * pcOut [O] Destination
385 *
386 * RETURNS
387 * Success: S_OK.
388 * Failure: E_INVALIDARG, if the source value is invalid
389 * DISP_E_OVERFLOW, if the value will not fit in the destination
390 */
391 HRESULT WINAPI VarI1FromCy(CY cyIn, signed char* pcOut)
392 {
393 LONG i = I1_MAX + 1;
394
395 VarI4FromCy(cyIn, &i);
396 return _VarI1FromI4(i, pcOut);
397 }
398
399 /************************************************************************
400 * VarI1FromStr (OLEAUT32.251)
401 *
402 * Convert a VT_BSTR to a VT_I1.
403 *
404 * PARAMS
405 * strIn [I] Source
406 * lcid [I] LCID for the conversion
407 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
408 * pcOut [O] Destination
409 *
410 * RETURNS
411 * Success: S_OK.
412 * Failure: E_INVALIDARG, if the source value is invalid
413 * DISP_E_OVERFLOW, if the value will not fit in the destination
414 * DISP_E_TYPEMISMATCH, if the type cannot be converted
415 */
416 HRESULT WINAPI VarI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, signed char* pcOut)
417 {
418 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pcOut, VT_I1);
419 }
420
421 /************************************************************************
422 * VarI1FromDisp (OLEAUT32.252)
423 *
424 * Convert a VT_DISPATCH to a VT_I1.
425 *
426 * PARAMS
427 * pdispIn [I] Source
428 * lcid [I] LCID for conversion
429 * pcOut [O] Destination
430 *
431 * RETURNS
432 * Success: S_OK.
433 * Failure: E_INVALIDARG, if the source value is invalid
434 * DISP_E_OVERFLOW, if the value will not fit in the destination
435 * DISP_E_TYPEMISMATCH, if the type cannot be converted
436 */
437 HRESULT WINAPI VarI1FromDisp(IDispatch* pdispIn, LCID lcid, signed char* pcOut)
438 {
439 return VARIANT_FromDisp(pdispIn, lcid, pcOut, VT_I1, 0);
440 }
441
442 /************************************************************************
443 * VarI1FromBool (OLEAUT32.253)
444 *
445 * Convert a VT_BOOL to a VT_I1.
446 *
447 * PARAMS
448 * boolIn [I] Source
449 * pcOut [O] Destination
450 *
451 * RETURNS
452 * S_OK.
453 */
454 HRESULT WINAPI VarI1FromBool(VARIANT_BOOL boolIn, signed char* pcOut)
455 {
456 return _VarI1FromBool(boolIn, pcOut);
457 }
458
459 /************************************************************************
460 * VarI1FromUI2 (OLEAUT32.254)
461 *
462 * Convert a VT_UI2 to a VT_I1.
463 *
464 * PARAMS
465 * usIn [I] Source
466 * pcOut [O] Destination
467 *
468 * RETURNS
469 * Success: S_OK.
470 * Failure: E_INVALIDARG, if the source value is invalid
471 * DISP_E_OVERFLOW, if the value will not fit in the destination
472 */
473 HRESULT WINAPI VarI1FromUI2(USHORT usIn, signed char* pcOut)
474 {
475 return _VarI1FromUI2(usIn, pcOut);
476 }
477
478 /************************************************************************
479 * VarI1FromUI4 (OLEAUT32.255)
480 *
481 * Convert a VT_UI4 to a VT_I1.
482 *
483 * PARAMS
484 * ulIn [I] Source
485 * pcOut [O] Destination
486 *
487 * RETURNS
488 * Success: S_OK.
489 * Failure: E_INVALIDARG, if the source value is invalid
490 * DISP_E_OVERFLOW, if the value will not fit in the destination
491 * DISP_E_TYPEMISMATCH, if the type cannot be converted
492 */
493 HRESULT WINAPI VarI1FromUI4(ULONG ulIn, signed char* pcOut)
494 {
495 return _VarI1FromUI4(ulIn, pcOut);
496 }
497
498 /************************************************************************
499 * VarI1FromDec (OLEAUT32.256)
500 *
501 * Convert a VT_DECIMAL to a VT_I1.
502 *
503 * PARAMS
504 * pDecIn [I] Source
505 * pcOut [O] Destination
506 *
507 * RETURNS
508 * Success: S_OK.
509 * Failure: E_INVALIDARG, if the source value is invalid
510 * DISP_E_OVERFLOW, if the value will not fit in the destination
511 */
512 HRESULT WINAPI VarI1FromDec(DECIMAL *pdecIn, signed char* pcOut)
513 {
514 LONG64 i64;
515 HRESULT hRet;
516
517 hRet = VarI8FromDec(pdecIn, &i64);
518
519 if (SUCCEEDED(hRet))
520 hRet = _VarI1FromI8(i64, pcOut);
521 return hRet;
522 }
523
524 /************************************************************************
525 * VarI1FromI8 (OLEAUT32.376)
526 *
527 * Convert a VT_I8 to a VT_I1.
528 *
529 * PARAMS
530 * llIn [I] Source
531 * pcOut [O] Destination
532 *
533 * RETURNS
534 * Success: S_OK.
535 * Failure: E_INVALIDARG, if the source value is invalid
536 * DISP_E_OVERFLOW, if the value will not fit in the destination
537 */
538 HRESULT WINAPI VarI1FromI8(LONG64 llIn, signed char* pcOut)
539 {
540 return _VarI1FromI8(llIn, pcOut);
541 }
542
543 /************************************************************************
544 * VarI1FromUI8 (OLEAUT32.377)
545 *
546 * Convert a VT_UI8 to a VT_I1.
547 *
548 * PARAMS
549 * ullIn [I] Source
550 * pcOut [O] Destination
551 *
552 * RETURNS
553 * Success: S_OK.
554 * Failure: E_INVALIDARG, if the source value is invalid
555 * DISP_E_OVERFLOW, if the value will not fit in the destination
556 */
557 HRESULT WINAPI VarI1FromUI8(ULONG64 ullIn, signed char* pcOut)
558 {
559 return _VarI1FromUI8(ullIn, pcOut);
560 }
561
562 /* UI1
563 */
564
565 /************************************************************************
566 * VarUI1FromI2 (OLEAUT32.130)
567 *
568 * Convert a VT_I2 to a VT_UI1.
569 *
570 * PARAMS
571 * sIn [I] Source
572 * pbOut [O] Destination
573 *
574 * RETURNS
575 * Success: S_OK.
576 * Failure: E_INVALIDARG, if the source value is invalid
577 * DISP_E_OVERFLOW, if the value will not fit in the destination
578 */
579 HRESULT WINAPI VarUI1FromI2(SHORT sIn, BYTE* pbOut)
580 {
581 return _VarUI1FromI2(sIn, pbOut);
582 }
583
584 /************************************************************************
585 * VarUI1FromI4 (OLEAUT32.131)
586 *
587 * Convert a VT_I4 to a VT_UI1.
588 *
589 * PARAMS
590 * iIn [I] Source
591 * pbOut [O] Destination
592 *
593 * RETURNS
594 * Success: S_OK.
595 * Failure: E_INVALIDARG, if the source value is invalid
596 * DISP_E_OVERFLOW, if the value will not fit in the destination
597 */
598 HRESULT WINAPI VarUI1FromI4(LONG iIn, BYTE* pbOut)
599 {
600 return _VarUI1FromI4(iIn, pbOut);
601 }
602
603 /************************************************************************
604 * VarUI1FromR4 (OLEAUT32.132)
605 *
606 * Convert a VT_R4 to a VT_UI1.
607 *
608 * PARAMS
609 * fltIn [I] Source
610 * pbOut [O] Destination
611 *
612 * RETURNS
613 * Success: S_OK.
614 * Failure: E_INVALIDARG, if the source value is invalid
615 * DISP_E_OVERFLOW, if the value will not fit in the destination
616 * DISP_E_TYPEMISMATCH, if the type cannot be converted
617 */
618 HRESULT WINAPI VarUI1FromR4(FLOAT fltIn, BYTE* pbOut)
619 {
620 return VarUI1FromR8(fltIn, pbOut);
621 }
622
623 /************************************************************************
624 * VarUI1FromR8 (OLEAUT32.133)
625 *
626 * Convert a VT_R8 to a VT_UI1.
627 *
628 * PARAMS
629 * dblIn [I] Source
630 * pbOut [O] Destination
631 *
632 * RETURNS
633 * Success: S_OK.
634 * Failure: E_INVALIDARG, if the source value is invalid
635 * DISP_E_OVERFLOW, if the value will not fit in the destination
636 *
637 * NOTES
638 * See VarI8FromR8() for details concerning rounding.
639 */
640 HRESULT WINAPI VarUI1FromR8(double dblIn, BYTE* pbOut)
641 {
642 if (dblIn < -0.5 || dblIn >= UI1_MAX + 0.5)
643 return DISP_E_OVERFLOW;
644 VARIANT_DutchRound(BYTE, dblIn, *pbOut);
645 return S_OK;
646 }
647
648 /************************************************************************
649 * VarUI1FromCy (OLEAUT32.134)
650 *
651 * Convert a VT_CY to a VT_UI1.
652 *
653 * PARAMS
654 * cyIn [I] Source
655 * pbOut [O] Destination
656 *
657 * RETURNS
658 * Success: S_OK.
659 * Failure: E_INVALIDARG, if the source value is invalid
660 * DISP_E_OVERFLOW, if the value will not fit in the destination
661 *
662 * NOTES
663 * Negative values >= -5000 will be converted to 0.
664 */
665 HRESULT WINAPI VarUI1FromCy(CY cyIn, BYTE* pbOut)
666 {
667 ULONG i = UI1_MAX + 1;
668
669 VarUI4FromCy(cyIn, &i);
670 return _VarUI1FromUI4(i, pbOut);
671 }
672
673 /************************************************************************
674 * VarUI1FromDate (OLEAUT32.135)
675 *
676 * Convert a VT_DATE to a VT_UI1.
677 *
678 * PARAMS
679 * dateIn [I] Source
680 * pbOut [O] Destination
681 *
682 * RETURNS
683 * Success: S_OK.
684 * Failure: E_INVALIDARG, if the source value is invalid
685 * DISP_E_OVERFLOW, if the value will not fit in the destination
686 */
687 HRESULT WINAPI VarUI1FromDate(DATE dateIn, BYTE* pbOut)
688 {
689 return VarUI1FromR8(dateIn, pbOut);
690 }
691
692 /************************************************************************
693 * VarUI1FromStr (OLEAUT32.136)
694 *
695 * Convert a VT_BSTR to a VT_UI1.
696 *
697 * PARAMS
698 * strIn [I] Source
699 * lcid [I] LCID for the conversion
700 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
701 * pbOut [O] Destination
702 *
703 * RETURNS
704 * Success: S_OK.
705 * Failure: E_INVALIDARG, if the source value is invalid
706 * DISP_E_OVERFLOW, if the value will not fit in the destination
707 * DISP_E_TYPEMISMATCH, if the type cannot be converted
708 */
709 HRESULT WINAPI VarUI1FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, BYTE* pbOut)
710 {
711 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pbOut, VT_UI1);
712 }
713
714 /************************************************************************
715 * VarUI1FromDisp (OLEAUT32.137)
716 *
717 * Convert a VT_DISPATCH to a VT_UI1.
718 *
719 * PARAMS
720 * pdispIn [I] Source
721 * lcid [I] LCID for conversion
722 * pbOut [O] Destination
723 *
724 * RETURNS
725 * Success: S_OK.
726 * Failure: E_INVALIDARG, if the source value is invalid
727 * DISP_E_OVERFLOW, if the value will not fit in the destination
728 * DISP_E_TYPEMISMATCH, if the type cannot be converted
729 */
730 HRESULT WINAPI VarUI1FromDisp(IDispatch* pdispIn, LCID lcid, BYTE* pbOut)
731 {
732 return VARIANT_FromDisp(pdispIn, lcid, pbOut, VT_UI1, 0);
733 }
734
735 /************************************************************************
736 * VarUI1FromBool (OLEAUT32.138)
737 *
738 * Convert a VT_BOOL to a VT_UI1.
739 *
740 * PARAMS
741 * boolIn [I] Source
742 * pbOut [O] Destination
743 *
744 * RETURNS
745 * S_OK.
746 */
747 HRESULT WINAPI VarUI1FromBool(VARIANT_BOOL boolIn, BYTE* pbOut)
748 {
749 return _VarUI1FromBool(boolIn, pbOut);
750 }
751
752 /************************************************************************
753 * VarUI1FromI1 (OLEAUT32.237)
754 *
755 * Convert a VT_I1 to a VT_UI1.
756 *
757 * PARAMS
758 * cIn [I] Source
759 * pbOut [O] Destination
760 *
761 * RETURNS
762 * Success: S_OK.
763 * Failure: E_INVALIDARG, if the source value is invalid
764 * DISP_E_OVERFLOW, if the value will not fit in the destination
765 */
766 HRESULT WINAPI VarUI1FromI1(signed char cIn, BYTE* pbOut)
767 {
768 return _VarUI1FromI1(cIn, pbOut);
769 }
770
771 /************************************************************************
772 * VarUI1FromUI2 (OLEAUT32.238)
773 *
774 * Convert a VT_UI2 to a VT_UI1.
775 *
776 * PARAMS
777 * usIn [I] Source
778 * pbOut [O] Destination
779 *
780 * RETURNS
781 * Success: S_OK.
782 * Failure: E_INVALIDARG, if the source value is invalid
783 * DISP_E_OVERFLOW, if the value will not fit in the destination
784 */
785 HRESULT WINAPI VarUI1FromUI2(USHORT usIn, BYTE* pbOut)
786 {
787 return _VarUI1FromUI2(usIn, pbOut);
788 }
789
790 /************************************************************************
791 * VarUI1FromUI4 (OLEAUT32.239)
792 *
793 * Convert a VT_UI4 to a VT_UI1.
794 *
795 * PARAMS
796 * ulIn [I] Source
797 * pbOut [O] Destination
798 *
799 * RETURNS
800 * Success: S_OK.
801 * Failure: E_INVALIDARG, if the source value is invalid
802 * DISP_E_OVERFLOW, if the value will not fit in the destination
803 */
804 HRESULT WINAPI VarUI1FromUI4(ULONG ulIn, BYTE* pbOut)
805 {
806 return _VarUI1FromUI4(ulIn, pbOut);
807 }
808
809 /************************************************************************
810 * VarUI1FromDec (OLEAUT32.240)
811 *
812 * Convert a VT_DECIMAL to a VT_UI1.
813 *
814 * PARAMS
815 * pDecIn [I] Source
816 * pbOut [O] Destination
817 *
818 * RETURNS
819 * Success: S_OK.
820 * Failure: E_INVALIDARG, if the source value is invalid
821 * DISP_E_OVERFLOW, if the value will not fit in the destination
822 */
823 HRESULT WINAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE* pbOut)
824 {
825 LONG64 i64;
826 HRESULT hRet;
827
828 hRet = VarI8FromDec(pdecIn, &i64);
829
830 if (SUCCEEDED(hRet))
831 hRet = _VarUI1FromI8(i64, pbOut);
832 return hRet;
833 }
834
835 /************************************************************************
836 * VarUI1FromI8 (OLEAUT32.372)
837 *
838 * Convert a VT_I8 to a VT_UI1.
839 *
840 * PARAMS
841 * llIn [I] Source
842 * pbOut [O] Destination
843 *
844 * RETURNS
845 * Success: S_OK.
846 * Failure: E_INVALIDARG, if the source value is invalid
847 * DISP_E_OVERFLOW, if the value will not fit in the destination
848 */
849 HRESULT WINAPI VarUI1FromI8(LONG64 llIn, BYTE* pbOut)
850 {
851 return _VarUI1FromI8(llIn, pbOut);
852 }
853
854 /************************************************************************
855 * VarUI1FromUI8 (OLEAUT32.373)
856 *
857 * Convert a VT_UI8 to a VT_UI1.
858 *
859 * PARAMS
860 * ullIn [I] Source
861 * pbOut [O] Destination
862 *
863 * RETURNS
864 * Success: S_OK.
865 * Failure: E_INVALIDARG, if the source value is invalid
866 * DISP_E_OVERFLOW, if the value will not fit in the destination
867 */
868 HRESULT WINAPI VarUI1FromUI8(ULONG64 ullIn, BYTE* pbOut)
869 {
870 return _VarUI1FromUI8(ullIn, pbOut);
871 }
872
873
874 /* I2
875 */
876
877 /************************************************************************
878 * VarI2FromUI1 (OLEAUT32.48)
879 *
880 * Convert a VT_UI2 to a VT_I2.
881 *
882 * PARAMS
883 * bIn [I] Source
884 * psOut [O] Destination
885 *
886 * RETURNS
887 * S_OK.
888 */
889 HRESULT WINAPI VarI2FromUI1(BYTE bIn, SHORT* psOut)
890 {
891 return _VarI2FromUI1(bIn, psOut);
892 }
893
894 /************************************************************************
895 * VarI2FromI4 (OLEAUT32.49)
896 *
897 * Convert a VT_I4 to a VT_I2.
898 *
899 * PARAMS
900 * iIn [I] Source
901 * psOut [O] Destination
902 *
903 * RETURNS
904 * Success: S_OK.
905 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
906 */
907 HRESULT WINAPI VarI2FromI4(LONG iIn, SHORT* psOut)
908 {
909 return _VarI2FromI4(iIn, psOut);
910 }
911
912 /************************************************************************
913 * VarI2FromR4 (OLEAUT32.50)
914 *
915 * Convert a VT_R4 to a VT_I2.
916 *
917 * PARAMS
918 * fltIn [I] Source
919 * psOut [O] Destination
920 *
921 * RETURNS
922 * Success: S_OK.
923 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
924 */
925 HRESULT WINAPI VarI2FromR4(FLOAT fltIn, SHORT* psOut)
926 {
927 return VarI2FromR8(fltIn, psOut);
928 }
929
930 /************************************************************************
931 * VarI2FromR8 (OLEAUT32.51)
932 *
933 * Convert a VT_R8 to a VT_I2.
934 *
935 * PARAMS
936 * dblIn [I] Source
937 * psOut [O] Destination
938 *
939 * RETURNS
940 * Success: S_OK.
941 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
942 *
943 * NOTES
944 * See VarI8FromR8() for details concerning rounding.
945 */
946 HRESULT WINAPI VarI2FromR8(double dblIn, SHORT* psOut)
947 {
948 if (dblIn < I2_MIN - 0.5 || dblIn >= I2_MAX + 0.5)
949 return DISP_E_OVERFLOW;
950 VARIANT_DutchRound(SHORT, dblIn, *psOut);
951 return S_OK;
952 }
953
954 /************************************************************************
955 * VarI2FromCy (OLEAUT32.52)
956 *
957 * Convert a VT_CY to a VT_I2.
958 *
959 * PARAMS
960 * cyIn [I] Source
961 * psOut [O] Destination
962 *
963 * RETURNS
964 * Success: S_OK.
965 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
966 */
967 HRESULT WINAPI VarI2FromCy(CY cyIn, SHORT* psOut)
968 {
969 LONG i = I2_MAX + 1;
970
971 VarI4FromCy(cyIn, &i);
972 return _VarI2FromI4(i, psOut);
973 }
974
975 /************************************************************************
976 * VarI2FromDate (OLEAUT32.53)
977 *
978 * Convert a VT_DATE to a VT_I2.
979 *
980 * PARAMS
981 * dateIn [I] Source
982 * psOut [O] Destination
983 *
984 * RETURNS
985 * Success: S_OK.
986 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
987 */
988 HRESULT WINAPI VarI2FromDate(DATE dateIn, SHORT* psOut)
989 {
990 return VarI2FromR8(dateIn, psOut);
991 }
992
993 /************************************************************************
994 * VarI2FromStr (OLEAUT32.54)
995 *
996 * Convert a VT_BSTR to a VT_I2.
997 *
998 * PARAMS
999 * strIn [I] Source
1000 * lcid [I] LCID for the conversion
1001 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1002 * psOut [O] Destination
1003 *
1004 * RETURNS
1005 * Success: S_OK.
1006 * Failure: E_INVALIDARG, if any parameter is invalid
1007 * DISP_E_OVERFLOW, if the value will not fit in the destination
1008 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1009 */
1010 HRESULT WINAPI VarI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, SHORT* psOut)
1011 {
1012 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, psOut, VT_I2);
1013 }
1014
1015 /************************************************************************
1016 * VarI2FromDisp (OLEAUT32.55)
1017 *
1018 * Convert a VT_DISPATCH to a VT_I2.
1019 *
1020 * PARAMS
1021 * pdispIn [I] Source
1022 * lcid [I] LCID for conversion
1023 * psOut [O] Destination
1024 *
1025 * RETURNS
1026 * Success: S_OK.
1027 * Failure: E_INVALIDARG, if pdispIn is invalid,
1028 * DISP_E_OVERFLOW, if the value will not fit in the destination,
1029 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1030 */
1031 HRESULT WINAPI VarI2FromDisp(IDispatch* pdispIn, LCID lcid, SHORT* psOut)
1032 {
1033 return VARIANT_FromDisp(pdispIn, lcid, psOut, VT_I2, 0);
1034 }
1035
1036 /************************************************************************
1037 * VarI2FromBool (OLEAUT32.56)
1038 *
1039 * Convert a VT_BOOL to a VT_I2.
1040 *
1041 * PARAMS
1042 * boolIn [I] Source
1043 * psOut [O] Destination
1044 *
1045 * RETURNS
1046 * S_OK.
1047 */
1048 HRESULT WINAPI VarI2FromBool(VARIANT_BOOL boolIn, SHORT* psOut)
1049 {
1050 return _VarI2FromBool(boolIn, psOut);
1051 }
1052
1053 /************************************************************************
1054 * VarI2FromI1 (OLEAUT32.205)
1055 *
1056 * Convert a VT_I1 to a VT_I2.
1057 *
1058 * PARAMS
1059 * cIn [I] Source
1060 * psOut [O] Destination
1061 *
1062 * RETURNS
1063 * S_OK.
1064 */
1065 HRESULT WINAPI VarI2FromI1(signed char cIn, SHORT* psOut)
1066 {
1067 return _VarI2FromI1(cIn, psOut);
1068 }
1069
1070 /************************************************************************
1071 * VarI2FromUI2 (OLEAUT32.206)
1072 *
1073 * Convert a VT_UI2 to a VT_I2.
1074 *
1075 * PARAMS
1076 * usIn [I] Source
1077 * psOut [O] Destination
1078 *
1079 * RETURNS
1080 * Success: S_OK.
1081 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1082 */
1083 HRESULT WINAPI VarI2FromUI2(USHORT usIn, SHORT* psOut)
1084 {
1085 return _VarI2FromUI2(usIn, psOut);
1086 }
1087
1088 /************************************************************************
1089 * VarI2FromUI4 (OLEAUT32.207)
1090 *
1091 * Convert a VT_UI4 to a VT_I2.
1092 *
1093 * PARAMS
1094 * ulIn [I] Source
1095 * psOut [O] Destination
1096 *
1097 * RETURNS
1098 * Success: S_OK.
1099 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1100 */
1101 HRESULT WINAPI VarI2FromUI4(ULONG ulIn, SHORT* psOut)
1102 {
1103 return _VarI2FromUI4(ulIn, psOut);
1104 }
1105
1106 /************************************************************************
1107 * VarI2FromDec (OLEAUT32.208)
1108 *
1109 * Convert a VT_DECIMAL to a VT_I2.
1110 *
1111 * PARAMS
1112 * pDecIn [I] Source
1113 * psOut [O] Destination
1114 *
1115 * RETURNS
1116 * Success: S_OK.
1117 * Failure: E_INVALIDARG, if the source value is invalid
1118 * DISP_E_OVERFLOW, if the value will not fit in the destination
1119 */
1120 HRESULT WINAPI VarI2FromDec(DECIMAL *pdecIn, SHORT* psOut)
1121 {
1122 LONG64 i64;
1123 HRESULT hRet;
1124
1125 hRet = VarI8FromDec(pdecIn, &i64);
1126
1127 if (SUCCEEDED(hRet))
1128 hRet = _VarI2FromI8(i64, psOut);
1129 return hRet;
1130 }
1131
1132 /************************************************************************
1133 * VarI2FromI8 (OLEAUT32.346)
1134 *
1135 * Convert a VT_I8 to a VT_I2.
1136 *
1137 * PARAMS
1138 * llIn [I] Source
1139 * psOut [O] Destination
1140 *
1141 * RETURNS
1142 * Success: S_OK.
1143 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1144 */
1145 HRESULT WINAPI VarI2FromI8(LONG64 llIn, SHORT* psOut)
1146 {
1147 return _VarI2FromI8(llIn, psOut);
1148 }
1149
1150 /************************************************************************
1151 * VarI2FromUI8 (OLEAUT32.347)
1152 *
1153 * Convert a VT_UI8 to a VT_I2.
1154 *
1155 * PARAMS
1156 * ullIn [I] Source
1157 * psOut [O] Destination
1158 *
1159 * RETURNS
1160 * Success: S_OK.
1161 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1162 */
1163 HRESULT WINAPI VarI2FromUI8(ULONG64 ullIn, SHORT* psOut)
1164 {
1165 return _VarI2FromUI8(ullIn, psOut);
1166 }
1167
1168 /* UI2
1169 */
1170
1171 /************************************************************************
1172 * VarUI2FromUI1 (OLEAUT32.257)
1173 *
1174 * Convert a VT_UI1 to a VT_UI2.
1175 *
1176 * PARAMS
1177 * bIn [I] Source
1178 * pusOut [O] Destination
1179 *
1180 * RETURNS
1181 * S_OK.
1182 */
1183 HRESULT WINAPI VarUI2FromUI1(BYTE bIn, USHORT* pusOut)
1184 {
1185 return _VarUI2FromUI1(bIn, pusOut);
1186 }
1187
1188 /************************************************************************
1189 * VarUI2FromI2 (OLEAUT32.258)
1190 *
1191 * Convert a VT_I2 to a VT_UI2.
1192 *
1193 * PARAMS
1194 * sIn [I] Source
1195 * pusOut [O] Destination
1196 *
1197 * RETURNS
1198 * Success: S_OK.
1199 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1200 */
1201 HRESULT WINAPI VarUI2FromI2(SHORT sIn, USHORT* pusOut)
1202 {
1203 return _VarUI2FromI2(sIn, pusOut);
1204 }
1205
1206 /************************************************************************
1207 * VarUI2FromI4 (OLEAUT32.259)
1208 *
1209 * Convert a VT_I4 to a VT_UI2.
1210 *
1211 * PARAMS
1212 * iIn [I] Source
1213 * pusOut [O] Destination
1214 *
1215 * RETURNS
1216 * Success: S_OK.
1217 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1218 */
1219 HRESULT WINAPI VarUI2FromI4(LONG iIn, USHORT* pusOut)
1220 {
1221 return _VarUI2FromI4(iIn, pusOut);
1222 }
1223
1224 /************************************************************************
1225 * VarUI2FromR4 (OLEAUT32.260)
1226 *
1227 * Convert a VT_R4 to a VT_UI2.
1228 *
1229 * PARAMS
1230 * fltIn [I] Source
1231 * pusOut [O] Destination
1232 *
1233 * RETURNS
1234 * Success: S_OK.
1235 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1236 */
1237 HRESULT WINAPI VarUI2FromR4(FLOAT fltIn, USHORT* pusOut)
1238 {
1239 return VarUI2FromR8(fltIn, pusOut);
1240 }
1241
1242 /************************************************************************
1243 * VarUI2FromR8 (OLEAUT32.261)
1244 *
1245 * Convert a VT_R8 to a VT_UI2.
1246 *
1247 * PARAMS
1248 * dblIn [I] Source
1249 * pusOut [O] Destination
1250 *
1251 * RETURNS
1252 * Success: S_OK.
1253 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1254 *
1255 * NOTES
1256 * See VarI8FromR8() for details concerning rounding.
1257 */
1258 HRESULT WINAPI VarUI2FromR8(double dblIn, USHORT* pusOut)
1259 {
1260 if (dblIn < -0.5 || dblIn >= UI2_MAX + 0.5)
1261 return DISP_E_OVERFLOW;
1262 VARIANT_DutchRound(USHORT, dblIn, *pusOut);
1263 return S_OK;
1264 }
1265
1266 /************************************************************************
1267 * VarUI2FromDate (OLEAUT32.262)
1268 *
1269 * Convert a VT_DATE to a VT_UI2.
1270 *
1271 * PARAMS
1272 * dateIn [I] Source
1273 * pusOut [O] Destination
1274 *
1275 * RETURNS
1276 * Success: S_OK.
1277 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1278 */
1279 HRESULT WINAPI VarUI2FromDate(DATE dateIn, USHORT* pusOut)
1280 {
1281 return VarUI2FromR8(dateIn, pusOut);
1282 }
1283
1284 /************************************************************************
1285 * VarUI2FromCy (OLEAUT32.263)
1286 *
1287 * Convert a VT_CY to a VT_UI2.
1288 *
1289 * PARAMS
1290 * cyIn [I] Source
1291 * pusOut [O] Destination
1292 *
1293 * RETURNS
1294 * Success: S_OK.
1295 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1296 *
1297 * NOTES
1298 * Negative values >= -5000 will be converted to 0.
1299 */
1300 HRESULT WINAPI VarUI2FromCy(CY cyIn, USHORT* pusOut)
1301 {
1302 ULONG i = UI2_MAX + 1;
1303
1304 VarUI4FromCy(cyIn, &i);
1305 return _VarUI2FromUI4(i, pusOut);
1306 }
1307
1308 /************************************************************************
1309 * VarUI2FromStr (OLEAUT32.264)
1310 *
1311 * Convert a VT_BSTR to a VT_UI2.
1312 *
1313 * PARAMS
1314 * strIn [I] Source
1315 * lcid [I] LCID for the conversion
1316 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1317 * pusOut [O] Destination
1318 *
1319 * RETURNS
1320 * Success: S_OK.
1321 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1322 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1323 */
1324 HRESULT WINAPI VarUI2FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, USHORT* pusOut)
1325 {
1326 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pusOut, VT_UI2);
1327 }
1328
1329 /************************************************************************
1330 * VarUI2FromDisp (OLEAUT32.265)
1331 *
1332 * Convert a VT_DISPATCH to a VT_UI2.
1333 *
1334 * PARAMS
1335 * pdispIn [I] Source
1336 * lcid [I] LCID for conversion
1337 * pusOut [O] Destination
1338 *
1339 * RETURNS
1340 * Success: S_OK.
1341 * Failure: E_INVALIDARG, if the source value is invalid
1342 * DISP_E_OVERFLOW, if the value will not fit in the destination
1343 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1344 */
1345 HRESULT WINAPI VarUI2FromDisp(IDispatch* pdispIn, LCID lcid, USHORT* pusOut)
1346 {
1347 return VARIANT_FromDisp(pdispIn, lcid, pusOut, VT_UI2, 0);
1348 }
1349
1350 /************************************************************************
1351 * VarUI2FromBool (OLEAUT32.266)
1352 *
1353 * Convert a VT_BOOL to a VT_UI2.
1354 *
1355 * PARAMS
1356 * boolIn [I] Source
1357 * pusOut [O] Destination
1358 *
1359 * RETURNS
1360 * S_OK.
1361 */
1362 HRESULT WINAPI VarUI2FromBool(VARIANT_BOOL boolIn, USHORT* pusOut)
1363 {
1364 return _VarUI2FromBool(boolIn, pusOut);
1365 }
1366
1367 /************************************************************************
1368 * VarUI2FromI1 (OLEAUT32.267)
1369 *
1370 * Convert a VT_I1 to a VT_UI2.
1371 *
1372 * PARAMS
1373 * cIn [I] Source
1374 * pusOut [O] Destination
1375 *
1376 * RETURNS
1377 * Success: S_OK.
1378 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1379 */
1380 HRESULT WINAPI VarUI2FromI1(signed char cIn, USHORT* pusOut)
1381 {
1382 return _VarUI2FromI1(cIn, pusOut);
1383 }
1384
1385 /************************************************************************
1386 * VarUI2FromUI4 (OLEAUT32.268)
1387 *
1388 * Convert a VT_UI4 to a VT_UI2.
1389 *
1390 * PARAMS
1391 * ulIn [I] Source
1392 * pusOut [O] Destination
1393 *
1394 * RETURNS
1395 * Success: S_OK.
1396 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1397 */
1398 HRESULT WINAPI VarUI2FromUI4(ULONG ulIn, USHORT* pusOut)
1399 {
1400 return _VarUI2FromUI4(ulIn, pusOut);
1401 }
1402
1403 /************************************************************************
1404 * VarUI2FromDec (OLEAUT32.269)
1405 *
1406 * Convert a VT_DECIMAL to a VT_UI2.
1407 *
1408 * PARAMS
1409 * pDecIn [I] Source
1410 * pusOut [O] Destination
1411 *
1412 * RETURNS
1413 * Success: S_OK.
1414 * Failure: E_INVALIDARG, if the source value is invalid
1415 * DISP_E_OVERFLOW, if the value will not fit in the destination
1416 */
1417 HRESULT WINAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT* pusOut)
1418 {
1419 LONG64 i64;
1420 HRESULT hRet;
1421
1422 hRet = VarI8FromDec(pdecIn, &i64);
1423
1424 if (SUCCEEDED(hRet))
1425 hRet = _VarUI2FromI8(i64, pusOut);
1426 return hRet;
1427 }
1428
1429 /************************************************************************
1430 * VarUI2FromI8 (OLEAUT32.378)
1431 *
1432 * Convert a VT_I8 to a VT_UI2.
1433 *
1434 * PARAMS
1435 * llIn [I] Source
1436 * pusOut [O] Destination
1437 *
1438 * RETURNS
1439 * Success: S_OK.
1440 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1441 */
1442 HRESULT WINAPI VarUI2FromI8(LONG64 llIn, USHORT* pusOut)
1443 {
1444 return _VarUI2FromI8(llIn, pusOut);
1445 }
1446
1447 /************************************************************************
1448 * VarUI2FromUI8 (OLEAUT32.379)
1449 *
1450 * Convert a VT_UI8 to a VT_UI2.
1451 *
1452 * PARAMS
1453 * ullIn [I] Source
1454 * pusOut [O] Destination
1455 *
1456 * RETURNS
1457 * Success: S_OK.
1458 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1459 */
1460 HRESULT WINAPI VarUI2FromUI8(ULONG64 ullIn, USHORT* pusOut)
1461 {
1462 return _VarUI2FromUI8(ullIn, pusOut);
1463 }
1464
1465 /* I4
1466 */
1467
1468 /************************************************************************
1469 * VarI4FromUI1 (OLEAUT32.58)
1470 *
1471 * Convert a VT_UI1 to a VT_I4.
1472 *
1473 * PARAMS
1474 * bIn [I] Source
1475 * piOut [O] Destination
1476 *
1477 * RETURNS
1478 * S_OK.
1479 */
1480 HRESULT WINAPI VarI4FromUI1(BYTE bIn, LONG *piOut)
1481 {
1482 return _VarI4FromUI1(bIn, piOut);
1483 }
1484
1485 /************************************************************************
1486 * VarI4FromI2 (OLEAUT32.59)
1487 *
1488 * Convert a VT_I2 to a VT_I4.
1489 *
1490 * PARAMS
1491 * sIn [I] Source
1492 * piOut [O] Destination
1493 *
1494 * RETURNS
1495 * Success: S_OK.
1496 * Failure: E_INVALIDARG, if the source value is invalid
1497 * DISP_E_OVERFLOW, if the value will not fit in the destination
1498 */
1499 HRESULT WINAPI VarI4FromI2(SHORT sIn, LONG *piOut)
1500 {
1501 return _VarI4FromI2(sIn, piOut);
1502 }
1503
1504 /************************************************************************
1505 * VarI4FromR4 (OLEAUT32.60)
1506 *
1507 * Convert a VT_R4 to a VT_I4.
1508 *
1509 * PARAMS
1510 * fltIn [I] Source
1511 * piOut [O] Destination
1512 *
1513 * RETURNS
1514 * Success: S_OK.
1515 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1516 */
1517 HRESULT WINAPI VarI4FromR4(FLOAT fltIn, LONG *piOut)
1518 {
1519 return VarI4FromR8(fltIn, piOut);
1520 }
1521
1522 /************************************************************************
1523 * VarI4FromR8 (OLEAUT32.61)
1524 *
1525 * Convert a VT_R8 to a VT_I4.
1526 *
1527 * PARAMS
1528 * dblIn [I] Source
1529 * piOut [O] Destination
1530 *
1531 * RETURNS
1532 * Success: S_OK.
1533 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1534 *
1535 * NOTES
1536 * See VarI8FromR8() for details concerning rounding.
1537 */
1538 HRESULT WINAPI VarI4FromR8(double dblIn, LONG *piOut)
1539 {
1540 if (dblIn < I4_MIN - 0.5 || dblIn >= I4_MAX + 0.5)
1541 return DISP_E_OVERFLOW;
1542 VARIANT_DutchRound(LONG, dblIn, *piOut);
1543 return S_OK;
1544 }
1545
1546 /************************************************************************
1547 * VarI4FromCy (OLEAUT32.62)
1548 *
1549 * Convert a VT_CY to a VT_I4.
1550 *
1551 * PARAMS
1552 * cyIn [I] Source
1553 * piOut [O] Destination
1554 *
1555 * RETURNS
1556 * Success: S_OK.
1557 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1558 */
1559 HRESULT WINAPI VarI4FromCy(CY cyIn, LONG *piOut)
1560 {
1561 double d = cyIn.int64 / CY_MULTIPLIER_F;
1562 return VarI4FromR8(d, piOut);
1563 }
1564
1565 /************************************************************************
1566 * VarI4FromDate (OLEAUT32.63)
1567 *
1568 * Convert a VT_DATE to a VT_I4.
1569 *
1570 * PARAMS
1571 * dateIn [I] Source
1572 * piOut [O] Destination
1573 *
1574 * RETURNS
1575 * Success: S_OK.
1576 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1577 */
1578 HRESULT WINAPI VarI4FromDate(DATE dateIn, LONG *piOut)
1579 {
1580 return VarI4FromR8(dateIn, piOut);
1581 }
1582
1583 /************************************************************************
1584 * VarI4FromStr (OLEAUT32.64)
1585 *
1586 * Convert a VT_BSTR to a VT_I4.
1587 *
1588 * PARAMS
1589 * strIn [I] Source
1590 * lcid [I] LCID for the conversion
1591 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1592 * piOut [O] Destination
1593 *
1594 * RETURNS
1595 * Success: S_OK.
1596 * Failure: E_INVALIDARG, if any parameter is invalid
1597 * DISP_E_OVERFLOW, if the value will not fit in the destination
1598 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1599 */
1600 HRESULT WINAPI VarI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG *piOut)
1601 {
1602 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, piOut, VT_I4);
1603 }
1604
1605 /************************************************************************
1606 * VarI4FromDisp (OLEAUT32.65)
1607 *
1608 * Convert a VT_DISPATCH to a VT_I4.
1609 *
1610 * PARAMS
1611 * pdispIn [I] Source
1612 * lcid [I] LCID for conversion
1613 * piOut [O] Destination
1614 *
1615 * RETURNS
1616 * Success: S_OK.
1617 * Failure: E_INVALIDARG, if the source value is invalid
1618 * DISP_E_OVERFLOW, if the value will not fit in the destination
1619 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1620 */
1621 HRESULT WINAPI VarI4FromDisp(IDispatch* pdispIn, LCID lcid, LONG *piOut)
1622 {
1623 return VARIANT_FromDisp(pdispIn, lcid, piOut, VT_I4, 0);
1624 }
1625
1626 /************************************************************************
1627 * VarI4FromBool (OLEAUT32.66)
1628 *
1629 * Convert a VT_BOOL to a VT_I4.
1630 *
1631 * PARAMS
1632 * boolIn [I] Source
1633 * piOut [O] Destination
1634 *
1635 * RETURNS
1636 * S_OK.
1637 */
1638 HRESULT WINAPI VarI4FromBool(VARIANT_BOOL boolIn, LONG *piOut)
1639 {
1640 return _VarI4FromBool(boolIn, piOut);
1641 }
1642
1643 /************************************************************************
1644 * VarI4FromI1 (OLEAUT32.209)
1645 *
1646 * Convert a VT_I1 to a VT_I4.
1647 *
1648 * PARAMS
1649 * cIn [I] Source
1650 * piOut [O] Destination
1651 *
1652 * RETURNS
1653 * S_OK.
1654 */
1655 HRESULT WINAPI VarI4FromI1(signed char cIn, LONG *piOut)
1656 {
1657 return _VarI4FromI1(cIn, piOut);
1658 }
1659
1660 /************************************************************************
1661 * VarI4FromUI2 (OLEAUT32.210)
1662 *
1663 * Convert a VT_UI2 to a VT_I4.
1664 *
1665 * PARAMS
1666 * usIn [I] Source
1667 * piOut [O] Destination
1668 *
1669 * RETURNS
1670 * S_OK.
1671 */
1672 HRESULT WINAPI VarI4FromUI2(USHORT usIn, LONG *piOut)
1673 {
1674 return _VarI4FromUI2(usIn, piOut);
1675 }
1676
1677 /************************************************************************
1678 * VarI4FromUI4 (OLEAUT32.211)
1679 *
1680 * Convert a VT_UI4 to a VT_I4.
1681 *
1682 * PARAMS
1683 * ulIn [I] Source
1684 * piOut [O] Destination
1685 *
1686 * RETURNS
1687 * Success: S_OK.
1688 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1689 */
1690 HRESULT WINAPI VarI4FromUI4(ULONG ulIn, LONG *piOut)
1691 {
1692 return _VarI4FromUI4(ulIn, piOut);
1693 }
1694
1695 /************************************************************************
1696 * VarI4FromDec (OLEAUT32.212)
1697 *
1698 * Convert a VT_DECIMAL to a VT_I4.
1699 *
1700 * PARAMS
1701 * pDecIn [I] Source
1702 * piOut [O] Destination
1703 *
1704 * RETURNS
1705 * Success: S_OK.
1706 * Failure: E_INVALIDARG, if pdecIn is invalid
1707 * DISP_E_OVERFLOW, if the value will not fit in the destination
1708 */
1709 HRESULT WINAPI VarI4FromDec(DECIMAL *pdecIn, LONG *piOut)
1710 {
1711 LONG64 i64;
1712 HRESULT hRet;
1713
1714 hRet = VarI8FromDec(pdecIn, &i64);
1715
1716 if (SUCCEEDED(hRet))
1717 hRet = _VarI4FromI8(i64, piOut);
1718 return hRet;
1719 }
1720
1721 /************************************************************************
1722 * VarI4FromI8 (OLEAUT32.348)
1723 *
1724 * Convert a VT_I8 to a VT_I4.
1725 *
1726 * PARAMS
1727 * llIn [I] Source
1728 * piOut [O] Destination
1729 *
1730 * RETURNS
1731 * Success: S_OK.
1732 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1733 */
1734 HRESULT WINAPI VarI4FromI8(LONG64 llIn, LONG *piOut)
1735 {
1736 return _VarI4FromI8(llIn, piOut);
1737 }
1738
1739 /************************************************************************
1740 * VarI4FromUI8 (OLEAUT32.349)
1741 *
1742 * Convert a VT_UI8 to a VT_I4.
1743 *
1744 * PARAMS
1745 * ullIn [I] Source
1746 * piOut [O] Destination
1747 *
1748 * RETURNS
1749 * Success: S_OK.
1750 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1751 */
1752 HRESULT WINAPI VarI4FromUI8(ULONG64 ullIn, LONG *piOut)
1753 {
1754 return _VarI4FromUI8(ullIn, piOut);
1755 }
1756
1757 /* UI4
1758 */
1759
1760 /************************************************************************
1761 * VarUI4FromUI1 (OLEAUT32.270)
1762 *
1763 * Convert a VT_UI1 to a VT_UI4.
1764 *
1765 * PARAMS
1766 * bIn [I] Source
1767 * pulOut [O] Destination
1768 *
1769 * RETURNS
1770 * S_OK.
1771 */
1772 HRESULT WINAPI VarUI4FromUI1(BYTE bIn, ULONG *pulOut)
1773 {
1774 return _VarUI4FromUI1(bIn, pulOut);
1775 }
1776
1777 /************************************************************************
1778 * VarUI4FromI2 (OLEAUT32.271)
1779 *
1780 * Convert a VT_I2 to a VT_UI4.
1781 *
1782 * PARAMS
1783 * sIn [I] Source
1784 * pulOut [O] Destination
1785 *
1786 * RETURNS
1787 * Success: S_OK.
1788 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1789 */
1790 HRESULT WINAPI VarUI4FromI2(SHORT sIn, ULONG *pulOut)
1791 {
1792 return _VarUI4FromI2(sIn, pulOut);
1793 }
1794
1795 /************************************************************************
1796 * VarUI4FromI4 (OLEAUT32.272)
1797 *
1798 * Convert a VT_I4 to a VT_UI4.
1799 *
1800 * PARAMS
1801 * iIn [I] Source
1802 * pulOut [O] Destination
1803 *
1804 * RETURNS
1805 * Success: S_OK.
1806 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1807 */
1808 HRESULT WINAPI VarUI4FromI4(LONG iIn, ULONG *pulOut)
1809 {
1810 return _VarUI4FromI4(iIn, pulOut);
1811 }
1812
1813 /************************************************************************
1814 * VarUI4FromR4 (OLEAUT32.273)
1815 *
1816 * Convert a VT_R4 to a VT_UI4.
1817 *
1818 * PARAMS
1819 * fltIn [I] Source
1820 * pulOut [O] Destination
1821 *
1822 * RETURNS
1823 * Success: S_OK.
1824 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1825 */
1826 HRESULT WINAPI VarUI4FromR4(FLOAT fltIn, ULONG *pulOut)
1827 {
1828 return VarUI4FromR8(fltIn, pulOut);
1829 }
1830
1831 /************************************************************************
1832 * VarUI4FromR8 (OLEAUT32.274)
1833 *
1834 * Convert a VT_R8 to a VT_UI4.
1835 *
1836 * PARAMS
1837 * dblIn [I] Source
1838 * pulOut [O] Destination
1839 *
1840 * RETURNS
1841 * Success: S_OK.
1842 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1843 *
1844 * NOTES
1845 * See VarI8FromR8() for details concerning rounding.
1846 */
1847 HRESULT WINAPI VarUI4FromR8(double dblIn, ULONG *pulOut)
1848 {
1849 if (dblIn < -0.5 || dblIn >= UI4_MAX + 0.5)
1850 return DISP_E_OVERFLOW;
1851 VARIANT_DutchRound(ULONG, dblIn, *pulOut);
1852 return S_OK;
1853 }
1854
1855 /************************************************************************
1856 * VarUI4FromDate (OLEAUT32.275)
1857 *
1858 * Convert a VT_DATE to a VT_UI4.
1859 *
1860 * PARAMS
1861 * dateIn [I] Source
1862 * pulOut [O] Destination
1863 *
1864 * RETURNS
1865 * Success: S_OK.
1866 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1867 */
1868 HRESULT WINAPI VarUI4FromDate(DATE dateIn, ULONG *pulOut)
1869 {
1870 return VarUI4FromR8(dateIn, pulOut);
1871 }
1872
1873 /************************************************************************
1874 * VarUI4FromCy (OLEAUT32.276)
1875 *
1876 * Convert a VT_CY to a VT_UI4.
1877 *
1878 * PARAMS
1879 * cyIn [I] Source
1880 * pulOut [O] Destination
1881 *
1882 * RETURNS
1883 * Success: S_OK.
1884 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1885 */
1886 HRESULT WINAPI VarUI4FromCy(CY cyIn, ULONG *pulOut)
1887 {
1888 double d = cyIn.int64 / CY_MULTIPLIER_F;
1889 return VarUI4FromR8(d, pulOut);
1890 }
1891
1892 /************************************************************************
1893 * VarUI4FromStr (OLEAUT32.277)
1894 *
1895 * Convert a VT_BSTR to a VT_UI4.
1896 *
1897 * PARAMS
1898 * strIn [I] Source
1899 * lcid [I] LCID for the conversion
1900 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
1901 * pulOut [O] Destination
1902 *
1903 * RETURNS
1904 * Success: S_OK.
1905 * Failure: E_INVALIDARG, if any parameter is invalid
1906 * DISP_E_OVERFLOW, if the value will not fit in the destination
1907 * DISP_E_TYPEMISMATCH, if strIn cannot be converted
1908 */
1909 HRESULT WINAPI VarUI4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG *pulOut)
1910 {
1911 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pulOut, VT_UI4);
1912 }
1913
1914 /************************************************************************
1915 * VarUI4FromDisp (OLEAUT32.278)
1916 *
1917 * Convert a VT_DISPATCH to a VT_UI4.
1918 *
1919 * PARAMS
1920 * pdispIn [I] Source
1921 * lcid [I] LCID for conversion
1922 * pulOut [O] Destination
1923 *
1924 * RETURNS
1925 * Success: S_OK.
1926 * Failure: E_INVALIDARG, if the source value is invalid
1927 * DISP_E_OVERFLOW, if the value will not fit in the destination
1928 * DISP_E_TYPEMISMATCH, if the type cannot be converted
1929 */
1930 HRESULT WINAPI VarUI4FromDisp(IDispatch* pdispIn, LCID lcid, ULONG *pulOut)
1931 {
1932 return VARIANT_FromDisp(pdispIn, lcid, pulOut, VT_UI4, 0);
1933 }
1934
1935 /************************************************************************
1936 * VarUI4FromBool (OLEAUT32.279)
1937 *
1938 * Convert a VT_BOOL to a VT_UI4.
1939 *
1940 * PARAMS
1941 * boolIn [I] Source
1942 * pulOut [O] Destination
1943 *
1944 * RETURNS
1945 * S_OK.
1946 */
1947 HRESULT WINAPI VarUI4FromBool(VARIANT_BOOL boolIn, ULONG *pulOut)
1948 {
1949 return _VarUI4FromBool(boolIn, pulOut);
1950 }
1951
1952 /************************************************************************
1953 * VarUI4FromI1 (OLEAUT32.280)
1954 *
1955 * Convert a VT_I1 to a VT_UI4.
1956 *
1957 * PARAMS
1958 * cIn [I] Source
1959 * pulOut [O] Destination
1960 *
1961 * RETURNS
1962 * Success: S_OK.
1963 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
1964 */
1965 HRESULT WINAPI VarUI4FromI1(signed char cIn, ULONG *pulOut)
1966 {
1967 return _VarUI4FromI1(cIn, pulOut);
1968 }
1969
1970 /************************************************************************
1971 * VarUI4FromUI2 (OLEAUT32.281)
1972 *
1973 * Convert a VT_UI2 to a VT_UI4.
1974 *
1975 * PARAMS
1976 * usIn [I] Source
1977 * pulOut [O] Destination
1978 *
1979 * RETURNS
1980 * S_OK.
1981 */
1982 HRESULT WINAPI VarUI4FromUI2(USHORT usIn, ULONG *pulOut)
1983 {
1984 return _VarUI4FromUI2(usIn, pulOut);
1985 }
1986
1987 /************************************************************************
1988 * VarUI4FromDec (OLEAUT32.282)
1989 *
1990 * Convert a VT_DECIMAL to a VT_UI4.
1991 *
1992 * PARAMS
1993 * pDecIn [I] Source
1994 * pulOut [O] Destination
1995 *
1996 * RETURNS
1997 * Success: S_OK.
1998 * Failure: E_INVALIDARG, if pdecIn is invalid
1999 * DISP_E_OVERFLOW, if the value will not fit in the destination
2000 */
2001 HRESULT WINAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pulOut)
2002 {
2003 LONG64 i64;
2004 HRESULT hRet;
2005
2006 hRet = VarI8FromDec(pdecIn, &i64);
2007
2008 if (SUCCEEDED(hRet))
2009 hRet = _VarUI4FromI8(i64, pulOut);
2010 return hRet;
2011 }
2012
2013 /************************************************************************
2014 * VarUI4FromI8 (OLEAUT32.425)
2015 *
2016 * Convert a VT_I8 to a VT_UI4.
2017 *
2018 * PARAMS
2019 * llIn [I] Source
2020 * pulOut [O] Destination
2021 *
2022 * RETURNS
2023 * Success: S_OK.
2024 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2025 */
2026 HRESULT WINAPI VarUI4FromI8(LONG64 llIn, ULONG *pulOut)
2027 {
2028 return _VarUI4FromI8(llIn, pulOut);
2029 }
2030
2031 /************************************************************************
2032 * VarUI4FromUI8 (OLEAUT32.426)
2033 *
2034 * Convert a VT_UI8 to a VT_UI4.
2035 *
2036 * PARAMS
2037 * ullIn [I] Source
2038 * pulOut [O] Destination
2039 *
2040 * RETURNS
2041 * Success: S_OK.
2042 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2043 */
2044 HRESULT WINAPI VarUI4FromUI8(ULONG64 ullIn, ULONG *pulOut)
2045 {
2046 return _VarUI4FromUI8(ullIn, pulOut);
2047 }
2048
2049 /* I8
2050 */
2051
2052 /************************************************************************
2053 * VarI8FromUI1 (OLEAUT32.333)
2054 *
2055 * Convert a VT_UI1 to a VT_I8.
2056 *
2057 * PARAMS
2058 * bIn [I] Source
2059 * pi64Out [O] Destination
2060 *
2061 * RETURNS
2062 * S_OK.
2063 */
2064 HRESULT WINAPI VarI8FromUI1(BYTE bIn, LONG64* pi64Out)
2065 {
2066 return _VarI8FromUI1(bIn, pi64Out);
2067 }
2068
2069
2070 /************************************************************************
2071 * VarI8FromI2 (OLEAUT32.334)
2072 *
2073 * Convert a VT_I2 to a VT_I8.
2074 *
2075 * PARAMS
2076 * sIn [I] Source
2077 * pi64Out [O] Destination
2078 *
2079 * RETURNS
2080 * S_OK.
2081 */
2082 HRESULT WINAPI VarI8FromI2(SHORT sIn, LONG64* pi64Out)
2083 {
2084 return _VarI8FromI2(sIn, pi64Out);
2085 }
2086
2087 /************************************************************************
2088 * VarI8FromR4 (OLEAUT32.335)
2089 *
2090 * Convert a VT_R4 to a VT_I8.
2091 *
2092 * PARAMS
2093 * fltIn [I] Source
2094 * pi64Out [O] Destination
2095 *
2096 * RETURNS
2097 * Success: S_OK.
2098 * Failure: E_INVALIDARG, if the source value is invalid
2099 * DISP_E_OVERFLOW, if the value will not fit in the destination
2100 */
2101 HRESULT WINAPI VarI8FromR4(FLOAT fltIn, LONG64* pi64Out)
2102 {
2103 return VarI8FromR8(fltIn, pi64Out);
2104 }
2105
2106 /************************************************************************
2107 * VarI8FromR8 (OLEAUT32.336)
2108 *
2109 * Convert a VT_R8 to a VT_I8.
2110 *
2111 * PARAMS
2112 * dblIn [I] Source
2113 * pi64Out [O] Destination
2114 *
2115 * RETURNS
2116 * Success: S_OK.
2117 * Failure: E_INVALIDARG, if the source value is invalid
2118 * DISP_E_OVERFLOW, if the value will not fit in the destination
2119 *
2120 * NOTES
2121 * Only values that fit into 63 bits are accepted. Due to rounding issues,
2122 * very high or low values will not be accurately converted.
2123 *
2124 * Numbers are rounded using Dutch rounding, as follows:
2125 *
2126 *| Fractional Part Sign Direction Example
2127 *| --------------- ---- --------- -------
2128 *| < 0.5 + Down 0.4 -> 0.0
2129 *| < 0.5 - Up -0.4 -> 0.0
2130 *| > 0.5 + Up 0.6 -> 1.0
2131 *| < 0.5 - Up -0.6 -> -1.0
2132 *| = 0.5 + Up/Down Down if even, Up if odd
2133 *| = 0.5 - Up/Down Up if even, Down if odd
2134 *
2135 * This system is often used in supermarkets.
2136 */
2137 HRESULT WINAPI VarI8FromR8(double dblIn, LONG64* pi64Out)
2138 {
2139 if ( dblIn < -4611686018427387904.0 || dblIn >= 4611686018427387904.0)
2140 return DISP_E_OVERFLOW;
2141 VARIANT_DutchRound(LONG64, dblIn, *pi64Out);
2142 return S_OK;
2143 }
2144
2145 /************************************************************************
2146 * VarI8FromCy (OLEAUT32.337)
2147 *
2148 * Convert a VT_CY to a VT_I8.
2149 *
2150 * PARAMS
2151 * cyIn [I] Source
2152 * pi64Out [O] Destination
2153 *
2154 * RETURNS
2155 * S_OK.
2156 *
2157 * NOTES
2158 * All negative numbers are rounded down by 1, including those that are
2159 * evenly divisible by 10000 (this is a Win32 bug that Wine mimics).
2160 * Positive numbers are rounded using Dutch rounding: See VarI8FromR8()
2161 * for details.
2162 */
2163 HRESULT WINAPI VarI8FromCy(CY cyIn, LONG64* pi64Out)
2164 {
2165 *pi64Out = cyIn.int64 / CY_MULTIPLIER;
2166
2167 if (cyIn.int64 < 0)
2168 (*pi64Out)--; /* Mimic Win32 bug */
2169 else
2170 {
2171 cyIn.int64 -= *pi64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2172
2173 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pi64Out & 0x1)))
2174 (*pi64Out)++;
2175 }
2176 return S_OK;
2177 }
2178
2179 /************************************************************************
2180 * VarI8FromDate (OLEAUT32.338)
2181 *
2182 * Convert a VT_DATE to a VT_I8.
2183 *
2184 * PARAMS
2185 * dateIn [I] Source
2186 * pi64Out [O] Destination
2187 *
2188 * RETURNS
2189 * Success: S_OK.
2190 * Failure: E_INVALIDARG, if the source value is invalid
2191 * DISP_E_OVERFLOW, if the value will not fit in the destination
2192 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2193 */
2194 HRESULT WINAPI VarI8FromDate(DATE dateIn, LONG64* pi64Out)
2195 {
2196 return VarI8FromR8(dateIn, pi64Out);
2197 }
2198
2199 /************************************************************************
2200 * VarI8FromStr (OLEAUT32.339)
2201 *
2202 * Convert a VT_BSTR to a VT_I8.
2203 *
2204 * PARAMS
2205 * strIn [I] Source
2206 * lcid [I] LCID for the conversion
2207 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2208 * pi64Out [O] Destination
2209 *
2210 * RETURNS
2211 * Success: S_OK.
2212 * Failure: E_INVALIDARG, if the source value is invalid
2213 * DISP_E_OVERFLOW, if the value will not fit in the destination
2214 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2215 */
2216 HRESULT WINAPI VarI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, LONG64* pi64Out)
2217 {
2218 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pi64Out, VT_I8);
2219 }
2220
2221 /************************************************************************
2222 * VarI8FromDisp (OLEAUT32.340)
2223 *
2224 * Convert a VT_DISPATCH to a VT_I8.
2225 *
2226 * PARAMS
2227 * pdispIn [I] Source
2228 * lcid [I] LCID for conversion
2229 * pi64Out [O] Destination
2230 *
2231 * RETURNS
2232 * Success: S_OK.
2233 * Failure: E_INVALIDARG, if the source value is invalid
2234 * DISP_E_OVERFLOW, if the value will not fit in the destination
2235 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2236 */
2237 HRESULT WINAPI VarI8FromDisp(IDispatch* pdispIn, LCID lcid, LONG64* pi64Out)
2238 {
2239 return VARIANT_FromDisp(pdispIn, lcid, pi64Out, VT_I8, 0);
2240 }
2241
2242 /************************************************************************
2243 * VarI8FromBool (OLEAUT32.341)
2244 *
2245 * Convert a VT_BOOL to a VT_I8.
2246 *
2247 * PARAMS
2248 * boolIn [I] Source
2249 * pi64Out [O] Destination
2250 *
2251 * RETURNS
2252 * S_OK.
2253 */
2254 HRESULT WINAPI VarI8FromBool(VARIANT_BOOL boolIn, LONG64* pi64Out)
2255 {
2256 return VarI8FromI2(boolIn, pi64Out);
2257 }
2258
2259 /************************************************************************
2260 * VarI8FromI1 (OLEAUT32.342)
2261 *
2262 * Convert a VT_I1 to a VT_I8.
2263 *
2264 * PARAMS
2265 * cIn [I] Source
2266 * pi64Out [O] Destination
2267 *
2268 * RETURNS
2269 * S_OK.
2270 */
2271 HRESULT WINAPI VarI8FromI1(signed char cIn, LONG64* pi64Out)
2272 {
2273 return _VarI8FromI1(cIn, pi64Out);
2274 }
2275
2276 /************************************************************************
2277 * VarI8FromUI2 (OLEAUT32.343)
2278 *
2279 * Convert a VT_UI2 to a VT_I8.
2280 *
2281 * PARAMS
2282 * usIn [I] Source
2283 * pi64Out [O] Destination
2284 *
2285 * RETURNS
2286 * S_OK.
2287 */
2288 HRESULT WINAPI VarI8FromUI2(USHORT usIn, LONG64* pi64Out)
2289 {
2290 return _VarI8FromUI2(usIn, pi64Out);
2291 }
2292
2293 /************************************************************************
2294 * VarI8FromUI4 (OLEAUT32.344)
2295 *
2296 * Convert a VT_UI4 to a VT_I8.
2297 *
2298 * PARAMS
2299 * ulIn [I] Source
2300 * pi64Out [O] Destination
2301 *
2302 * RETURNS
2303 * S_OK.
2304 */
2305 HRESULT WINAPI VarI8FromUI4(ULONG ulIn, LONG64* pi64Out)
2306 {
2307 return _VarI8FromUI4(ulIn, pi64Out);
2308 }
2309
2310 /************************************************************************
2311 * VarI8FromDec (OLEAUT32.345)
2312 *
2313 * Convert a VT_DECIMAL to a VT_I8.
2314 *
2315 * PARAMS
2316 * pDecIn [I] Source
2317 * pi64Out [O] Destination
2318 *
2319 * RETURNS
2320 * Success: S_OK.
2321 * Failure: E_INVALIDARG, if the source value is invalid
2322 * DISP_E_OVERFLOW, if the value will not fit in the destination
2323 */
2324 HRESULT WINAPI VarI8FromDec(DECIMAL *pdecIn, LONG64* pi64Out)
2325 {
2326 if (!DEC_SCALE(pdecIn))
2327 {
2328 /* This decimal is just a 96 bit integer */
2329 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2330 return E_INVALIDARG;
2331
2332 if (DEC_HI32(pdecIn) || DEC_MID32(pdecIn) & 0x80000000)
2333 return DISP_E_OVERFLOW;
2334
2335 if (DEC_SIGN(pdecIn))
2336 *pi64Out = -DEC_LO64(pdecIn);
2337 else
2338 *pi64Out = DEC_LO64(pdecIn);
2339 return S_OK;
2340 }
2341 else
2342 {
2343 /* Decimal contains a floating point number */
2344 HRESULT hRet;
2345 double dbl;
2346
2347 hRet = VarR8FromDec(pdecIn, &dbl);
2348 if (SUCCEEDED(hRet))
2349 hRet = VarI8FromR8(dbl, pi64Out);
2350 return hRet;
2351 }
2352 }
2353
2354 /************************************************************************
2355 * VarI8FromUI8 (OLEAUT32.427)
2356 *
2357 * Convert a VT_UI8 to a VT_I8.
2358 *
2359 * PARAMS
2360 * ullIn [I] Source
2361 * pi64Out [O] Destination
2362 *
2363 * RETURNS
2364 * Success: S_OK.
2365 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2366 */
2367 HRESULT WINAPI VarI8FromUI8(ULONG64 ullIn, LONG64* pi64Out)
2368 {
2369 return _VarI8FromUI8(ullIn, pi64Out);
2370 }
2371
2372 /* UI8
2373 */
2374
2375 /************************************************************************
2376 * VarUI8FromI8 (OLEAUT32.428)
2377 *
2378 * Convert a VT_I8 to a VT_UI8.
2379 *
2380 * PARAMS
2381 * ulIn [I] Source
2382 * pui64Out [O] Destination
2383 *
2384 * RETURNS
2385 * Success: S_OK.
2386 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2387 */
2388 HRESULT WINAPI VarUI8FromI8(LONG64 llIn, ULONG64* pui64Out)
2389 {
2390 return _VarUI8FromI8(llIn, pui64Out);
2391 }
2392
2393 /************************************************************************
2394 * VarUI8FromUI1 (OLEAUT32.429)
2395 *
2396 * Convert a VT_UI1 to a VT_UI8.
2397 *
2398 * PARAMS
2399 * bIn [I] Source
2400 * pui64Out [O] Destination
2401 *
2402 * RETURNS
2403 * S_OK.
2404 */
2405 HRESULT WINAPI VarUI8FromUI1(BYTE bIn, ULONG64* pui64Out)
2406 {
2407 return _VarUI8FromUI1(bIn, pui64Out);
2408 }
2409
2410 /************************************************************************
2411 * VarUI8FromI2 (OLEAUT32.430)
2412 *
2413 * Convert a VT_I2 to a VT_UI8.
2414 *
2415 * PARAMS
2416 * sIn [I] Source
2417 * pui64Out [O] Destination
2418 *
2419 * RETURNS
2420 * S_OK.
2421 */
2422 HRESULT WINAPI VarUI8FromI2(SHORT sIn, ULONG64* pui64Out)
2423 {
2424 return _VarUI8FromI2(sIn, pui64Out);
2425 }
2426
2427 /************************************************************************
2428 * VarUI8FromR4 (OLEAUT32.431)
2429 *
2430 * Convert a VT_R4 to a VT_UI8.
2431 *
2432 * PARAMS
2433 * fltIn [I] Source
2434 * pui64Out [O] Destination
2435 *
2436 * RETURNS
2437 * Success: S_OK.
2438 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2439 */
2440 HRESULT WINAPI VarUI8FromR4(FLOAT fltIn, ULONG64* pui64Out)
2441 {
2442 return VarUI8FromR8(fltIn, pui64Out);
2443 }
2444
2445 /************************************************************************
2446 * VarUI8FromR8 (OLEAUT32.432)
2447 *
2448 * Convert a VT_R8 to a VT_UI8.
2449 *
2450 * PARAMS
2451 * dblIn [I] Source
2452 * pui64Out [O] Destination
2453 *
2454 * RETURNS
2455 * Success: S_OK.
2456 * Failure: E_INVALIDARG, if the source value is invalid
2457 * DISP_E_OVERFLOW, if the value will not fit in the destination
2458 *
2459 * NOTES
2460 * See VarI8FromR8() for details concerning rounding.
2461 */
2462 HRESULT WINAPI VarUI8FromR8(double dblIn, ULONG64* pui64Out)
2463 {
2464 if (dblIn < -0.5 || dblIn > 1.844674407370955e19)
2465 return DISP_E_OVERFLOW;
2466 VARIANT_DutchRound(ULONG64, dblIn, *pui64Out);
2467 return S_OK;
2468 }
2469
2470 /************************************************************************
2471 * VarUI8FromCy (OLEAUT32.433)
2472 *
2473 * Convert a VT_CY to a VT_UI8.
2474 *
2475 * PARAMS
2476 * cyIn [I] Source
2477 * pui64Out [O] Destination
2478 *
2479 * RETURNS
2480 * Success: S_OK.
2481 * Failure: E_INVALIDARG, if the source value is invalid
2482 * DISP_E_OVERFLOW, if the value will not fit in the destination
2483 *
2484 * NOTES
2485 * Negative values >= -5000 will be converted to 0.
2486 */
2487 HRESULT WINAPI VarUI8FromCy(CY cyIn, ULONG64* pui64Out)
2488 {
2489 if (cyIn.int64 < 0)
2490 {
2491 if (cyIn.int64 < -CY_HALF)
2492 return DISP_E_OVERFLOW;
2493 *pui64Out = 0;
2494 }
2495 else
2496 {
2497 *pui64Out = cyIn.int64 / CY_MULTIPLIER;
2498
2499 cyIn.int64 -= *pui64Out * CY_MULTIPLIER; /* cyIn.s.Lo now holds fractional remainder */
2500
2501 if (cyIn.s.Lo > CY_HALF || (cyIn.s.Lo == CY_HALF && (*pui64Out & 0x1)))
2502 (*pui64Out)++;
2503 }
2504 return S_OK;
2505 }
2506
2507 /************************************************************************
2508 * VarUI8FromDate (OLEAUT32.434)
2509 *
2510 * Convert a VT_DATE to a VT_UI8.
2511 *
2512 * PARAMS
2513 * dateIn [I] Source
2514 * pui64Out [O] Destination
2515 *
2516 * RETURNS
2517 * Success: S_OK.
2518 * Failure: E_INVALIDARG, if the source value is invalid
2519 * DISP_E_OVERFLOW, if the value will not fit in the destination
2520 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2521 */
2522 HRESULT WINAPI VarUI8FromDate(DATE dateIn, ULONG64* pui64Out)
2523 {
2524 return VarUI8FromR8(dateIn, pui64Out);
2525 }
2526
2527 /************************************************************************
2528 * VarUI8FromStr (OLEAUT32.435)
2529 *
2530 * Convert a VT_BSTR to a VT_UI8.
2531 *
2532 * PARAMS
2533 * strIn [I] Source
2534 * lcid [I] LCID for the conversion
2535 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2536 * pui64Out [O] Destination
2537 *
2538 * RETURNS
2539 * Success: S_OK.
2540 * Failure: E_INVALIDARG, if the source value is invalid
2541 * DISP_E_OVERFLOW, if the value will not fit in the destination
2542 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2543 */
2544 HRESULT WINAPI VarUI8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, ULONG64* pui64Out)
2545 {
2546 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pui64Out, VT_UI8);
2547 }
2548
2549 /************************************************************************
2550 * VarUI8FromDisp (OLEAUT32.436)
2551 *
2552 * Convert a VT_DISPATCH to a VT_UI8.
2553 *
2554 * PARAMS
2555 * pdispIn [I] Source
2556 * lcid [I] LCID for conversion
2557 * pui64Out [O] Destination
2558 *
2559 * RETURNS
2560 * Success: S_OK.
2561 * Failure: E_INVALIDARG, if the source value is invalid
2562 * DISP_E_OVERFLOW, if the value will not fit in the destination
2563 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2564 */
2565 HRESULT WINAPI VarUI8FromDisp(IDispatch* pdispIn, LCID lcid, ULONG64* pui64Out)
2566 {
2567 return VARIANT_FromDisp(pdispIn, lcid, pui64Out, VT_UI8, 0);
2568 }
2569
2570 /************************************************************************
2571 * VarUI8FromBool (OLEAUT32.437)
2572 *
2573 * Convert a VT_BOOL to a VT_UI8.
2574 *
2575 * PARAMS
2576 * boolIn [I] Source
2577 * pui64Out [O] Destination
2578 *
2579 * RETURNS
2580 * Success: S_OK.
2581 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2582 */
2583 HRESULT WINAPI VarUI8FromBool(VARIANT_BOOL boolIn, ULONG64* pui64Out)
2584 {
2585 return VarI8FromI2(boolIn, (LONG64 *)pui64Out);
2586 }
2587 /************************************************************************
2588 * VarUI8FromI1 (OLEAUT32.438)
2589 *
2590 * Convert a VT_I1 to a VT_UI8.
2591 *
2592 * PARAMS
2593 * cIn [I] Source
2594 * pui64Out [O] Destination
2595 *
2596 * RETURNS
2597 * Success: S_OK.
2598 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
2599 */
2600 HRESULT WINAPI VarUI8FromI1(signed char cIn, ULONG64* pui64Out)
2601 {
2602 return _VarUI8FromI1(cIn, pui64Out);
2603 }
2604
2605 /************************************************************************
2606 * VarUI8FromUI2 (OLEAUT32.439)
2607 *
2608 * Convert a VT_UI2 to a VT_UI8.
2609 *
2610 * PARAMS
2611 * usIn [I] Source
2612 * pui64Out [O] Destination
2613 *
2614 * RETURNS
2615 * S_OK.
2616 */
2617 HRESULT WINAPI VarUI8FromUI2(USHORT usIn, ULONG64* pui64Out)
2618 {
2619 return _VarUI8FromUI2(usIn, pui64Out);
2620 }
2621
2622 /************************************************************************
2623 * VarUI8FromUI4 (OLEAUT32.440)
2624 *
2625 * Convert a VT_UI4 to a VT_UI8.
2626 *
2627 * PARAMS
2628 * ulIn [I] Source
2629 * pui64Out [O] Destination
2630 *
2631 * RETURNS
2632 * S_OK.
2633 */
2634 HRESULT WINAPI VarUI8FromUI4(ULONG ulIn, ULONG64* pui64Out)
2635 {
2636 return _VarUI8FromUI4(ulIn, pui64Out);
2637 }
2638
2639 /************************************************************************
2640 * VarUI8FromDec (OLEAUT32.441)
2641 *
2642 * Convert a VT_DECIMAL to a VT_UI8.
2643 *
2644 * PARAMS
2645 * pDecIn [I] Source
2646 * pui64Out [O] Destination
2647 *
2648 * RETURNS
2649 * Success: S_OK.
2650 * Failure: E_INVALIDARG, if the source value is invalid
2651 * DISP_E_OVERFLOW, if the value will not fit in the destination
2652 *
2653 * NOTES
2654 * Under native Win32, if the source value has a scale of 0, its sign is
2655 * ignored, i.e. this function takes the absolute value rather than fail
2656 * with DISP_E_OVERFLOW. This bug has been fixed in Wine's implementation
2657 * (use VarAbs() on pDecIn first if you really want this behaviour).
2658 */
2659 HRESULT WINAPI VarUI8FromDec(DECIMAL *pdecIn, ULONG64* pui64Out)
2660 {
2661 if (!DEC_SCALE(pdecIn))
2662 {
2663 /* This decimal is just a 96 bit integer */
2664 if (DEC_SIGN(pdecIn) & ~DECIMAL_NEG)
2665 return E_INVALIDARG;
2666
2667 if (DEC_HI32(pdecIn))
2668 return DISP_E_OVERFLOW;
2669
2670 if (DEC_SIGN(pdecIn))
2671 {
2672 WARN("Sign would be ignored under Win32!\n");
2673 return DISP_E_OVERFLOW;
2674 }
2675
2676 *pui64Out = DEC_LO64(pdecIn);
2677 return S_OK;
2678 }
2679 else
2680 {
2681 /* Decimal contains a floating point number */
2682 HRESULT hRet;
2683 double dbl;
2684
2685 hRet = VarR8FromDec(pdecIn, &dbl);
2686 if (SUCCEEDED(hRet))
2687 hRet = VarUI8FromR8(dbl, pui64Out);
2688 return hRet;
2689 }
2690 }
2691
2692 /* R4
2693 */
2694
2695 /************************************************************************
2696 * VarR4FromUI1 (OLEAUT32.68)
2697 *
2698 * Convert a VT_UI1 to a VT_R4.
2699 *
2700 * PARAMS
2701 * bIn [I] Source
2702 * pFltOut [O] Destination
2703 *
2704 * RETURNS
2705 * S_OK.
2706 */
2707 HRESULT WINAPI VarR4FromUI1(BYTE bIn, float *pFltOut)
2708 {
2709 return _VarR4FromUI1(bIn, pFltOut);
2710 }
2711
2712 /************************************************************************
2713 * VarR4FromI2 (OLEAUT32.69)
2714 *
2715 * Convert a VT_I2 to a VT_R4.
2716 *
2717 * PARAMS
2718 * sIn [I] Source
2719 * pFltOut [O] Destination
2720 *
2721 * RETURNS
2722 * S_OK.
2723 */
2724 HRESULT WINAPI VarR4FromI2(SHORT sIn, float *pFltOut)
2725 {
2726 return _VarR4FromI2(sIn, pFltOut);
2727 }
2728
2729 /************************************************************************
2730 * VarR4FromI4 (OLEAUT32.70)
2731 *
2732 * Convert a VT_I4 to a VT_R4.
2733 *
2734 * PARAMS
2735 * sIn [I] Source
2736 * pFltOut [O] Destination
2737 *
2738 * RETURNS
2739 * S_OK.
2740 */
2741 HRESULT WINAPI VarR4FromI4(LONG lIn, float *pFltOut)
2742 {
2743 return _VarR4FromI4(lIn, pFltOut);
2744 }
2745
2746 /************************************************************************
2747 * VarR4FromR8 (OLEAUT32.71)
2748 *
2749 * Convert a VT_R8 to a VT_R4.
2750 *
2751 * PARAMS
2752 * dblIn [I] Source
2753 * pFltOut [O] Destination
2754 *
2755 * RETURNS
2756 * Success: S_OK.
2757 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2758 */
2759 HRESULT WINAPI VarR4FromR8(double dblIn, float *pFltOut)
2760 {
2761 double d = dblIn < 0.0 ? -dblIn : dblIn;
2762 if (d > R4_MAX) return DISP_E_OVERFLOW;
2763 *pFltOut = dblIn;
2764 return S_OK;
2765 }
2766
2767 /************************************************************************
2768 * VarR4FromCy (OLEAUT32.72)
2769 *
2770 * Convert a VT_CY to a VT_R4.
2771 *
2772 * PARAMS
2773 * cyIn [I] Source
2774 * pFltOut [O] Destination
2775 *
2776 * RETURNS
2777 * S_OK.
2778 */
2779 HRESULT WINAPI VarR4FromCy(CY cyIn, float *pFltOut)
2780 {
2781 *pFltOut = (double)cyIn.int64 / CY_MULTIPLIER_F;
2782 return S_OK;
2783 }
2784
2785 /************************************************************************
2786 * VarR4FromDate (OLEAUT32.73)
2787 *
2788 * Convert a VT_DATE to a VT_R4.
2789 *
2790 * PARAMS
2791 * dateIn [I] Source
2792 * pFltOut [O] Destination
2793 *
2794 * RETURNS
2795 * Success: S_OK.
2796 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination.
2797 */
2798 HRESULT WINAPI VarR4FromDate(DATE dateIn, float *pFltOut)
2799 {
2800 return VarR4FromR8(dateIn, pFltOut);
2801 }
2802
2803 /************************************************************************
2804 * VarR4FromStr (OLEAUT32.74)
2805 *
2806 * Convert a VT_BSTR to a VT_R4.
2807 *
2808 * PARAMS
2809 * strIn [I] Source
2810 * lcid [I] LCID for the conversion
2811 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
2812 * pFltOut [O] Destination
2813 *
2814 * RETURNS
2815 * Success: S_OK.
2816 * Failure: E_INVALIDARG, if strIn or pFltOut is invalid.
2817 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2818 */
2819 HRESULT WINAPI VarR4FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, float *pFltOut)
2820 {
2821 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pFltOut, VT_R4);
2822 }
2823
2824 /************************************************************************
2825 * VarR4FromDisp (OLEAUT32.75)
2826 *
2827 * Convert a VT_DISPATCH to a VT_R4.
2828 *
2829 * PARAMS
2830 * pdispIn [I] Source
2831 * lcid [I] LCID for conversion
2832 * pFltOut [O] Destination
2833 *
2834 * RETURNS
2835 * Success: S_OK.
2836 * Failure: E_INVALIDARG, if the source value is invalid
2837 * DISP_E_OVERFLOW, if the value will not fit in the destination
2838 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2839 */
2840 HRESULT WINAPI VarR4FromDisp(IDispatch* pdispIn, LCID lcid, float *pFltOut)
2841 {
2842 return VARIANT_FromDisp(pdispIn, lcid, pFltOut, VT_R4, 0);
2843 }
2844
2845 /************************************************************************
2846 * VarR4FromBool (OLEAUT32.76)
2847 *
2848 * Convert a VT_BOOL to a VT_R4.
2849 *
2850 * PARAMS
2851 * boolIn [I] Source
2852 * pFltOut [O] Destination
2853 *
2854 * RETURNS
2855 * S_OK.
2856 */
2857 HRESULT WINAPI VarR4FromBool(VARIANT_BOOL boolIn, float *pFltOut)
2858 {
2859 return VarR4FromI2(boolIn, pFltOut);
2860 }
2861
2862 /************************************************************************
2863 * VarR4FromI1 (OLEAUT32.213)
2864 *
2865 * Convert a VT_I1 to a VT_R4.
2866 *
2867 * PARAMS
2868 * cIn [I] Source
2869 * pFltOut [O] Destination
2870 *
2871 * RETURNS
2872 * Success: S_OK.
2873 * Failure: E_INVALIDARG, if the source value is invalid
2874 * DISP_E_OVERFLOW, if the value will not fit in the destination
2875 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2876 */
2877 HRESULT WINAPI VarR4FromI1(signed char cIn, float *pFltOut)
2878 {
2879 return _VarR4FromI1(cIn, pFltOut);
2880 }
2881
2882 /************************************************************************
2883 * VarR4FromUI2 (OLEAUT32.214)
2884 *
2885 * Convert a VT_UI2 to a VT_R4.
2886 *
2887 * PARAMS
2888 * usIn [I] Source
2889 * pFltOut [O] Destination
2890 *
2891 * RETURNS
2892 * Success: S_OK.
2893 * Failure: E_INVALIDARG, if the source value is invalid
2894 * DISP_E_OVERFLOW, if the value will not fit in the destination
2895 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2896 */
2897 HRESULT WINAPI VarR4FromUI2(USHORT usIn, float *pFltOut)
2898 {
2899 return _VarR4FromUI2(usIn, pFltOut);
2900 }
2901
2902 /************************************************************************
2903 * VarR4FromUI4 (OLEAUT32.215)
2904 *
2905 * Convert a VT_UI4 to a VT_R4.
2906 *
2907 * PARAMS
2908 * ulIn [I] Source
2909 * pFltOut [O] Destination
2910 *
2911 * RETURNS
2912 * Success: S_OK.
2913 * Failure: E_INVALIDARG, if the source value is invalid
2914 * DISP_E_OVERFLOW, if the value will not fit in the destination
2915 * DISP_E_TYPEMISMATCH, if the type cannot be converted
2916 */
2917 HRESULT WINAPI VarR4FromUI4(ULONG ulIn, float *pFltOut)
2918 {
2919 return _VarR4FromUI4(ulIn, pFltOut);
2920 }
2921
2922 /************************************************************************
2923 * VarR4FromDec (OLEAUT32.216)
2924 *
2925 * Convert a VT_DECIMAL to a VT_R4.
2926 *
2927 * PARAMS
2928 * pDecIn [I] Source
2929 * pFltOut [O] Destination
2930 *
2931 * RETURNS
2932 * Success: S_OK.
2933 * Failure: E_INVALIDARG, if the source value is invalid.
2934 */
2935 HRESULT WINAPI VarR4FromDec(DECIMAL* pDecIn, float *pFltOut)
2936 {
2937 BYTE scale = DEC_SCALE(pDecIn);
2938 double divisor = 1.0;
2939 double highPart;
2940
2941 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
2942 return E_INVALIDARG;
2943
2944 while (scale--)
2945 divisor *= 10.0;
2946
2947 if (DEC_SIGN(pDecIn))
2948 divisor = -divisor;
2949
2950 if (DEC_HI32(pDecIn))
2951 {
2952 highPart = (double)DEC_HI32(pDecIn) / divisor;
2953 highPart *= 4294967296.0F;
2954 highPart *= 4294967296.0F;
2955 }
2956 else
2957 highPart = 0.0;
2958
2959 *pFltOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
2960 return S_OK;
2961 }
2962
2963 /************************************************************************
2964 * VarR4FromI8 (OLEAUT32.360)
2965 *
2966 * Convert a VT_I8 to a VT_R4.
2967 *
2968 * PARAMS
2969 * ullIn [I] Source
2970 * pFltOut [O] Destination
2971 *
2972 * RETURNS
2973 * S_OK.
2974 */
2975 HRESULT WINAPI VarR4FromI8(LONG64 llIn, float *pFltOut)
2976 {
2977 return _VarR4FromI8(llIn, pFltOut);
2978 }
2979
2980 /************************************************************************
2981 * VarR4FromUI8 (OLEAUT32.361)
2982 *
2983 * Convert a VT_UI8 to a VT_R4.
2984 *
2985 * PARAMS
2986 * ullIn [I] Source
2987 * pFltOut [O] Destination
2988 *
2989 * RETURNS
2990 * S_OK.
2991 */
2992 HRESULT WINAPI VarR4FromUI8(ULONG64 ullIn, float *pFltOut)
2993 {
2994 return _VarR4FromUI8(ullIn, pFltOut);
2995 }
2996
2997 /************************************************************************
2998 * VarR4CmpR8 (OLEAUT32.316)
2999 *
3000 * Compare a VT_R4 to a VT_R8.
3001 *
3002 * PARAMS
3003 * fltLeft [I] Source
3004 * dblRight [I] Value to compare
3005 *
3006 * RETURNS
3007 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that fltLeft is less than,
3008 * equal to or greater than dblRight respectively.
3009 */
3010 HRESULT WINAPI VarR4CmpR8(float fltLeft, double dblRight)
3011 {
3012 if (fltLeft < dblRight)
3013 return VARCMP_LT;
3014 else if (fltLeft > dblRight)
3015 return VARCMP_GT;
3016 return VARCMP_EQ;
3017 }
3018
3019 /* R8
3020 */
3021
3022 /************************************************************************
3023 * VarR8FromUI1 (OLEAUT32.78)
3024 *
3025 * Convert a VT_UI1 to a VT_R8.
3026 *
3027 * PARAMS
3028 * bIn [I] Source
3029 * pDblOut [O] Destination
3030 *
3031 * RETURNS
3032 * S_OK.
3033 */
3034 HRESULT WINAPI VarR8FromUI1(BYTE bIn, double *pDblOut)
3035 {
3036 return _VarR8FromUI1(bIn, pDblOut);
3037 }
3038
3039 /************************************************************************
3040 * VarR8FromI2 (OLEAUT32.79)
3041 *
3042 * Convert a VT_I2 to a VT_R8.
3043 *
3044 * PARAMS
3045 * sIn [I] Source
3046 * pDblOut [O] Destination
3047 *
3048 * RETURNS
3049 * S_OK.
3050 */
3051 HRESULT WINAPI VarR8FromI2(SHORT sIn, double *pDblOut)
3052 {
3053 return _VarR8FromI2(sIn, pDblOut);
3054 }
3055
3056 /************************************************************************
3057 * VarR8FromI4 (OLEAUT32.80)
3058 *
3059 * Convert a VT_I4 to a VT_R8.
3060 *
3061 * PARAMS
3062 * sIn [I] Source
3063 * pDblOut [O] Destination
3064 *
3065 * RETURNS
3066 * S_OK.
3067 */
3068 HRESULT WINAPI VarR8FromI4(LONG lIn, double *pDblOut)
3069 {
3070 return _VarR8FromI4(lIn, pDblOut);
3071 }
3072
3073 /************************************************************************
3074 * VarR8FromR4 (OLEAUT32.81)
3075 *
3076 * Convert a VT_R4 to a VT_R8.
3077 *
3078 * PARAMS
3079 * fltIn [I] Source
3080 * pDblOut [O] Destination
3081 *
3082 * RETURNS
3083 * S_OK.
3084 */
3085 HRESULT WINAPI VarR8FromR4(FLOAT fltIn, double *pDblOut)
3086 {
3087 return _VarR8FromR4(fltIn, pDblOut);
3088 }
3089
3090 /************************************************************************
3091 * VarR8FromCy (OLEAUT32.82)
3092 *
3093 * Convert a VT_CY to a VT_R8.
3094 *
3095 * PARAMS
3096 * cyIn [I] Source
3097 * pDblOut [O] Destination
3098 *
3099 * RETURNS
3100 * S_OK.
3101 */
3102 HRESULT WINAPI VarR8FromCy(CY cyIn, double *pDblOut)
3103 {
3104 return _VarR8FromCy(cyIn, pDblOut);
3105 }
3106
3107 /************************************************************************
3108 * VarR8FromDate (OLEAUT32.83)
3109 *
3110 * Convert a VT_DATE to a VT_R8.
3111 *
3112 * PARAMS
3113 * dateIn [I] Source
3114 * pDblOut [O] Destination
3115 *
3116 * RETURNS
3117 * S_OK.
3118 */
3119 HRESULT WINAPI VarR8FromDate(DATE dateIn, double *pDblOut)
3120 {
3121 return _VarR8FromDate(dateIn, pDblOut);
3122 }
3123
3124 /************************************************************************
3125 * VarR8FromStr (OLEAUT32.84)
3126 *
3127 * Convert a VT_BSTR to a VT_R8.
3128 *
3129 * PARAMS
3130 * strIn [I] Source
3131 * lcid [I] LCID for the conversion
3132 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3133 * pDblOut [O] Destination
3134 *
3135 * RETURNS
3136 * Success: S_OK.
3137 * Failure: E_INVALIDARG, if strIn or pDblOut is invalid.
3138 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3139 */
3140 HRESULT WINAPI VarR8FromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, double *pDblOut)
3141 {
3142 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDblOut, VT_R8);
3143 }
3144
3145 /************************************************************************
3146 * VarR8FromDisp (OLEAUT32.85)
3147 *
3148 * Convert a VT_DISPATCH to a VT_R8.
3149 *
3150 * PARAMS
3151 * pdispIn [I] Source
3152 * lcid [I] LCID for conversion
3153 * pDblOut [O] Destination
3154 *
3155 * RETURNS
3156 * Success: S_OK.
3157 * Failure: E_INVALIDARG, if the source value is invalid
3158 * DISP_E_OVERFLOW, if the value will not fit in the destination
3159 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3160 */
3161 HRESULT WINAPI VarR8FromDisp(IDispatch* pdispIn, LCID lcid, double *pDblOut)
3162 {
3163 return VARIANT_FromDisp(pdispIn, lcid, pDblOut, VT_R8, 0);
3164 }
3165
3166 /************************************************************************
3167 * VarR8FromBool (OLEAUT32.86)
3168 *
3169 * Convert a VT_BOOL to a VT_R8.
3170 *
3171 * PARAMS
3172 * boolIn [I] Source
3173 * pDblOut [O] Destination
3174 *
3175 * RETURNS
3176 * S_OK.
3177 */
3178 HRESULT WINAPI VarR8FromBool(VARIANT_BOOL boolIn, double *pDblOut)
3179 {
3180 return VarR8FromI2(boolIn, pDblOut);
3181 }
3182
3183 /************************************************************************
3184 * VarR8FromI1 (OLEAUT32.217)
3185 *
3186 * Convert a VT_I1 to a VT_R8.
3187 *
3188 * PARAMS
3189 * cIn [I] Source
3190 * pDblOut [O] Destination
3191 *
3192 * RETURNS
3193 * Success: S_OK.
3194 * Failure: E_INVALIDARG, if the source value is invalid
3195 * DISP_E_OVERFLOW, if the value will not fit in the destination
3196 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3197 */
3198 HRESULT WINAPI VarR8FromI1(signed char cIn, double *pDblOut)
3199 {
3200 return _VarR8FromI1(cIn, pDblOut);
3201 }
3202
3203 /************************************************************************
3204 * VarR8FromUI2 (OLEAUT32.218)
3205 *
3206 * Convert a VT_UI2 to a VT_R8.
3207 *
3208 * PARAMS
3209 * usIn [I] Source
3210 * pDblOut [O] Destination
3211 *
3212 * RETURNS
3213 * Success: S_OK.
3214 * Failure: E_INVALIDARG, if the source value is invalid
3215 * DISP_E_OVERFLOW, if the value will not fit in the destination
3216 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3217 */
3218 HRESULT WINAPI VarR8FromUI2(USHORT usIn, double *pDblOut)
3219 {
3220 return _VarR8FromUI2(usIn, pDblOut);
3221 }
3222
3223 /************************************************************************
3224 * VarR8FromUI4 (OLEAUT32.219)
3225 *
3226 * Convert a VT_UI4 to a VT_R8.
3227 *
3228 * PARAMS
3229 * ulIn [I] Source
3230 * pDblOut [O] Destination
3231 *
3232 * RETURNS
3233 * Success: S_OK.
3234 * Failure: E_INVALIDARG, if the source value is invalid
3235 * DISP_E_OVERFLOW, if the value will not fit in the destination
3236 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3237 */
3238 HRESULT WINAPI VarR8FromUI4(ULONG ulIn, double *pDblOut)
3239 {
3240 return _VarR8FromUI4(ulIn, pDblOut);
3241 }
3242
3243 /************************************************************************
3244 * VarR8FromDec (OLEAUT32.220)
3245 *
3246 * Convert a VT_DECIMAL to a VT_R8.
3247 *
3248 * PARAMS
3249 * pDecIn [I] Source
3250 * pDblOut [O] Destination
3251 *
3252 * RETURNS
3253 * Success: S_OK.
3254 * Failure: E_INVALIDARG, if the source value is invalid.
3255 */
3256 HRESULT WINAPI VarR8FromDec(const DECIMAL* pDecIn, double *pDblOut)
3257 {
3258 BYTE scale = DEC_SCALE(pDecIn);
3259 double divisor = 1.0, highPart;
3260
3261 if (scale > DEC_MAX_SCALE || DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
3262 return E_INVALIDARG;
3263
3264 while (scale--)
3265 divisor *= 10;
3266
3267 if (DEC_SIGN(pDecIn))
3268 divisor = -divisor;
3269
3270 if (DEC_HI32(pDecIn))
3271 {
3272 highPart = (double)DEC_HI32(pDecIn) / divisor;
3273 highPart *= 4294967296.0F;
3274 highPart *= 4294967296.0F;
3275 }
3276 else
3277 highPart = 0.0;
3278
3279 *pDblOut = (double)DEC_LO64(pDecIn) / divisor + highPart;
3280 return S_OK;
3281 }
3282
3283 /************************************************************************
3284 * VarR8FromI8 (OLEAUT32.362)
3285 *
3286 * Convert a VT_I8 to a VT_R8.
3287 *
3288 * PARAMS
3289 * ullIn [I] Source
3290 * pDblOut [O] Destination
3291 *
3292 * RETURNS
3293 * S_OK.
3294 */
3295 HRESULT WINAPI VarR8FromI8(LONG64 llIn, double *pDblOut)
3296 {
3297 return _VarR8FromI8(llIn, pDblOut);
3298 }
3299
3300 /************************************************************************
3301 * VarR8FromUI8 (OLEAUT32.363)
3302 *
3303 * Convert a VT_UI8 to a VT_R8.
3304 *
3305 * PARAMS
3306 * ullIn [I] Source
3307 * pDblOut [O] Destination
3308 *
3309 * RETURNS
3310 * S_OK.
3311 */
3312 HRESULT WINAPI VarR8FromUI8(ULONG64 ullIn, double *pDblOut)
3313 {
3314 return _VarR8FromUI8(ullIn, pDblOut);
3315 }
3316
3317 /************************************************************************
3318 * VarR8Pow (OLEAUT32.315)
3319 *
3320 * Raise a VT_R8 to a power.
3321 *
3322 * PARAMS
3323 * dblLeft [I] Source
3324 * dblPow [I] Power to raise dblLeft by
3325 * pDblOut [O] Destination
3326 *
3327 * RETURNS
3328 * S_OK. pDblOut contains dblLeft to the power of dblRight.
3329 */
3330 HRESULT WINAPI VarR8Pow(double dblLeft, double dblPow, double *pDblOut)
3331 {
3332 *pDblOut = pow(dblLeft, dblPow);
3333 return S_OK;
3334 }
3335
3336 /************************************************************************
3337 * VarR8Round (OLEAUT32.317)
3338 *
3339 * Round a VT_R8 to a given number of decimal points.
3340 *
3341 * PARAMS
3342 * dblIn [I] Source
3343 * nDig [I] Number of decimal points to round to
3344 * pDblOut [O] Destination for rounded number
3345 *
3346 * RETURNS
3347 * Success: S_OK. pDblOut is rounded to nDig digits.
3348 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3349 *
3350 * NOTES
3351 * The native version of this function rounds using the internal
3352 * binary representation of the number. Wine uses the dutch rounding
3353 * convention, so therefore small differences can occur in the value returned.
3354 * MSDN says that you should use your own rounding function if you want
3355 * rounding to be predictable in your application.
3356 */
3357 HRESULT WINAPI VarR8Round(double dblIn, int nDig, double *pDblOut)
3358 {
3359 double scale, whole, fract;
3360
3361 if (nDig < 0)
3362 return E_INVALIDARG;
3363
3364 scale = pow(10.0, nDig);
3365
3366 dblIn *= scale;
3367 whole = dblIn < 0 ? ceil(dblIn) : floor(dblIn);
3368 fract = dblIn - whole;
3369
3370 if (fract > 0.5)
3371 dblIn = whole + 1.0;
3372 else if (fract == 0.5)
3373 dblIn = whole + fmod(whole, 2.0);
3374 else if (fract >= 0.0)
3375 dblIn = whole;
3376 else if (fract == -0.5)
3377 dblIn = whole - fmod(whole, 2.0);
3378 else if (fract > -0.5)
3379 dblIn = whole;
3380 else
3381 dblIn = whole - 1.0;
3382
3383 *pDblOut = dblIn / scale;
3384 return S_OK;
3385 }
3386
3387 /* CY
3388 */
3389
3390 /* Powers of 10 from 0..4 D.P. */
3391 static const int CY_Divisors[5] = { CY_MULTIPLIER/10000, CY_MULTIPLIER/1000,
3392 CY_MULTIPLIER/100, CY_MULTIPLIER/10, CY_MULTIPLIER };
3393
3394 /************************************************************************
3395 * VarCyFromUI1 (OLEAUT32.98)
3396 *
3397 * Convert a VT_UI1 to a VT_CY.
3398 *
3399 * PARAMS
3400 * bIn [I] Source
3401 * pCyOut [O] Destination
3402 *
3403 * RETURNS
3404 * Success: S_OK.
3405 * Failure: E_INVALIDARG, if the source value is invalid
3406 * DISP_E_OVERFLOW, if the value will not fit in the destination
3407 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3408 */
3409 HRESULT WINAPI VarCyFromUI1(BYTE bIn, CY* pCyOut)
3410 {
3411 pCyOut->int64 = (ULONG64)bIn * CY_MULTIPLIER;
3412 return S_OK;
3413 }
3414
3415 /************************************************************************
3416 * VarCyFromI2 (OLEAUT32.99)
3417 *
3418 * Convert a VT_I2 to a VT_CY.
3419 *
3420 * PARAMS
3421 * sIn [I] Source
3422 * pCyOut [O] Destination
3423 *
3424 * RETURNS
3425 * Success: S_OK.
3426 * Failure: E_INVALIDARG, if the source value is invalid
3427 * DISP_E_OVERFLOW, if the value will not fit in the destination
3428 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3429 */
3430 HRESULT WINAPI VarCyFromI2(SHORT sIn, CY* pCyOut)
3431 {
3432 pCyOut->int64 = (LONG64)sIn * CY_MULTIPLIER;
3433 return S_OK;
3434 }
3435
3436 /************************************************************************
3437 * VarCyFromI4 (OLEAUT32.100)
3438 *
3439 * Convert a VT_I4 to a VT_CY.
3440 *
3441 * PARAMS
3442 * sIn [I] Source
3443 * pCyOut [O] Destination
3444 *
3445 * RETURNS
3446 * Success: S_OK.
3447 * Failure: E_INVALIDARG, if the source value is invalid
3448 * DISP_E_OVERFLOW, if the value will not fit in the destination
3449 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3450 */
3451 HRESULT WINAPI VarCyFromI4(LONG lIn, CY* pCyOut)
3452 {
3453 pCyOut->int64 = (LONG64)lIn * CY_MULTIPLIER;
3454 return S_OK;
3455 }
3456
3457 /************************************************************************
3458 * VarCyFromR4 (OLEAUT32.101)
3459 *
3460 * Convert a VT_R4 to a VT_CY.
3461 *
3462 * PARAMS
3463 * fltIn [I] Source
3464 * pCyOut [O] Destination
3465 *
3466 * RETURNS
3467 * Success: S_OK.
3468 * Failure: E_INVALIDARG, if the source value is invalid
3469 * DISP_E_OVERFLOW, if the value will not fit in the destination
3470 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3471 */
3472 HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut)
3473 {
3474 return VarCyFromR8(fltIn, pCyOut);
3475 }
3476
3477 /************************************************************************
3478 * VarCyFromR8 (OLEAUT32.102)
3479 *
3480 * Convert a VT_R8 to a VT_CY.
3481 *
3482 * PARAMS
3483 * dblIn [I] Source
3484 * pCyOut [O] Destination
3485 *
3486 * RETURNS
3487 * Success: S_OK.
3488 * Failure: E_INVALIDARG, if the source value is invalid
3489 * DISP_E_OVERFLOW, if the value will not fit in the destination
3490 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3491 */
3492 HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut)
3493 {
3494 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
3495 /* This code gives identical results to Win32 on Intel.
3496 * Here we use fp exceptions to catch overflows when storing the value.
3497 */
3498 static const unsigned short r8_fpcontrol = 0x137f;
3499 static const double r8_multiplier = CY_MULTIPLIER_F;
3500 unsigned short old_fpcontrol, result_fpstatus;
3501
3502 /* Clear exceptions, save the old fp state and load the new state */
3503 __asm__ __volatile__( "fnclex" );
3504 __asm__ __volatile__( "fstcw %0" : "=m" (old_fpcontrol) : );
3505 __asm__ __volatile__( "fldcw %0" : : "m" (r8_fpcontrol) );
3506 /* Perform the conversion. */
3507 __asm__ __volatile__( "fldl %0" : : "m" (dblIn) );
3508 __asm__ __volatile__( "fmull %0" : : "m" (r8_multiplier) );
3509 __asm__ __volatile__( "fistpll %0" : : "m" (*pCyOut) );
3510 /* Save the resulting fp state, load the old state and clear exceptions */
3511 __asm__ __volatile__( "fstsw %0" : "=m" (result_fpstatus) : );
3512 __asm__ __volatile__( "fnclex" );
3513 __asm__ __volatile__( "fldcw %0" : : "m" (old_fpcontrol) );
3514
3515 if (result_fpstatus & 0x9) /* Overflow | Invalid */
3516 return DISP_E_OVERFLOW;
3517 #else
3518 /* This version produces slightly different results for boundary cases */
3519 if (dblIn < -922337203685477.5807 || dblIn >= 922337203685477.5807)
3520 return DISP_E_OVERFLOW;
3521 dblIn *= CY_MULTIPLIER_F;
3522 VARIANT_DutchRound(LONG64, dblIn, pCyOut->int64);
3523 #endif
3524 return S_OK;
3525 }
3526
3527 /************************************************************************
3528 * VarCyFromDate (OLEAUT32.103)
3529 *
3530 * Convert a VT_DATE to a VT_CY.
3531 *
3532 * PARAMS
3533 * dateIn [I] Source
3534 * pCyOut [O] Destination
3535 *
3536 * RETURNS
3537 * Success: S_OK.
3538 * Failure: E_INVALIDARG, if the source value is invalid
3539 * DISP_E_OVERFLOW, if the value will not fit in the destination
3540 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3541 */
3542 HRESULT WINAPI VarCyFromDate(DATE dateIn, CY* pCyOut)
3543 {
3544 return VarCyFromR8(dateIn, pCyOut);
3545 }
3546
3547 /************************************************************************
3548 * VarCyFromStr (OLEAUT32.104)
3549 *
3550 * Convert a VT_BSTR to a VT_CY.
3551 *
3552 * PARAMS
3553 * strIn [I] Source
3554 * lcid [I] LCID for the conversion
3555 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
3556 * pCyOut [O] Destination
3557 *
3558 * RETURNS
3559 * Success: S_OK.
3560 * Failure: E_INVALIDARG, if the source value is invalid
3561 * DISP_E_OVERFLOW, if the value will not fit in the destination
3562 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3563 */
3564 HRESULT WINAPI VarCyFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, CY* pCyOut)
3565 {
3566 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pCyOut, VT_CY);
3567 }
3568
3569 /************************************************************************
3570 * VarCyFromDisp (OLEAUT32.105)
3571 *
3572 * Convert a VT_DISPATCH to a VT_CY.
3573 *
3574 * PARAMS
3575 * pdispIn [I] Source
3576 * lcid [I] LCID for conversion
3577 * pCyOut [O] Destination
3578 *
3579 * RETURNS
3580 * Success: S_OK.
3581 * Failure: E_INVALIDARG, if the source value is invalid
3582 * DISP_E_OVERFLOW, if the value will not fit in the destination
3583 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3584 */
3585 HRESULT WINAPI VarCyFromDisp(IDispatch* pdispIn, LCID lcid, CY* pCyOut)
3586 {
3587 return VARIANT_FromDisp(pdispIn, lcid, pCyOut, VT_CY, 0);
3588 }
3589
3590 /************************************************************************
3591 * VarCyFromBool (OLEAUT32.106)
3592 *
3593 * Convert a VT_BOOL to a VT_CY.
3594 *
3595 * PARAMS
3596 * boolIn [I] Source
3597 * pCyOut [O] Destination
3598 *
3599 * RETURNS
3600 * Success: S_OK.
3601 * Failure: E_INVALIDARG, if the source value is invalid
3602 * DISP_E_OVERFLOW, if the value will not fit in the destination
3603 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3604 *
3605 * NOTES
3606 * While the sign of the boolean is stored in the currency, the value is
3607 * converted to either 0 or 1.
3608 */
3609 HRESULT WINAPI VarCyFromBool(VARIANT_BOOL boolIn, CY* pCyOut)
3610 {
3611 pCyOut->int64 = (LONG64)boolIn * CY_MULTIPLIER;
3612 return S_OK;
3613 }
3614
3615 /************************************************************************
3616 * VarCyFromI1 (OLEAUT32.225)
3617 *
3618 * Convert a VT_I1 to a VT_CY.
3619 *
3620 * PARAMS
3621 * cIn [I] Source
3622 * pCyOut [O] Destination
3623 *
3624 * RETURNS
3625 * Success: S_OK.
3626 * Failure: E_INVALIDARG, if the source value is invalid
3627 * DISP_E_OVERFLOW, if the value will not fit in the destination
3628 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3629 */
3630 HRESULT WINAPI VarCyFromI1(signed char cIn, CY* pCyOut)
3631 {
3632 pCyOut->int64 = (LONG64)cIn * CY_MULTIPLIER;
3633 return S_OK;
3634 }
3635
3636 /************************************************************************
3637 * VarCyFromUI2 (OLEAUT32.226)
3638 *
3639 * Convert a VT_UI2 to a VT_CY.
3640 *
3641 * PARAMS
3642 * usIn [I] Source
3643 * pCyOut [O] Destination
3644 *
3645 * RETURNS
3646 * Success: S_OK.
3647 * Failure: E_INVALIDARG, if the source value is invalid
3648 * DISP_E_OVERFLOW, if the value will not fit in the destination
3649 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3650 */
3651 HRESULT WINAPI VarCyFromUI2(USHORT usIn, CY* pCyOut)
3652 {
3653 pCyOut->int64 = (ULONG64)usIn * CY_MULTIPLIER;
3654 return S_OK;
3655 }
3656
3657 /************************************************************************
3658 * VarCyFromUI4 (OLEAUT32.227)
3659 *
3660 * Convert a VT_UI4 to a VT_CY.
3661 *
3662 * PARAMS
3663 * ulIn [I] Source
3664 * pCyOut [O] Destination
3665 *
3666 * RETURNS
3667 * Success: S_OK.
3668 * Failure: E_INVALIDARG, if the source value is invalid
3669 * DISP_E_OVERFLOW, if the value will not fit in the destination
3670 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3671 */
3672 HRESULT WINAPI VarCyFromUI4(ULONG ulIn, CY* pCyOut)
3673 {
3674 pCyOut->int64 = (ULONG64)ulIn * CY_MULTIPLIER;
3675 return S_OK;
3676 }
3677
3678 /************************************************************************
3679 * VarCyFromDec (OLEAUT32.228)
3680 *
3681 * Convert a VT_DECIMAL to a VT_CY.
3682 *
3683 * PARAMS
3684 * pdecIn [I] Source
3685 * pCyOut [O] Destination
3686 *
3687 * RETURNS
3688 * Success: S_OK.
3689 * Failure: E_INVALIDARG, if the source value is invalid
3690 * DISP_E_OVERFLOW, if the value will not fit in the destination
3691 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3692 */
3693 HRESULT WINAPI VarCyFromDec(DECIMAL* pdecIn, CY* pCyOut)
3694 {
3695 DECIMAL rounded;
3696 HRESULT hRet;
3697
3698 hRet = VarDecRound(pdecIn, 4, &rounded);
3699
3700 if (SUCCEEDED(hRet))
3701 {
3702 double d;
3703
3704 if (DEC_HI32(&rounded))
3705 return DISP_E_OVERFLOW;
3706
3707 /* Note: Without the casts this promotes to int64 which loses precision */
3708 d = (double)DEC_LO64(&rounded) / (double)CY_Divisors[DEC_SCALE(&rounded)];
3709 if (DEC_SIGN(&rounded))
3710 d = -d;
3711 return VarCyFromR8(d, pCyOut);
3712 }
3713 return hRet;
3714 }
3715
3716 /************************************************************************
3717 * VarCyFromI8 (OLEAUT32.366)
3718 *
3719 * Convert a VT_I8 to a VT_CY.
3720 *
3721 * PARAMS
3722 * ullIn [I] Source
3723 * pCyOut [O] Destination
3724 *
3725 * RETURNS
3726 * Success: S_OK.
3727 * Failure: E_INVALIDARG, if the source value is invalid
3728 * DISP_E_OVERFLOW, if the value will not fit in the destination
3729 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3730 */
3731 HRESULT WINAPI VarCyFromI8(LONG64 llIn, CY* pCyOut)
3732 {
3733 if (llIn <= (I8_MIN/CY_MULTIPLIER) || llIn >= (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3734 pCyOut->int64 = llIn * CY_MULTIPLIER;
3735 return S_OK;
3736 }
3737
3738 /************************************************************************
3739 * VarCyFromUI8 (OLEAUT32.375)
3740 *
3741 * Convert a VT_UI8 to a VT_CY.
3742 *
3743 * PARAMS
3744 * ullIn [I] Source
3745 * pCyOut [O] Destination
3746 *
3747 * RETURNS
3748 * Success: S_OK.
3749 * Failure: E_INVALIDARG, if the source value is invalid
3750 * DISP_E_OVERFLOW, if the value will not fit in the destination
3751 * DISP_E_TYPEMISMATCH, if the type cannot be converted
3752 */
3753 HRESULT WINAPI VarCyFromUI8(ULONG64 ullIn, CY* pCyOut)
3754 {
3755 if (ullIn > (I8_MAX/CY_MULTIPLIER)) return DISP_E_OVERFLOW;
3756 pCyOut->int64 = ullIn * CY_MULTIPLIER;
3757 return S_OK;
3758 }
3759
3760 /************************************************************************
3761 * VarCyAdd (OLEAUT32.299)
3762 *
3763 * Add one CY to another.
3764 *
3765 * PARAMS
3766 * cyLeft [I] Source
3767 * cyRight [I] Value to add
3768 * pCyOut [O] Destination
3769 *
3770 * RETURNS
3771 * Success: S_OK.
3772 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3773 */
3774 HRESULT WINAPI VarCyAdd(const CY cyLeft, const CY cyRight, CY* pCyOut)
3775 {
3776 double l,r;
3777 _VarR8FromCy(cyLeft, &l);
3778 _VarR8FromCy(cyRight, &r);
3779 l = l + r;
3780 return VarCyFromR8(l, pCyOut);
3781 }
3782
3783 /************************************************************************
3784 * VarCyMul (OLEAUT32.303)
3785 *
3786 * Multiply one CY by another.
3787 *
3788 * PARAMS
3789 * cyLeft [I] Source
3790 * cyRight [I] Value to multiply by
3791 * pCyOut [O] Destination
3792 *
3793 * RETURNS
3794 * Success: S_OK.
3795 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3796 */
3797 HRESULT WINAPI VarCyMul(const CY cyLeft, const CY cyRight, CY* pCyOut)
3798 {
3799 double l,r;
3800 _VarR8FromCy(cyLeft, &l);
3801 _VarR8FromCy(cyRight, &r);
3802 l = l * r;
3803 return VarCyFromR8(l, pCyOut);
3804 }
3805
3806 /************************************************************************
3807 * VarCyMulI4 (OLEAUT32.304)
3808 *
3809 * Multiply one CY by a VT_I4.
3810 *
3811 * PARAMS
3812 * cyLeft [I] Source
3813 * lRight [I] Value to multiply by
3814 * pCyOut [O] Destination
3815 *
3816 * RETURNS
3817 * Success: S_OK.
3818 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3819 */
3820 HRESULT WINAPI VarCyMulI4(const CY cyLeft, LONG lRight, CY* pCyOut)
3821 {
3822 double d;
3823
3824 _VarR8FromCy(cyLeft, &d);
3825 d = d * lRight;
3826 return VarCyFromR8(d, pCyOut);
3827 }
3828
3829 /************************************************************************
3830 * VarCySub (OLEAUT32.305)
3831 *
3832 * Subtract one CY from another.
3833 *
3834 * PARAMS
3835 * cyLeft [I] Source
3836 * cyRight [I] Value to subtract
3837 * pCyOut [O] Destination
3838 *
3839 * RETURNS
3840 * Success: S_OK.
3841 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3842 */
3843 HRESULT WINAPI VarCySub(const CY cyLeft, const CY cyRight, CY* pCyOut)
3844 {
3845 double l,r;
3846 _VarR8FromCy(cyLeft, &l);
3847 _VarR8FromCy(cyRight, &r);
3848 l = l - r;
3849 return VarCyFromR8(l, pCyOut);
3850 }
3851
3852 /************************************************************************
3853 * VarCyAbs (OLEAUT32.306)
3854 *
3855 * Convert a VT_CY into its absolute value.
3856 *
3857 * PARAMS
3858 * cyIn [I] Source
3859 * pCyOut [O] Destination
3860 *
3861 * RETURNS
3862 * Success: S_OK. pCyOut contains the absolute value.
3863 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3864 */
3865 HRESULT WINAPI VarCyAbs(const CY cyIn, CY* pCyOut)
3866 {
3867 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3868 return DISP_E_OVERFLOW;
3869
3870 pCyOut->int64 = cyIn.int64 < 0 ? -cyIn.int64 : cyIn.int64;
3871 return S_OK;
3872 }
3873
3874 /************************************************************************
3875 * VarCyFix (OLEAUT32.307)
3876 *
3877 * Return the integer part of a VT_CY.
3878 *
3879 * PARAMS
3880 * cyIn [I] Source
3881 * pCyOut [O] Destination
3882 *
3883 * RETURNS
3884 * Success: S_OK.
3885 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3886 *
3887 * NOTES
3888 * - The difference between this function and VarCyInt() is that VarCyInt() rounds
3889 * negative numbers away from 0, while this function rounds them towards zero.
3890 */
3891 HRESULT WINAPI VarCyFix(const CY cyIn, CY* pCyOut)
3892 {
3893 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3894 pCyOut->int64 *= CY_MULTIPLIER;
3895 return S_OK;
3896 }
3897
3898 /************************************************************************
3899 * VarCyInt (OLEAUT32.308)
3900 *
3901 * Return the integer part of a VT_CY.
3902 *
3903 * PARAMS
3904 * cyIn [I] Source
3905 * pCyOut [O] Destination
3906 *
3907 * RETURNS
3908 * Success: S_OK.
3909 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3910 *
3911 * NOTES
3912 * - The difference between this function and VarCyFix() is that VarCyFix() rounds
3913 * negative numbers towards 0, while this function rounds them away from zero.
3914 */
3915 HRESULT WINAPI VarCyInt(const CY cyIn, CY* pCyOut)
3916 {
3917 pCyOut->int64 = cyIn.int64 / CY_MULTIPLIER;
3918 pCyOut->int64 *= CY_MULTIPLIER;
3919
3920 if (cyIn.int64 < 0 && cyIn.int64 % CY_MULTIPLIER != 0)
3921 {
3922 pCyOut->int64 -= CY_MULTIPLIER;
3923 }
3924 return S_OK;
3925 }
3926
3927 /************************************************************************
3928 * VarCyNeg (OLEAUT32.309)
3929 *
3930 * Change the sign of a VT_CY.
3931 *
3932 * PARAMS
3933 * cyIn [I] Source
3934 * pCyOut [O] Destination
3935 *
3936 * RETURNS
3937 * Success: S_OK.
3938 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
3939 */
3940 HRESULT WINAPI VarCyNeg(const CY cyIn, CY* pCyOut)
3941 {
3942 if (cyIn.s.Hi == (int)0x80000000 && !cyIn.s.Lo)
3943 return DISP_E_OVERFLOW;
3944
3945 pCyOut->int64 = -cyIn.int64;
3946 return S_OK;
3947 }
3948
3949 /************************************************************************
3950 * VarCyRound (OLEAUT32.310)
3951 *
3952 * Change the precision of a VT_CY.
3953 *
3954 * PARAMS
3955 * cyIn [I] Source
3956 * cDecimals [I] New number of decimals to keep
3957 * pCyOut [O] Destination
3958 *
3959 * RETURNS
3960 * Success: S_OK.
3961 * Failure: E_INVALIDARG, if cDecimals is less than 0.
3962 */
3963 HRESULT WINAPI VarCyRound(const CY cyIn, int cDecimals, CY* pCyOut)
3964 {
3965 if (cDecimals < 0)
3966 return E_INVALIDARG;
3967
3968 if (cDecimals > 3)
3969 {
3970 /* Rounding to more precision than we have */
3971 *pCyOut = cyIn;
3972 return S_OK;
3973 }
3974 else
3975 {
3976 double d, div = CY_Divisors[cDecimals];
3977
3978 _VarR8FromCy(cyIn, &d);
3979 d = d * div;
3980 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3981 d = (double)pCyOut->int64 / div * CY_MULTIPLIER_F;
3982 VARIANT_DutchRound(LONGLONG, d, pCyOut->int64);
3983 return S_OK;
3984 }
3985 }
3986
3987 /************************************************************************
3988 * VarCyCmp (OLEAUT32.311)
3989 *
3990 * Compare two VT_CY values.
3991 *
3992 * PARAMS
3993 * cyLeft [I] Source
3994 * cyRight [I] Value to compare
3995 *
3996 * RETURNS
3997 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that the value to
3998 * compare is less, equal or greater than source respectively.
3999 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4000 */
4001 HRESULT WINAPI VarCyCmp(const CY cyLeft, const CY cyRight)
4002 {
4003 HRESULT hRet;
4004 CY result;
4005
4006 /* Subtract right from left, and compare the result to 0 */
4007 hRet = VarCySub(cyLeft, cyRight, &result);
4008
4009 if (SUCCEEDED(hRet))
4010 {
4011 if (result.int64 < 0)
4012 hRet = (HRESULT)VARCMP_LT;
4013 else if (result.int64 > 0)
4014 hRet = (HRESULT)VARCMP_GT;
4015 else
4016 hRet = (HRESULT)VARCMP_EQ;
4017 }
4018 return hRet;
4019 }
4020
4021 /************************************************************************
4022 * VarCyCmpR8 (OLEAUT32.312)
4023 *
4024 * Compare a VT_CY to a double
4025 *
4026 * PARAMS
4027 * cyLeft [I] Currency Source
4028 * dblRight [I] double to compare to cyLeft
4029 *
4030 * RETURNS
4031 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight is
4032 * less than, equal to or greater than cyLeft respectively.
4033 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
4034 */
4035 HRESULT WINAPI VarCyCmpR8(const CY cyLeft, double dblRight)
4036 {
4037 HRESULT hRet;
4038 CY cyRight;
4039
4040 hRet = VarCyFromR8(dblRight, &cyRight);
4041
4042 if (SUCCEEDED(hRet))
4043 hRet = VarCyCmp(cyLeft, cyRight);
4044
4045 return hRet;
4046 }
4047
4048 /************************************************************************
4049 * VarCyMulI8 (OLEAUT32.329)
4050 *
4051 * Multiply a VT_CY by a VT_I8.
4052 *
4053 * PARAMS
4054 * cyLeft [I] Source
4055 * llRight [I] Value to multiply by
4056 * pCyOut [O] Destination
4057 *
4058 * RETURNS
4059 * Success: S_OK.
4060 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4061 */
4062 HRESULT WINAPI VarCyMulI8(const CY cyLeft, LONG64 llRight, CY* pCyOut)
4063 {
4064 double d;
4065
4066 _VarR8FromCy(cyLeft, &d);
4067 d = d * (double)llRight;
4068 return VarCyFromR8(d, pCyOut);
4069 }
4070
4071 /* DECIMAL
4072 */
4073
4074 /************************************************************************
4075 * VarDecFromUI1 (OLEAUT32.190)
4076 *
4077 * Convert a VT_UI1 to a DECIMAL.
4078 *
4079 * PARAMS
4080 * bIn [I] Source
4081 * pDecOut [O] Destination
4082 *
4083 * RETURNS
4084 * S_OK.
4085 */
4086 HRESULT WINAPI VarDecFromUI1(BYTE bIn, DECIMAL* pDecOut)
4087 {
4088 return VarDecFromUI4(bIn, pDecOut);
4089 }
4090
4091 /************************************************************************
4092 * VarDecFromI2 (OLEAUT32.191)
4093 *
4094 * Convert a VT_I2 to a DECIMAL.
4095 *
4096 * PARAMS
4097 * sIn [I] Source
4098 * pDecOut [O] Destination
4099 *
4100 * RETURNS
4101 * S_OK.
4102 */
4103 HRESULT WINAPI VarDecFromI2(SHORT sIn, DECIMAL* pDecOut)
4104 {
4105 return VarDecFromI4(sIn, pDecOut);
4106 }
4107
4108 /************************************************************************
4109 * VarDecFromI4 (OLEAUT32.192)
4110 *
4111 * Convert a VT_I4 to a DECIMAL.
4112 *
4113 * PARAMS
4114 * sIn [I] Source
4115 * pDecOut [O] Destination
4116 *
4117 * RETURNS
4118 * S_OK.
4119 */
4120 HRESULT WINAPI VarDecFromI4(LONG lIn, DECIMAL* pDecOut)
4121 {
4122 DEC_HI32(pDecOut) = 0;
4123 DEC_MID32(pDecOut) = 0;
4124
4125 if (lIn < 0)
4126 {
4127 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4128 DEC_LO32(pDecOut) = -lIn;
4129 }
4130 else
4131 {
4132 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4133 DEC_LO32(pDecOut) = lIn;
4134 }
4135 return S_OK;
4136 }
4137
4138 /* internal representation of the value stored in a DECIMAL. The bytes are
4139 stored from LSB at index 0 to MSB at index 11
4140 */
4141 typedef struct DECIMAL_internal
4142 {
4143 DWORD bitsnum[3]; /* 96 significant bits, unsigned */
4144 unsigned char scale; /* number scaled * 10 ^ -(scale) */
4145 unsigned int sign : 1; /* 0 - positive, 1 - negative */
4146 } VARIANT_DI;
4147
4148 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest);
4149 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest);
4150 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to);
4151 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to);
4152 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor);
4153 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n);
4154
4155 /************************************************************************
4156 * VarDecFromR4 (OLEAUT32.193)
4157 *
4158 * Convert a VT_R4 to a DECIMAL.
4159 *
4160 * PARAMS
4161 * fltIn [I] Source
4162 * pDecOut [O] Destination
4163 *
4164 * RETURNS
4165 * S_OK.
4166 */
4167 HRESULT WINAPI VarDecFromR4(FLOAT fltIn, DECIMAL* pDecOut)
4168 {
4169 VARIANT_DI di;
4170 HRESULT hres;
4171
4172 hres = VARIANT_DI_FromR4(fltIn, &di);
4173 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4174 return hres;
4175 }
4176
4177 /************************************************************************
4178 * VarDecFromR8 (OLEAUT32.194)
4179 *
4180 * Convert a VT_R8 to a DECIMAL.
4181 *
4182 * PARAMS
4183 * dblIn [I] Source
4184 * pDecOut [O] Destination
4185 *
4186 * RETURNS
4187 * S_OK.
4188 */
4189 HRESULT WINAPI VarDecFromR8(double dblIn, DECIMAL* pDecOut)
4190 {
4191 VARIANT_DI di;
4192 HRESULT hres;
4193
4194 hres = VARIANT_DI_FromR8(dblIn, &di);
4195 if (hres == S_OK) VARIANT_DecFromDI(&di, pDecOut);
4196 return hres;
4197 }
4198
4199 /************************************************************************
4200 * VarDecFromDate (OLEAUT32.195)
4201 *
4202 * Convert a VT_DATE to a DECIMAL.
4203 *
4204 * PARAMS
4205 * dateIn [I] Source
4206 * pDecOut [O] Destination
4207 *
4208 * RETURNS
4209 * S_OK.
4210 */
4211 HRESULT WINAPI VarDecFromDate(DATE dateIn, DECIMAL* pDecOut)
4212 {
4213 return VarDecFromR8(dateIn, pDecOut);
4214 }
4215
4216 /************************************************************************
4217 * VarDecFromCy (OLEAUT32.196)
4218 *
4219 * Convert a VT_CY to a DECIMAL.
4220 *
4221 * PARAMS
4222 * cyIn [I] Source
4223 * pDecOut [O] Destination
4224 *
4225 * RETURNS
4226 * S_OK.
4227 */
4228 HRESULT WINAPI VarDecFromCy(CY cyIn, DECIMAL* pDecOut)
4229 {
4230 DEC_HI32(pDecOut) = 0;
4231
4232 /* Note: This assumes 2s complement integer representation */
4233 if (cyIn.s.Hi & 0x80000000)
4234 {
4235 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,4);
4236 DEC_LO64(pDecOut) = -cyIn.int64;
4237 }
4238 else
4239 {
4240 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,4);
4241 DEC_MID32(pDecOut) = cyIn.s.Hi;
4242 DEC_LO32(pDecOut) = cyIn.s.Lo;
4243 }
4244 return S_OK;
4245 }
4246
4247 /************************************************************************
4248 * VarDecFromStr (OLEAUT32.197)
4249 *
4250 * Convert a VT_BSTR to a DECIMAL.
4251 *
4252 * PARAMS
4253 * strIn [I] Source
4254 * lcid [I] LCID for the conversion
4255 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
4256 * pDecOut [O] Destination
4257 *
4258 * RETURNS
4259 * Success: S_OK.
4260 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4261 */
4262 HRESULT WINAPI VarDecFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DECIMAL* pDecOut)
4263 {
4264 return VARIANT_NumberFromBstr(strIn, lcid, dwFlags, pDecOut, VT_DECIMAL);
4265 }
4266
4267 /************************************************************************
4268 * VarDecFromDisp (OLEAUT32.198)
4269 *
4270 * Convert a VT_DISPATCH to a DECIMAL.
4271 *
4272 * PARAMS
4273 * pdispIn [I] Source
4274 * lcid [I] LCID for conversion
4275 * pDecOut [O] Destination
4276 *
4277 * RETURNS
4278 * Success: S_OK.
4279 * Failure: DISP_E_TYPEMISMATCH, if the type cannot be converted
4280 */
4281 HRESULT WINAPI VarDecFromDisp(IDispatch* pdispIn, LCID lcid, DECIMAL* pDecOut)
4282 {
4283 return VARIANT_FromDisp(pdispIn, lcid, pDecOut, VT_DECIMAL, 0);
4284 }
4285
4286 /************************************************************************
4287 * VarDecFromBool (OLEAUT32.199)
4288 *
4289 * Convert a VT_BOOL to a DECIMAL.
4290 *
4291 * PARAMS
4292 * bIn [I] Source
4293 * pDecOut [O] Destination
4294 *
4295 * RETURNS
4296 * S_OK.
4297 *
4298 * NOTES
4299 * The value is converted to either 0 (if bIn is FALSE) or -1 (TRUE).
4300 */
4301 HRESULT WINAPI VarDecFromBool(VARIANT_BOOL bIn, DECIMAL* pDecOut)
4302 {
4303 DEC_HI32(pDecOut) = 0;
4304 DEC_MID32(pDecOut) = 0;
4305 if (bIn)
4306 {
4307 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4308 DEC_LO32(pDecOut) = 1;
4309 }
4310 else
4311 {
4312 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4313 DEC_LO32(pDecOut) = 0;
4314 }
4315 return S_OK;
4316 }
4317
4318 /************************************************************************
4319 * VarDecFromI1 (OLEAUT32.241)
4320 *
4321 * Convert a VT_I1 to a DECIMAL.
4322 *
4323 * PARAMS
4324 * cIn [I] Source
4325 * pDecOut [O] Destination
4326 *
4327 * RETURNS
4328 * S_OK.
4329 */
4330 HRESULT WINAPI VarDecFromI1(signed char cIn, DECIMAL* pDecOut)
4331 {
4332 return VarDecFromI4(cIn, pDecOut);
4333 }
4334
4335 /************************************************************************
4336 * VarDecFromUI2 (OLEAUT32.242)
4337 *
4338 * Convert a VT_UI2 to a DECIMAL.
4339 *
4340 * PARAMS
4341 * usIn [I] Source
4342 * pDecOut [O] Destination
4343 *
4344 * RETURNS
4345 * S_OK.
4346 */
4347 HRESULT WINAPI VarDecFromUI2(USHORT usIn, DECIMAL* pDecOut)
4348 {
4349 return VarDecFromUI4(usIn, pDecOut);
4350 }
4351
4352 /************************************************************************
4353 * VarDecFromUI4 (OLEAUT32.243)
4354 *
4355 * Convert a VT_UI4 to a DECIMAL.
4356 *
4357 * PARAMS
4358 * ulIn [I] Source
4359 * pDecOut [O] Destination
4360 *
4361 * RETURNS
4362 * S_OK.
4363 */
4364 HRESULT WINAPI VarDecFromUI4(ULONG ulIn, DECIMAL* pDecOut)
4365 {
4366 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4367 DEC_HI32(pDecOut) = 0;
4368 DEC_MID32(pDecOut) = 0;
4369 DEC_LO32(pDecOut) = ulIn;
4370 return S_OK;
4371 }
4372
4373 /************************************************************************
4374 * VarDecFromI8 (OLEAUT32.374)
4375 *
4376 * Convert a VT_I8 to a DECIMAL.
4377 *
4378 * PARAMS
4379 * llIn [I] Source
4380 * pDecOut [O] Destination
4381 *
4382 * RETURNS
4383 * S_OK.
4384 */
4385 HRESULT WINAPI VarDecFromI8(LONG64 llIn, DECIMAL* pDecOut)
4386 {
4387 PULARGE_INTEGER pLi = (PULARGE_INTEGER)&llIn;
4388
4389 DEC_HI32(pDecOut) = 0;
4390
4391 /* Note: This assumes 2s complement integer representation */
4392 if (pLi->u.HighPart & 0x80000000)
4393 {
4394 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_NEG,0);
4395 DEC_LO64(pDecOut) = -pLi->QuadPart;
4396 }
4397 else
4398 {
4399 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4400 DEC_MID32(pDecOut) = pLi->u.HighPart;
4401 DEC_LO32(pDecOut) = pLi->u.LowPart;
4402 }
4403 return S_OK;
4404 }
4405
4406 /************************************************************************
4407 * VarDecFromUI8 (OLEAUT32.375)
4408 *
4409 * Convert a VT_UI8 to a DECIMAL.
4410 *
4411 * PARAMS
4412 * ullIn [I] Source
4413 * pDecOut [O] Destination
4414 *
4415 * RETURNS
4416 * S_OK.
4417 */
4418 HRESULT WINAPI VarDecFromUI8(ULONG64 ullIn, DECIMAL* pDecOut)
4419 {
4420 DEC_SIGNSCALE(pDecOut) = SIGNSCALE(DECIMAL_POS,0);
4421 DEC_HI32(pDecOut) = 0;
4422 DEC_LO64(pDecOut) = ullIn;
4423 return S_OK;
4424 }
4425
4426 /* Make two DECIMALS the same scale; used by math functions below */
4427 static HRESULT VARIANT_DecScale(const DECIMAL** ppDecLeft,
4428 const DECIMAL** ppDecRight,
4429 DECIMAL pDecOut[2])
4430 {
4431 static DECIMAL scaleFactor;
4432 unsigned char remainder;
4433 DECIMAL decTemp;
4434 VARIANT_DI di;
4435 int scaleAmount, i;
4436
4437 if (DEC_SIGN(*ppDecLeft) & ~DECIMAL_NEG || DEC_SIGN(*ppDecRight) & ~DECIMAL_NEG)
4438 return E_INVALIDARG;
4439
4440 DEC_LO32(&scaleFactor) = 10;
4441
4442 i = scaleAmount = DEC_SCALE(*ppDecLeft) - DEC_SCALE(*ppDecRight);
4443
4444 if (!scaleAmount)
4445 return S_OK; /* Same scale */
4446
4447 if (scaleAmount > 0)
4448 {
4449 decTemp = *(*ppDecRight); /* Left is bigger - scale the right hand side */
4450 *ppDecRight = &pDecOut[0];
4451 }
4452 else
4453 {
4454 decTemp = *(*ppDecLeft); /* Right is bigger - scale the left hand side */
4455 *ppDecLeft = &pDecOut[0];
4456 i = -scaleAmount;
4457 }
4458
4459 /* Multiply up the value to be scaled by the correct amount (if possible) */
4460 while (i > 0 && SUCCEEDED(VarDecMul(&decTemp, &scaleFactor, &pDecOut[0])))
4461 {
4462 decTemp = pDecOut[0];
4463 i--;
4464 }
4465
4466 if (!i)
4467 {
4468 DEC_SCALE(&pDecOut[0]) += (scaleAmount > 0) ? scaleAmount : (-scaleAmount);
4469 return S_OK; /* Same scale */
4470 }
4471
4472 /* Scaling further not possible, reduce accuracy of other argument */
4473 pDecOut[0] = decTemp;
4474 if (scaleAmount > 0)
4475 {
4476 DEC_SCALE(&pDecOut[0]) += scaleAmount - i;
4477 VARIANT_DIFromDec(*ppDecLeft, &di);
4478 *ppDecLeft = &pDecOut[1];
4479 }
4480 else
4481 {
4482 DEC_SCALE(&pDecOut[0]) += (-scaleAmount) - i;
4483 VARIANT_DIFromDec(*ppDecRight, &di);
4484 *ppDecRight = &pDecOut[1];
4485 }
4486
4487 di.scale -= i;
4488 remainder = 0;
4489 while (i-- > 0 && !VARIANT_int_iszero(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD)))
4490 {
4491 remainder = VARIANT_int_divbychar(di.bitsnum, sizeof(di.bitsnum)/sizeof(DWORD), 10);
4492 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4493 }
4494
4495 /* round up the result - native oleaut32 does this */
4496 if (remainder >= 5) {
4497 for (remainder = 1, i = 0; i < sizeof(di.bitsnum)/sizeof(DWORD) && remainder; i++) {
4498 ULONGLONG digit = di.bitsnum[i] + 1;
4499 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4500 di.bitsnum[i] = digit & 0xFFFFFFFF;
4501 }
4502 }
4503
4504 VARIANT_DecFromDI(&di, &pDecOut[1]);
4505 return S_OK;
4506 }
4507
4508 /* Add two unsigned 32 bit values with overflow */
4509 static ULONG VARIANT_Add(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4510 {
4511 ULARGE_INTEGER ul64;
4512
4513 ul64.QuadPart = (ULONG64)ulLeft + (ULONG64)ulRight + (ULONG64)*pulHigh;
4514 *pulHigh = ul64.u.HighPart;
4515 return ul64.u.LowPart;
4516 }
4517
4518 /* Subtract two unsigned 32 bit values with underflow */
4519 static ULONG VARIANT_Sub(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4520 {
4521 BOOL invert = FALSE;
4522 ULARGE_INTEGER ul64;
4523
4524 ul64.QuadPart = (LONG64)ulLeft - (ULONG64)ulRight;
4525 if (ulLeft < ulRight)
4526 invert = TRUE;
4527
4528 if (ul64.QuadPart > (ULONG64)*pulHigh)
4529 ul64.QuadPart -= (ULONG64)*pulHigh;
4530 else
4531 {
4532 ul64.QuadPart -= (ULONG64)*pulHigh;
4533 invert = TRUE;
4534 }
4535 if (invert)
4536 ul64.u.HighPart = -ul64.u.HighPart ;
4537
4538 *pulHigh = ul64.u.HighPart;
4539 return ul64.u.LowPart;
4540 }
4541
4542 /* Multiply two unsigned 32 bit values with overflow */
4543 static ULONG VARIANT_Mul(ULONG ulLeft, ULONG ulRight, ULONG* pulHigh)
4544 {
4545 ULARGE_INTEGER ul64;
4546
4547 ul64.QuadPart = (ULONG64)ulLeft * (ULONG64)ulRight + (ULONG64)*pulHigh;
4548 *pulHigh = ul64.u.HighPart;
4549 return ul64.u.LowPart;
4550 }
4551
4552 /* Compare two decimals that have the same scale */
4553 static inline int VARIANT_DecCmp(const DECIMAL *pDecLeft, const DECIMAL *pDecRight)
4554 {
4555 if ( DEC_HI32(pDecLeft) < DEC_HI32(pDecRight) ||
4556 (DEC_HI32(pDecLeft) <= DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) < DEC_LO64(pDecRight)))
4557 return -1;
4558 else if (DEC_HI32(pDecLeft) == DEC_HI32(pDecRight) && DEC_LO64(pDecLeft) == DEC_LO64(pDecRight))
4559 return 0;
4560 return 1;
4561 }
4562
4563 /************************************************************************
4564 * VarDecAdd (OLEAUT32.177)
4565 *
4566 * Add one DECIMAL to another.
4567 *
4568 * PARAMS
4569 * pDecLeft [I] Source
4570 * pDecRight [I] Value to add
4571 * pDecOut [O] Destination
4572 *
4573 * RETURNS
4574 * Success: S_OK.
4575 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
4576 */
4577 HRESULT WINAPI VarDecAdd(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
4578 {
4579 HRESULT hRet;
4580 DECIMAL scaled[2];
4581
4582 hRet = VARIANT_DecScale(&pDecLeft, &pDecRight, scaled);
4583
4584 if (SUCCEEDED(hRet))
4585 {
4586 /* Our decimals now have the same scale, we can add them as 96 bit integers */
4587 ULONG overflow = 0;
4588 BYTE sign = DECIMAL_POS;
4589 int cmp;
4590
4591 /* Correct for the sign of the result */
4592 if (DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4593 {
4594 /* -x + -y : Negative */
4595 sign = DECIMAL_NEG;
4596 goto VarDecAdd_AsPositive;
4597 }
4598 else if (DEC_SIGN(pDecLeft) && !DEC_SIGN(pDecRight))
4599 {
4600 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4601
4602 /* -x + y : Negative if x > y */
4603 if (cmp > 0)
4604 {
4605 sign = DECIMAL_NEG;
4606 VarDecAdd_AsNegative:
4607 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4608 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4609 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4610 }
4611 else
4612 {
4613 VarDecAdd_AsInvertedNegative:
4614 DEC_LO32(pDecOut) = VARIANT_Sub(DEC_LO32(pDecRight), DEC_LO32(pDecLeft), &overflow);
4615 DEC_MID32(pDecOut) = VARIANT_Sub(DEC_MID32(pDecRight), DEC_MID32(pDecLeft), &overflow);
4616 DEC_HI32(pDecOut) = VARIANT_Sub(DEC_HI32(pDecRight), DEC_HI32(pDecLeft), &overflow);
4617 }
4618 }
4619 else if (!DEC_SIGN(pDecLeft) && DEC_SIGN(pDecRight))
4620 {
4621 cmp = VARIANT_DecCmp(pDecLeft, pDecRight);
4622
4623 /* x + -y : Negative if x <= y */
4624 if (cmp <= 0)
4625 {
4626 sign = DECIMAL_NEG;
4627 goto VarDecAdd_AsInvertedNegative;
4628 }
4629 goto VarDecAdd_AsNegative;
4630 }
4631 else
4632 {
4633 /* x + y : Positive */
4634 VarDecAdd_AsPositive:
4635 DEC_LO32(pDecOut) = VARIANT_Add(DEC_LO32(pDecLeft), DEC_LO32(pDecRight), &overflow);
4636 DEC_MID32(pDecOut) = VARIANT_Add(DEC_MID32(pDecLeft), DEC_MID32(pDecRight), &overflow);
4637 DEC_HI32(pDecOut) = VARIANT_Add(DEC_HI32(pDecLeft), DEC_HI32(pDecRight), &overflow);
4638 }
4639
4640 if (overflow)
4641 return DISP_E_OVERFLOW; /* overflowed */
4642
4643 DEC_SCALE(pDecOut) = DEC_SCALE(pDecLeft);
4644 DEC_SIGN(pDecOut) = sign;
4645 }
4646 return hRet;
4647 }
4648
4649 /* translate from external DECIMAL format into an internal representation */
4650 static void VARIANT_DIFromDec(const DECIMAL * from, VARIANT_DI * to)
4651 {
4652 to->scale = DEC_SCALE(from);
4653 to->sign = DEC_SIGN(from) ? 1 : 0;
4654
4655 to->bitsnum[0] = DEC_LO32(from);
4656 to->bitsnum[1] = DEC_MID32(from);
4657 to->bitsnum[2] = DEC_HI32(from);
4658 }
4659
4660 static void VARIANT_DecFromDI(const VARIANT_DI * from, DECIMAL * to)
4661 {
4662 if (from->sign) {
4663 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_NEG, from->scale);
4664 } else {
4665 DEC_SIGNSCALE(to) = SIGNSCALE(DECIMAL_POS, from->scale);
4666 }
4667
4668 DEC_LO32(to) = from->bitsnum[0];
4669 DEC_MID32(to) = from->bitsnum[1];
4670 DEC_HI32(to) = from->bitsnum[2];
4671 }
4672
4673 /* clear an internal representation of a DECIMAL */
4674 static void VARIANT_DI_clear(VARIANT_DI * i)
4675 {
4676 memset(i, 0, sizeof(VARIANT_DI));
4677 }
4678
4679 /* divide the (unsigned) number stored in p (LSB) by a byte value (<= 0xff). Any nonzero
4680 size is supported. The value in p is replaced by the quotient of the division, and
4681 the remainder is returned as a result. This routine is most often used with a divisor
4682 of 10 in order to scale up numbers, and in the DECIMAL->string conversion.
4683 */
4684 static unsigned char VARIANT_int_divbychar(DWORD * p, unsigned int n, unsigned char divisor)
4685 {
4686 if (divisor == 0) {
4687 /* division by 0 */
4688 return 0xFF;
4689 } else if (divisor == 1) {
4690 /* dividend remains unchanged */
4691 return 0;
4692 } else {
4693 unsigned char remainder = 0;
4694 ULONGLONG iTempDividend;
4695 signed int i;
4696
4697 for (i = n - 1; i >= 0 && !p[i]; i--); /* skip leading zeros */
4698 for (; i >= 0; i--) {
4699 iTempDividend = ((ULONGLONG)remainder << 32) + p[i];
4700 remainder = iTempDividend % divisor;
4701 p[i] = iTempDividend / divisor;
4702 }
4703
4704 return remainder;
4705 }
4706 }
4707
4708 /* check to test if encoded number is a zero. Returns 1 if zero, 0 for nonzero */
4709 static BOOL VARIANT_int_iszero(const DWORD * p, unsigned int n)
4710 {
4711 for (; n > 0; n--) if (*p++ != 0) return FALSE;
4712 return TRUE;
4713 }
4714
4715 /* multiply two DECIMALS, without changing either one, and place result in third
4716 parameter. Result is normalized when scale is > 0. Attempts to remove significant
4717 digits when scale > 0 in order to fit an overflowing result. Final overflow
4718 flag is returned.
4719 */
4720 static int VARIANT_DI_mul(const VARIANT_DI * a, const VARIANT_DI * b, VARIANT_DI * result)
4721 {
4722 BOOL r_overflow = FALSE;
4723 DWORD running[6];
4724 signed int mulstart;
4725
4726 VARIANT_DI_clear(result);
4727 result->sign = (a->sign ^ b->sign) ? 1 : 0;
4728
4729 /* Multiply 128-bit operands into a (max) 256-bit result. The scale
4730 of the result is formed by adding the scales of the operands.
4731 */
4732 result->scale = a->scale + b->scale;
4733 memset(running, 0, sizeof(running));
4734
4735 /* count number of leading zero-bytes in operand A */
4736 for (mulstart = sizeof(a->bitsnum)/sizeof(DWORD) - 1; mulstart >= 0 && !a->bitsnum[mulstart]; mulstart--);
4737 if (mulstart < 0) {
4738 /* result is 0, because operand A is 0 */
4739 result->scale = 0;
4740 result->sign = 0;
4741 } else {
4742 unsigned char remainder = 0;
4743 int iA;
4744
4745 /* perform actual multiplication */
4746 for (iA = 0; iA <= mulstart; iA++) {
4747 ULONG iOverflowMul;
4748 int iB;
4749
4750 for (iOverflowMul = 0, iB = 0; iB < sizeof(b->bitsnum)/sizeof(DWORD); iB++) {
4751 ULONG iRV;
4752 int iR;
4753
4754 iRV = VARIANT_Mul(b->bitsnum[iB], a->bitsnum[iA], &iOverflowMul);
4755 iR = iA + iB;
4756 do {
4757 running[iR] = VARIANT_Add(running[iR], 0, &iRV);
4758 iR++;
4759 } while (iRV);
4760 }
4761 }
4762
4763 /* Too bad - native oleaut does not do this, so we should not either */
4764 #if 0
4765 /* While the result is divisible by 10, and the scale > 0, divide by 10.
4766 This operation should not lose significant digits, and gives an
4767 opportunity to reduce the possibility of overflows in future
4768 operations issued by the application.
4769 */
4770 while (result->scale > 0) {
4771 memcpy(quotient, running, sizeof(quotient));
4772 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4773 if (remainder > 0) break;
4774 memcpy(running, quotient, sizeof(quotient));
4775 result->scale--;
4776 }
4777 #endif
4778 /* While the 256-bit result overflows, and the scale > 0, divide by 10.
4779 This operation *will* lose significant digits of the result because
4780 all the factors of 10 were consumed by the previous operation.
4781 */
4782 while (result->scale > 0 && !VARIANT_int_iszero(
4783 running + sizeof(result->bitsnum) / sizeof(DWORD),
4784 (sizeof(running) - sizeof(result->bitsnum)) / sizeof(DWORD))) {
4785
4786 remainder = VARIANT_int_divbychar(running, sizeof(running) / sizeof(DWORD), 10);
4787 if (remainder > 0) WARN("losing significant digits (remainder %u)...\n", remainder);
4788 result->scale--;
4789 }
4790
4791 /* round up the result - native oleaut32 does this */
4792 if (remainder >= 5) {
4793 unsigned int i;
4794 for (remainder = 1, i = 0; i < sizeof(running)/sizeof(DWORD) && remainder; i++) {
4795 ULONGLONG digit = running[i] + 1;
4796 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
4797 running[i] = digit & 0xFFFFFFFF;
4798 }
4799 }
4800
4801 /* Signal overflow if scale == 0 and 256-bit result still overflows,
4802 and copy result bits into result structure
4803 */
4804 r_overflow = !VARIANT_int_iszero(
4805 running + sizeof(result->bitsnum)/sizeof(DWORD),
4806 (sizeof(running) - sizeof(result->bitsnum))/sizeof(DWORD));
4807 memcpy(result->bitsnum, running, sizeof(result->bitsnum));
4808 }
4809 return r_overflow;
4810 }
4811
4812 /* cast DECIMAL into string. Any scale should be handled properly. en_US locale is
4813 hardcoded (period for decimal separator, dash as negative sign). Returns TRUE for
4814 success, FALSE if insufficient space in output buffer.
4815 */
4816 static BOOL VARIANT_DI_tostringW(const VARIANT_DI * a, WCHAR * s, unsigned int n)
4817 {
4818 BOOL overflow = FALSE;
4819 DWORD quotient[3];
4820 unsigned char remainder;
4821 unsigned int i;
4822
4823 /* place negative sign */
4824 if (!VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD)) && a->sign) {
4825 if (n > 0) {
4826 *s++ = '-';
4827 n--;
4828 }
4829 else overflow = TRUE;
4830 }
4831
4832 /* prepare initial 0 */
4833 if (!overflow) {
4834 if (n >= 2) {
4835 s[0] = '0';
4836 s[1] = '\0';
4837 } else overflow = TRUE;
4838 }
4839
4840 i = 0;
4841 memcpy(quotient, a->bitsnum, sizeof(a->bitsnum));
4842 while (!overflow && !VARIANT_int_iszero(quotient, sizeof(quotient) / sizeof(DWORD))) {
4843 remainder = VARIANT_int_divbychar(quotient, sizeof(quotient) / sizeof(DWORD), 10);
4844 if (i + 2 > n) {
4845 overflow = TRUE;
4846 } else {
4847 s[i++] = '0' + remainder;
4848 s[i] = '\0';
4849 }
4850 }
4851
4852 if (!overflow && !VARIANT_int_iszero(a->bitsnum, sizeof(a->bitsnum) / sizeof(DWORD))) {
4853
4854 /* reverse order of digits */
4855 WCHAR * x = s; WCHAR * y = s + i - 1;
4856 while (x < y) {
4857 *x ^= *y;
4858 *y ^= *x;
4859 *x++ ^= *y--;
4860 }
4861
4862 /* check for decimal point. "i" now has string length */
4863 if (i <= a->scale) {
4864 unsigned int numzeroes = a->scale + 1 - i;
4865 if (i + 1 + numzeroes >= n) {
4866 overflow = TRUE;
4867 } else {
4868 memmove(s + numzeroes, s, (i + 1) * sizeof(WCHAR));
4869 i += numzeroes;
4870 while (numzeroes > 0) {
4871 s[--numzeroes] = '0';
4872 }
4873 }
4874 }
4875
4876 /* place decimal point */
4877 if (a->scale > 0) {
4878 unsigned int periodpos = i - a->scale;
4879 if (i + 2 >= n) {
4880 overflow = TRUE;
4881 } else {
4882 memmove(s + periodpos + 1, s + periodpos, (i + 1 - periodpos) * sizeof(WCHAR));
4883 s[periodpos] = '.'; i++;
4884
4885 /* remove extra zeros at the end, if any */
4886 while (s[i - 1] == '0') s[--i] = '\0';
4887 if (s[i - 1] == '.') s[--i] = '\0';
4888 }
4889 }
4890 }
4891
4892 return !overflow;
4893 }
4894
4895 /* shift the bits of a DWORD array to the left. p[0] is assumed LSB */
4896 static void VARIANT_int_shiftleft(DWORD * p, unsigned int n, unsigned int shift)
4897 {
4898 DWORD shifted;
4899 unsigned int i;
4900
4901 /* shift whole DWORDs to the left */
4902 while (shift >= 32)
4903 {
4904 memmove(p + 1, p, (n - 1) * sizeof(DWORD));
4905 *p = 0; shift -= 32;
4906 }
4907
4908 /* shift remainder (1..31 bits) */
4909 shifted = 0;
4910 if (shift > 0) for (i = 0; i < n; i++)
4911 {
4912 DWORD b;
4913 b = p[i] >> (32 - shift);
4914 p[i] = (p[i] << shift) | shifted;
4915 shifted = b;
4916 }
4917 }
4918
4919 /* add the (unsigned) numbers stored in two DWORD arrays with LSB at index 0.
4920 Value at v is incremented by the value at p. Any size is supported, provided
4921 that v is not shorter than p. Any unapplied carry is returned as a result.
4922 */
4923 static unsigned char VARIANT_int_add(DWORD * v, unsigned int nv, const DWORD * p,
4924 unsigned int np)
4925 {
4926 unsigned char carry = 0;
4927
4928 if (nv >= np) {
4929 ULONGLONG sum;
4930 unsigned int i;
4931
4932 for (i = 0; i < np; i++) {
4933 sum = (ULONGLONG)v[i]
4934 + (ULONGLONG)p[i]
4935 + (ULONGLONG)carry;
4936 v[i] = sum & 0xffffffff;
4937 carry = sum >> 32;
4938 }
4939 for (; i < nv && carry; i++) {
4940 sum = (ULONGLONG)v[i]
4941 + (ULONGLONG)carry;
4942 v[i] = sum & 0xffffffff;
4943 carry = sum >> 32;
4944 }
4945 }
4946 return carry;
4947 }
4948
4949 /* perform integral division with operand p as dividend. Parameter n indicates
4950 number of available DWORDs in divisor p, but available space in p must be
4951 actually at least 2 * n DWORDs, because the remainder of the integral
4952 division is built in the next n DWORDs past the start of the quotient. This
4953 routine replaces the dividend in p with the quotient, and appends n
4954 additional DWORDs for the remainder.
4955
4956 Thanks to Lee & Mark Atkinson for their book _Using_C_ (my very first book on
4957 C/C++ :-) where the "longhand binary division" algorithm was exposed for the
4958 source code to the VLI (Very Large Integer) division operator. This algorithm
4959 was then heavily modified by me (Alex Villacis Lasso) in order to handle
4960 variably-scaled integers such as the MS DECIMAL representation.
4961 */
4962 static void VARIANT_int_div(DWORD * p, unsigned int n, const DWORD * divisor,
4963 unsigned int dn)
4964 {
4965 unsigned int i;
4966 DWORD tempsub[8];
4967 DWORD * negdivisor = tempsub + n;
4968
4969 /* build 2s-complement of divisor */
4970 for (i = 0; i < n; i++) negdivisor[i] = (i < dn) ? ~divisor[i] : 0xFFFFFFFF;
4971 p[n] = 1;
4972 VARIANT_int_add(negdivisor, n, p + n, 1);
4973 memset(p + n, 0, n * sizeof(DWORD));
4974
4975 /* skip all leading zero DWORDs in quotient */
4976 for (i = 0; i < n && !p[n - 1]; i++) VARIANT_int_shiftleft(p, n, 32);
4977 /* i is now number of DWORDs left to process */
4978 for (i <<= 5; i < (n << 5); i++) {
4979 VARIANT_int_shiftleft(p, n << 1, 1); /* shl quotient+remainder */
4980
4981 /* trial subtraction */
4982 memcpy(tempsub, p + n, n * sizeof(DWORD));
4983 VARIANT_int_add(tempsub, n, negdivisor, n);
4984
4985 /* check whether result of subtraction was negative */
4986 if ((tempsub[n - 1] & 0x80000000) == 0) {
4987 memcpy(p + n, tempsub, n * sizeof(DWORD));
4988 p[0] |= 1;
4989 }
4990 }
4991 }
4992
4993 /* perform integral multiplication by a byte operand. Used for scaling by 10 */
4994 static unsigned char VARIANT_int_mulbychar(DWORD * p, unsigned int n, unsigned char m)
4995 {
4996 unsigned int i;
4997 ULONG iOverflowMul;
4998
4999 for (iOverflowMul = 0, i = 0; i < n; i++)
5000 p[i] = VARIANT_Mul(p[i], m, &iOverflowMul);
5001 return (unsigned char)iOverflowMul;
5002 }
5003
5004 /* increment value in A by the value indicated in B, with scale adjusting.
5005 Modifies parameters by adjusting scales. Returns 0 if addition was
5006 successful, nonzero if a parameter underflowed before it could be
5007 successfully used in the addition.
5008 */
5009 static int VARIANT_int_addlossy(
5010 DWORD * a, int * ascale, unsigned int an,
5011 DWORD * b, int * bscale, unsigned int bn)
5012 {
5013 int underflow = 0;
5014
5015 if (VARIANT_int_iszero(a, an)) {
5016 /* if A is zero, copy B into A, after removing digits */
5017 while (bn > an && !VARIANT_int_iszero(b + an, bn - an)) {
5018 VARIANT_int_divbychar(b, bn, 10);
5019 (*bscale)--;
5020 }
5021 memcpy(a, b, an * sizeof(DWORD));
5022 *ascale = *bscale;
5023 } else if (!VARIANT_int_iszero(b, bn)) {
5024 unsigned int tn = an + 1;
5025 DWORD t[5];
5026
5027 if (bn + 1 > tn) tn = bn + 1;
5028 if (*ascale != *bscale) {
5029 /* first (optimistic) try - try to scale down the one with the bigger
5030 scale, while this number is divisible by 10 */
5031 DWORD * digitchosen;
5032 unsigned int nchosen;
5033 int * scalechosen;
5034 int targetscale;
5035
5036 if (*ascale < *bscale) {
5037 targetscale = *ascale;
5038 scalechosen = bscale;
5039 digitchosen = b;
5040 nchosen = bn;
5041 } else {
5042 targetscale = *bscale;
5043 scalechosen = ascale;
5044 digitchosen = a;
5045 nchosen = an;
5046 }
5047 memset(t, 0, tn * sizeof(DWORD));
5048 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5049
5050 /* divide by 10 until target scale is reached */
5051 while (*scalechosen > targetscale) {
5052 unsigned char remainder = VARIANT_int_divbychar(t, tn, 10);
5053 if (!remainder) {
5054 (*scalechosen)--;
5055 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5056 } else break;
5057 }
5058 }
5059
5060 if (*ascale != *bscale) {
5061 DWORD * digitchosen;
5062 unsigned int nchosen;
5063 int * scalechosen;
5064 int targetscale;
5065
5066 /* try to scale up the one with the smaller scale */
5067 if (*ascale > *bscale) {
5068 targetscale = *ascale;
5069 scalechosen = bscale;
5070 digitchosen = b;
5071 nchosen = bn;
5072 } else {
5073 targetscale = *bscale;
5074 scalechosen = ascale;
5075 digitchosen = a;
5076 nchosen = an;
5077 }
5078 memset(t, 0, tn * sizeof(DWORD));
5079 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5080
5081 /* multiply by 10 until target scale is reached, or
5082 significant bytes overflow the number
5083 */
5084 while (*scalechosen < targetscale && t[nchosen] == 0) {
5085 VARIANT_int_mulbychar(t, tn, 10);
5086 if (t[nchosen] == 0) {
5087 /* still does not overflow */
5088 (*scalechosen)++;
5089 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5090 }
5091 }
5092 }
5093
5094 if (*ascale != *bscale) {
5095 /* still different? try to scale down the one with the bigger scale
5096 (this *will* lose significant digits) */
5097 DWORD * digitchosen;
5098 unsigned int nchosen;
5099 int * scalechosen;
5100 int targetscale;
5101
5102 if (*ascale < *bscale) {
5103 targetscale = *ascale;
5104 scalechosen = bscale;
5105 digitchosen = b;
5106 nchosen = bn;
5107 } else {
5108 targetscale = *bscale;
5109 scalechosen = ascale;
5110 digitchosen = a;
5111 nchosen = an;
5112 }
5113 memset(t, 0, tn * sizeof(DWORD));
5114 memcpy(t, digitchosen, nchosen * sizeof(DWORD));
5115
5116 /* divide by 10 until target scale is reached */
5117 while (*scalechosen > targetscale) {
5118 VARIANT_int_divbychar(t, tn, 10);
5119 (*scalechosen)--;
5120 memcpy(digitchosen, t, nchosen * sizeof(DWORD));
5121 }
5122 }
5123
5124 /* check whether any of the operands still has significant digits
5125 (underflow case 1)
5126 */
5127 if (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn)) {
5128 underflow = 1;
5129 } else {
5130 /* at this step, both numbers have the same scale and can be added
5131 as integers. However, the result might not fit in A, so further
5132 scaling down might be necessary.
5133 */
5134 while (!underflow) {
5135 memset(t, 0, tn * sizeof(DWORD));
5136 memcpy(t, a, an * sizeof(DWORD));
5137
5138 VARIANT_int_add(t, tn, b, bn);
5139 if (VARIANT_int_iszero(t + an, tn - an)) {
5140 /* addition was successful */
5141 memcpy(a, t, an * sizeof(DWORD));
5142 break;
5143 } else {
5144 /* addition overflowed - remove significant digits
5145 from both operands and try again */
5146 VARIANT_int_divbychar(a, an, 10); (*ascale)--;
5147 VARIANT_int_divbychar(b, bn, 10); (*bscale)--;
5148 /* check whether any operand keeps significant digits after
5149 scaledown (underflow case 2)
5150 */
5151 underflow = (VARIANT_int_iszero(a, an) || VARIANT_int_iszero(b, bn));
5152 }
5153 }
5154 }
5155 }
5156 return underflow;
5157 }
5158
5159 /* perform complete DECIMAL division in the internal representation. Returns
5160 0 if the division was completed (even if quotient is set to 0), or nonzero
5161 in case of quotient overflow.
5162 */
5163 static HRESULT VARIANT_DI_div(const VARIANT_DI * dividend, const VARIANT_DI * divisor,
5164 VARIANT_DI * quotient, BOOL round_remainder)
5165 {
5166 HRESULT r_overflow = S_OK;
5167
5168 if (VARIANT_int_iszero(divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD))) {
5169 /* division by 0 */
5170 r_overflow = DISP_E_DIVBYZERO;
5171 } else if (VARIANT_int_iszero(dividend->bitsnum, sizeof(dividend->bitsnum)/sizeof(DWORD))) {
5172 VARIANT_DI_clear(quotient);
5173 } else {
5174 int quotientscale, remainderscale, tempquotientscale;
5175 DWORD remainderplusquotient[8];
5176 int underflow;
5177
5178 quotientscale = remainderscale = (int)dividend->scale - (int)divisor->scale;
5179 tempquotientscale = quotientscale;
5180 VARIANT_DI_clear(quotient);
5181 quotient->sign = (dividend->sign ^ divisor->sign) ? 1 : 0;
5182
5183 /* The following strategy is used for division
5184 1) if there was a nonzero remainder from previous iteration, use it as
5185 dividend for this iteration, else (for first iteration) use intended
5186 dividend
5187 2) perform integer division in temporary buffer, develop quotient in
5188 low-order part, remainder in high-order part
5189 3) add quotient from step 2 to final result, with possible loss of
5190 significant digits
5191 4) multiply integer part of remainder by 10, while incrementing the
5192 scale of the remainder. This operation preserves the intended value
5193 of the remainder.
5194 5) loop to step 1 until one of the following is true:
5195 a) remainder is zero (exact division achieved)
5196 b) addition in step 3 fails to modify bits in quotient (remainder underflow)
5197 */
5198 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5199 memcpy(remainderplusquotient, dividend->bitsnum, sizeof(dividend->bitsnum));
5200 do {
5201 VARIANT_int_div(
5202 remainderplusquotient, 4,
5203 divisor->bitsnum, sizeof(divisor->bitsnum)/sizeof(DWORD));
5204 underflow = VARIANT_int_addlossy(
5205 quotient->bitsnum, &quotientscale, sizeof(quotient->bitsnum) / sizeof(DWORD),
5206 remainderplusquotient, &tempquotientscale, 4);
5207 if (round_remainder) {
5208 if(remainderplusquotient[4] >= 5){
5209 unsigned int i;
5210 unsigned char remainder = 1;
5211 for (i = 0; i < sizeof(quotient->bitsnum) / sizeof(DWORD) && remainder; i++) {
5212 ULONGLONG digit = quotient->bitsnum[i] + 1;
5213 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5214 quotient->bitsnum[i] = digit & 0xFFFFFFFF;
5215 }
5216 }
5217 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5218 } else {
5219 VARIANT_int_mulbychar(remainderplusquotient + 4, 4, 10);
5220 memcpy(remainderplusquotient, remainderplusquotient + 4, 4 * sizeof(DWORD));
5221 }
5222 tempquotientscale = ++remainderscale;
5223 } while (!underflow && !VARIANT_int_iszero(remainderplusquotient + 4, 4));
5224
5225 /* quotient scale might now be negative (extremely big number). If, so, try
5226 to multiply quotient by 10 (without overflowing), while adjusting the scale,
5227 until scale is 0. If this cannot be done, it is a real overflow.
5228 */
5229 while (r_overflow == S_OK && quotientscale < 0) {
5230 memset(remainderplusquotient, 0, sizeof(remainderplusquotient));
5231 memcpy(remainderplusquotient, quotient->bitsnum, sizeof(quotient->bitsnum));
5232 VARIANT_int_mulbychar(remainderplusquotient, sizeof(remainderplusquotient)/sizeof(DWORD), 10);
5233 if (VARIANT_int_iszero(remainderplusquotient + sizeof(quotient->bitsnum)/sizeof(DWORD),
5234 (sizeof(remainderplusquotient) - sizeof(quotient->bitsnum))/sizeof(DWORD))) {
5235 quotientscale++;
5236 memcpy(quotient->bitsnum, remainderplusquotient, sizeof(quotient->bitsnum));
5237 } else r_overflow = DISP_E_OVERFLOW;
5238 }
5239 if (r_overflow == S_OK) {
5240 if (quotientscale <= 255) quotient->scale = quotientscale;
5241 else VARIANT_DI_clear(quotient);
5242 }
5243 }
5244 return r_overflow;
5245 }
5246
5247 /* This procedure receives a VARIANT_DI with a defined mantissa and sign, but
5248 with an undefined scale, which will be assigned to (if possible). It also
5249 receives an exponent of 2. This procedure will then manipulate the mantissa
5250 and calculate a corresponding scale, so that the exponent2 value is assimilated
5251 into the VARIANT_DI and is therefore no longer necessary. Returns S_OK if
5252 successful, or DISP_E_OVERFLOW if the represented value is too big to fit into
5253 a DECIMAL. */
5254 static HRESULT VARIANT_DI_normalize(VARIANT_DI * val, int exponent2, BOOL isDouble)
5255 {
5256 HRESULT hres = S_OK;
5257 int exponent5, exponent10;
5258
5259 /* A factor of 2^exponent2 is equivalent to (10^exponent2)/(5^exponent2), and
5260 thus equal to (5^-exponent2)*(10^exponent2). After all manipulations,
5261 exponent10 might be used to set the VARIANT_DI scale directly. However,
5262 the value of 5^-exponent5 must be assimilated into the VARIANT_DI. */
5263 exponent5 = -exponent2;
5264 exponent10 = exponent2;
5265
5266 /* Handle exponent5 > 0 */
5267 while (exponent5 > 0) {
5268 char bPrevCarryBit;
5269 char bCurrCarryBit;
5270
5271 /* In order to multiply the value represented by the VARIANT_DI by 5, it
5272 is best to multiply by 10/2. Therefore, exponent10 is incremented, and
5273 somehow the mantissa should be divided by 2. */
5274 if ((val->bitsnum[0] & 1) == 0) {
5275 /* The mantissa is divisible by 2. Therefore the division can be done
5276 without losing significant digits. */
5277 exponent10++; exponent5--;
5278
5279 /* Shift right */
5280 bPrevCarryBit = val->bitsnum[2] & 1;
5281 val->bitsnum[2] >>= 1;
5282 bCurrCarryBit = val->bitsnum[1] & 1;
5283 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5284 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5285 } else {
5286 /* The mantissa is NOT divisible by 2. Therefore the mantissa should
5287 be multiplied by 5, unless the multiplication overflows. */
5288 DWORD temp_bitsnum[3];
5289
5290 exponent5--;
5291
5292 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5293 if (0 == VARIANT_int_mulbychar(temp_bitsnum, 3, 5)) {
5294 /* Multiplication succeeded without overflow, so copy result back
5295 into VARIANT_DI */
5296 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5297
5298 /* Mask out 3 extraneous bits introduced by the multiply */
5299 } else {
5300 /* Multiplication by 5 overflows. The mantissa should be divided
5301 by 2, and therefore will lose significant digits. */
5302 exponent10++;
5303
5304 /* Shift right */
5305 bPrevCarryBit = val->bitsnum[2] & 1;
5306 val->bitsnum[2] >>= 1;
5307 bCurrCarryBit = val->bitsnum[1] & 1;
5308 val->bitsnum[1] = (val->bitsnum[1] >> 1) | (bPrevCarryBit ? 0x80000000 : 0);
5309 val->bitsnum[0] = (val->bitsnum[0] >> 1) | (bCurrCarryBit ? 0x80000000 : 0);
5310 }
5311 }
5312 }
5313
5314 /* Handle exponent5 < 0 */
5315 while (exponent5 < 0) {
5316 /* In order to divide the value represented by the VARIANT_DI by 5, it
5317 is best to multiply by 2/10. Therefore, exponent10 is decremented,
5318 and the mantissa should be multiplied by 2 */
5319 if ((val->bitsnum[2] & 0x80000000) == 0) {
5320 /* The mantissa can withstand a shift-left without overflowing */
5321 exponent10--; exponent5++;
5322 VARIANT_int_shiftleft(val->bitsnum, 3, 1);
5323 } else {
5324 /* The mantissa would overflow if shifted. Therefore it should be
5325 directly divided by 5. This will lose significant digits, unless
5326 by chance the mantissa happens to be divisible by 5 */
5327 exponent5++;
5328 VARIANT_int_divbychar(val->bitsnum, 3, 5);
5329 }
5330 }
5331
5332 /* At this point, the mantissa has assimilated the exponent5, but the
5333 exponent10 might not be suitable for assignment. The exponent10 must be
5334 in the range [-DEC_MAX_SCALE..0], so the mantissa must be scaled up or
5335 down appropriately. */
5336 while (hres == S_OK && exponent10 > 0) {
5337 /* In order to bring exponent10 down to 0, the mantissa should be
5338 multiplied by 10 to compensate. If the exponent10 is too big, this
5339 will cause the mantissa to overflow. */
5340 if (0 == VARIANT_int_mulbychar(val->bitsnum, 3, 10)) {
5341 exponent10--;
5342 } else {
5343 hres = DISP_E_OVERFLOW;
5344 }
5345 }
5346 while (exponent10 < -DEC_MAX_SCALE) {
5347 int rem10;
5348 /* In order to bring exponent up to -DEC_MAX_SCALE, the mantissa should
5349 be divided by 10 to compensate. If the exponent10 is too small, this
5350 will cause the mantissa to underflow and become 0 */
5351 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5352 exponent10++;
5353 if (VARIANT_int_iszero(val->bitsnum, 3)) {
5354 /* Underflow, unable to keep dividing */
5355 exponent10 = 0;
5356 } else if (rem10 >= 5) {
5357 DWORD x = 1;
5358 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5359 }
5360 }
5361 /* This step is required in order to remove excess bits of precision from the
5362 end of the bit representation, down to the precision guaranteed by the
5363 floating point number. */
5364 if (isDouble) {
5365 while (exponent10 < 0 && (val->bitsnum[2] != 0 || (val->bitsnum[1] & 0xFFE00000) != 0)) {
5366 int rem10;
5367
5368 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5369 exponent10++;
5370 if (rem10 >= 5) {
5371 DWORD x = 1;
5372 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5373 }
5374 }
5375 } else {
5376 while (exponent10 < 0 && (val->bitsnum[2] != 0 || val->bitsnum[1] != 0 ||
5377 (val->bitsnum[2] == 0 && val->bitsnum[1] == 0 && (val->bitsnum[0] & 0xFF000000) != 0))) {
5378 int rem10;
5379
5380 rem10 = VARIANT_int_divbychar(val->bitsnum, 3, 10);
5381 exponent10++;
5382 if (rem10 >= 5) {
5383 DWORD x = 1;
5384 VARIANT_int_add(val->bitsnum, 3, &x, 1);
5385 }
5386 }
5387 }
5388 /* Remove multiples of 10 from the representation */
5389 while (exponent10 < 0) {
5390 DWORD temp_bitsnum[3];
5391
5392 memcpy(temp_bitsnum, val->bitsnum, 3 * sizeof(DWORD));
5393 if (0 == VARIANT_int_divbychar(temp_bitsnum, 3, 10)) {
5394 exponent10++;
5395 memcpy(val->bitsnum, temp_bitsnum, 3 * sizeof(DWORD));
5396 } else break;
5397 }
5398
5399 /* Scale assignment */
5400 if (hres == S_OK) val->scale = -exponent10;
5401
5402 return hres;
5403 }
5404
5405 typedef union
5406 {
5407 struct
5408 {
5409 unsigned int m : 23;
5410 unsigned int exp_bias : 8;
5411 unsigned int sign : 1;
5412 } i;
5413 float f;
5414 } R4_FIELDS;
5415
5416 /* Convert a 32-bit floating point number into a DECIMAL, without using an
5417 intermediate string step. */
5418 static HRESULT VARIANT_DI_FromR4(float source, VARIANT_DI * dest)
5419 {
5420 HRESULT hres = S_OK;
5421 R4_FIELDS fx;
5422
5423 fx.f = source;
5424
5425 /* Detect special cases */
5426 if (fx.i.m == 0 && fx.i.exp_bias == 0) {
5427 /* Floating-point zero */
5428 VARIANT_DI_clear(dest);
5429 } else if (fx.i.m == 0 && fx.i.exp_bias == 0xFF) {
5430 /* Floating-point infinity */
5431 hres = DISP_E_OVERFLOW;
5432 } else if (fx.i.exp_bias == 0xFF) {
5433 /* Floating-point NaN */
5434 hres = DISP_E_BADVARTYPE;
5435 } else {
5436 int exponent2;
5437 VARIANT_DI_clear(dest);
5438
5439 exponent2 = fx.i.exp_bias - 127; /* Get unbiased exponent */
5440 dest->sign = fx.i.sign; /* Sign is simply copied */
5441
5442 /* Copy significant bits to VARIANT_DI mantissa */
5443 dest->bitsnum[0] = fx.i.m;
5444 dest->bitsnum[0] &= 0x007FFFFF;
5445 if (fx.i.exp_bias == 0) {
5446 /* Denormalized number - correct exponent */
5447 exponent2++;
5448 } else {
5449 /* Add hidden bit to mantissa */
5450 dest->bitsnum[0] |= 0x00800000;
5451 }
5452
5453 /* The act of copying a FP mantissa as integer bits is equivalent to
5454 shifting left the mantissa 23 bits. The exponent2 is reduced to
5455 compensate. */
5456 exponent2 -= 23;
5457
5458 hres = VARIANT_DI_normalize(dest, exponent2, FALSE);
5459 }
5460
5461 return hres;
5462 }
5463
5464 typedef union
5465 {
5466 struct
5467 {
5468 unsigned int m_lo : 32; /* 52 bits of precision */
5469 unsigned int m_hi : 20;
5470 unsigned int exp_bias : 11; /* bias == 1023 */
5471 unsigned int sign : 1;
5472 } i;
5473 double d;
5474 } R8_FIELDS;
5475
5476 /* Convert a 64-bit floating point number into a DECIMAL, without using an
5477 intermediate string step. */
5478 static HRESULT VARIANT_DI_FromR8(double source, VARIANT_DI * dest)
5479 {
5480 HRESULT hres = S_OK;
5481 R8_FIELDS fx;
5482
5483 fx.d = source;
5484
5485 /* Detect special cases */
5486 if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0) {
5487 /* Floating-point zero */
5488 VARIANT_DI_clear(dest);
5489 } else if (fx.i.m_lo == 0 && fx.i.m_hi == 0 && fx.i.exp_bias == 0x7FF) {
5490 /* Floating-point infinity */
5491 hres = DISP_E_OVERFLOW;
5492 } else if (fx.i.exp_bias == 0x7FF) {
5493 /* Floating-point NaN */
5494 hres = DISP_E_BADVARTYPE;
5495 } else {
5496 int exponent2;
5497 VARIANT_DI_clear(dest);
5498
5499 exponent2 = fx.i.exp_bias - 1023; /* Get unbiased exponent */
5500 dest->sign = fx.i.sign; /* Sign is simply copied */
5501
5502 /* Copy significant bits to VARIANT_DI mantissa */
5503 dest->bitsnum[0] = fx.i.m_lo;
5504 dest->bitsnum[1] = fx.i.m_hi;
5505 dest->bitsnum[1] &= 0x000FFFFF;
5506 if (fx.i.exp_bias == 0) {
5507 /* Denormalized number - correct exponent */
5508 exponent2++;
5509 } else {
5510 /* Add hidden bit to mantissa */
5511 dest->bitsnum[1] |= 0x00100000;
5512 }
5513
5514 /* The act of copying a FP mantissa as integer bits is equivalent to
5515 shifting left the mantissa 52 bits. The exponent2 is reduced to
5516 compensate. */
5517 exponent2 -= 52;
5518
5519 hres = VARIANT_DI_normalize(dest, exponent2, TRUE);
5520 }
5521
5522 return hres;
5523 }
5524
5525 static HRESULT VARIANT_do_division(const DECIMAL *pDecLeft, const DECIMAL *pDecRight, DECIMAL *pDecOut,
5526 BOOL round)
5527 {
5528 HRESULT hRet = S_OK;
5529 VARIANT_DI di_left, di_right, di_result;
5530 HRESULT divresult;
5531
5532 VARIANT_DIFromDec(pDecLeft, &di_left);
5533 VARIANT_DIFromDec(pDecRight, &di_right);
5534 divresult = VARIANT_DI_div(&di_left, &di_right, &di_result, round);
5535 if (divresult != S_OK)
5536 {
5537 /* division actually overflowed */
5538 hRet = divresult;
5539 }
5540 else
5541 {
5542 hRet = S_OK;
5543
5544 if (di_result.scale > DEC_MAX_SCALE)
5545 {
5546 unsigned char remainder = 0;
5547
5548 /* division underflowed. In order to comply with the MSDN
5549 specifications for DECIMAL ranges, some significant digits
5550 must be removed
5551 */
5552 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5553 di_result.scale);
5554 while (di_result.scale > DEC_MAX_SCALE &&
5555 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD)))
5556 {
5557 remainder = VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum) / sizeof(DWORD), 10);
5558 di_result.scale--;
5559 }
5560 if (di_result.scale > DEC_MAX_SCALE)
5561 {
5562 WARN("result underflowed, setting to 0\n");
5563 di_result.scale = 0;
5564 di_result.sign = 0;
5565 }
5566 else if (remainder >= 5) /* round up result - native oleaut32 does this */
5567 {
5568 unsigned int i;
5569 for (remainder = 1, i = 0; i < sizeof(di_result.bitsnum) / sizeof(DWORD) && remainder; i++) {
5570 ULONGLONG digit = di_result.bitsnum[i] + 1;
5571 remainder = (digit > 0xFFFFFFFF) ? 1 : 0;
5572 di_result.bitsnum[i] = digit & 0xFFFFFFFF;
5573 }
5574 }
5575 }
5576 VARIANT_DecFromDI(&di_result, pDecOut);
5577 }
5578 return hRet;
5579 }
5580
5581 /************************************************************************
5582 * VarDecDiv (OLEAUT32.178)
5583 *
5584 * Divide one DECIMAL by another.
5585 *
5586 * PARAMS
5587 * pDecLeft [I] Source
5588 * pDecRight [I] Value to divide by
5589 * pDecOut [O] Destination
5590 *
5591 * RETURNS
5592 * Success: S_OK.
5593 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5594 */
5595 HRESULT WINAPI VarDecDiv(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5596 {
5597 if (!pDecLeft || !pDecRight || !pDecOut) return E_INVALIDARG;
5598
5599 return VARIANT_do_division(pDecLeft, pDecRight, pDecOut, FALSE);
5600 }
5601
5602 /************************************************************************
5603 * VarDecMul (OLEAUT32.179)
5604 *
5605 * Multiply one DECIMAL by another.
5606 *
5607 * PARAMS
5608 * pDecLeft [I] Source
5609 * pDecRight [I] Value to multiply by
5610 * pDecOut [O] Destination
5611 *
5612 * RETURNS
5613 * Success: S_OK.
5614 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5615 */
5616 HRESULT WINAPI VarDecMul(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5617 {
5618 HRESULT hRet = S_OK;
5619 VARIANT_DI di_left, di_right, di_result;
5620 int mulresult;
5621
5622 VARIANT_DIFromDec(pDecLeft, &di_left);
5623 VARIANT_DIFromDec(pDecRight, &di_right);
5624 mulresult = VARIANT_DI_mul(&di_left, &di_right, &di_result);
5625 if (mulresult)
5626 {
5627 /* multiplication actually overflowed */
5628 hRet = DISP_E_OVERFLOW;
5629 }
5630 else
5631 {
5632 if (di_result.scale > DEC_MAX_SCALE)
5633 {
5634 /* multiplication underflowed. In order to comply with the MSDN
5635 specifications for DECIMAL ranges, some significant digits
5636 must be removed
5637 */
5638 WARN("result scale is %u, scaling (with loss of significant digits)...\n",
5639 di_result.scale);
5640 while (di_result.scale > DEC_MAX_SCALE &&
5641 !VARIANT_int_iszero(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD)))
5642 {
5643 VARIANT_int_divbychar(di_result.bitsnum, sizeof(di_result.bitsnum)/sizeof(DWORD), 10);
5644 di_result.scale--;
5645 }
5646 if (di_result.scale > DEC_MAX_SCALE)
5647 {
5648 WARN("result underflowed, setting to 0\n");
5649 di_result.scale = 0;
5650 di_result.sign = 0;
5651 }
5652 }
5653 VARIANT_DecFromDI(&di_result, pDecOut);
5654 }
5655 return hRet;
5656 }
5657
5658 /************************************************************************
5659 * VarDecSub (OLEAUT32.181)
5660 *
5661 * Subtract one DECIMAL from another.
5662 *
5663 * PARAMS
5664 * pDecLeft [I] Source
5665 * pDecRight [I] DECIMAL to subtract from pDecLeft
5666 * pDecOut [O] Destination
5667 *
5668 * RETURNS
5669 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5670 */
5671 HRESULT WINAPI VarDecSub(const DECIMAL* pDecLeft, const DECIMAL* pDecRight, DECIMAL* pDecOut)
5672 {
5673 DECIMAL decRight;
5674
5675 /* Implement as addition of the negative */
5676 VarDecNeg(pDecRight, &decRight);
5677 return VarDecAdd(pDecLeft, &decRight, pDecOut);
5678 }
5679
5680 /************************************************************************
5681 * VarDecAbs (OLEAUT32.182)
5682 *
5683 * Convert a DECIMAL into its absolute value.
5684 *
5685 * PARAMS
5686 * pDecIn [I] Source
5687 * pDecOut [O] Destination
5688 *
5689 * RETURNS
5690 * S_OK. This function does not fail.
5691 */
5692 HRESULT WINAPI VarDecAbs(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5693 {
5694 *pDecOut = *pDecIn;
5695 DEC_SIGN(pDecOut) &= ~DECIMAL_NEG;
5696 return S_OK;
5697 }
5698
5699 /************************************************************************
5700 * VarDecFix (OLEAUT32.187)
5701 *
5702 * Return the integer portion of a DECIMAL.
5703 *
5704 * PARAMS
5705 * pDecIn [I] Source
5706 * pDecOut [O] Destination
5707 *
5708 * RETURNS
5709 * Success: S_OK.
5710 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5711 *
5712 * NOTES
5713 * - The difference between this function and VarDecInt() is that VarDecInt() rounds
5714 * negative numbers away from 0, while this function rounds them towards zero.
5715 */
5716 HRESULT WINAPI VarDecFix(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5717 {
5718 double dbl;
5719 HRESULT hr;
5720
5721 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5722 return E_INVALIDARG;
5723
5724 if (!DEC_SCALE(pDecIn))
5725 {
5726 *pDecOut = *pDecIn; /* Already an integer */
5727 return S_OK;
5728 }
5729
5730 hr = VarR8FromDec(pDecIn, &dbl);
5731 if (SUCCEEDED(hr)) {
5732 LONGLONG rounded = dbl;
5733
5734 hr = VarDecFromI8(rounded, pDecOut);
5735 }
5736 return hr;
5737 }
5738
5739 /************************************************************************
5740 * VarDecInt (OLEAUT32.188)
5741 *
5742 * Return the integer portion of a DECIMAL.
5743 *
5744 * PARAMS
5745 * pDecIn [I] Source
5746 * pDecOut [O] Destination
5747 *
5748 * RETURNS
5749 * Success: S_OK.
5750 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
5751 *
5752 * NOTES
5753 * - The difference between this function and VarDecFix() is that VarDecFix() rounds
5754 * negative numbers towards 0, while this function rounds them away from zero.
5755 */
5756 HRESULT WINAPI VarDecInt(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5757 {
5758 double dbl;
5759 HRESULT hr;
5760
5761 if (DEC_SIGN(pDecIn) & ~DECIMAL_NEG)
5762 return E_INVALIDARG;
5763
5764 if (!(DEC_SIGN(pDecIn) & DECIMAL_NEG) || !DEC_SCALE(pDecIn))
5765 return VarDecFix(pDecIn, pDecOut); /* The same, if +ve or no fractionals */
5766
5767 hr = VarR8FromDec(pDecIn, &dbl);
5768 if (SUCCEEDED(hr)) {
5769 LONGLONG rounded = dbl >= 0.0 ? dbl + 0.5 : dbl - 0.5;
5770
5771 hr = VarDecFromI8(rounded, pDecOut);
5772 }
5773 return hr;
5774 }
5775
5776 /************************************************************************
5777 * VarDecNeg (OLEAUT32.189)
5778 *
5779 * Change the sign of a DECIMAL.
5780 *
5781 * PARAMS
5782 * pDecIn [I] Source
5783 * pDecOut [O] Destination
5784 *
5785 * RETURNS
5786 * S_OK. This function does not fail.
5787 */
5788 HRESULT WINAPI VarDecNeg(const DECIMAL* pDecIn, DECIMAL* pDecOut)
5789 {
5790 *pDecOut = *pDecIn;
5791 DEC_SIGN(pDecOut) ^= DECIMAL_NEG;
5792 return S_OK;
5793 }
5794
5795 /************************************************************************
5796 * VarDecRound (OLEAUT32.203)
5797 *
5798 * Change the precision of a DECIMAL.
5799 *
5800 * PARAMS
5801 * pDecIn [I] Source
5802 * cDecimals [I] New number of decimals to keep
5803 * pDecOut [O] Destination
5804 *
5805 * RETURNS
5806 * Success: S_OK. pDecOut contains the rounded value.
5807 * Failure: E_INVALIDARG if any argument is invalid.
5808 */
5809 HRESULT WINAPI VarDecRound(const DECIMAL* pDecIn, int cDecimals, DECIMAL* pDecOut)
5810 {
5811 DECIMAL divisor, tmp;
5812 HRESULT hr;
5813 unsigned int i;
5814
5815 if (cDecimals < 0 || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG) || DEC_SCALE(pDecIn) > DEC_MAX_SCALE)
5816 return E_INVALIDARG;
5817
5818 if (cDecimals >= DEC_SCALE(pDecIn))
5819 {
5820 *pDecOut = *pDecIn; /* More precision than we have */
5821 return S_OK;
5822 }
5823
5824 /* truncate significant digits and rescale */
5825 memset(&divisor, 0, sizeof(divisor));
5826 DEC_LO64(&divisor) = 1;
5827
5828 memset(&tmp, 0, sizeof(tmp));
5829 DEC_LO64(&tmp) = 10;
5830 for (i = 0; i < DEC_SCALE(pDecIn) - cDecimals; ++i)
5831 {
5832 hr = VarDecMul(&divisor, &tmp, &divisor);
5833 if (FAILED(hr))
5834 return hr;
5835 }
5836
5837 hr = VARIANT_do_division(pDecIn, &divisor, pDecOut, TRUE);
5838 if (FAILED(hr))
5839 return hr;
5840
5841 DEC_SCALE(pDecOut) = cDecimals;
5842
5843 return S_OK;
5844 }
5845
5846 /************************************************************************
5847 * VarDecCmp (OLEAUT32.204)
5848 *
5849 * Compare two DECIMAL values.
5850 *
5851 * PARAMS
5852 * pDecLeft [I] Source
5853 * pDecRight [I] Value to compare
5854 *
5855 * RETURNS
5856 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pDecLeft
5857 * is less than, equal to or greater than pDecRight respectively.
5858 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5859 */
5860 HRESULT WINAPI VarDecCmp(const DECIMAL* pDecLeft, const DECIMAL* pDecRight)
5861 {
5862 HRESULT hRet;
5863 DECIMAL result;
5864
5865 if (!pDecLeft || !pDecRight)
5866 return VARCMP_NULL;
5867
5868 if ((!(DEC_SIGN(pDecLeft) & DECIMAL_NEG)) && (DEC_SIGN(pDecRight) & DECIMAL_NEG) &&
5869 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5870 return VARCMP_GT;
5871 else if ((DEC_SIGN(pDecLeft) & DECIMAL_NEG) && (!(DEC_SIGN(pDecRight) & DECIMAL_NEG)) &&
5872 (DEC_HI32(pDecLeft) | DEC_MID32(pDecLeft) | DEC_LO32(pDecLeft)))
5873 return VARCMP_LT;
5874
5875 /* Subtract right from left, and compare the result to 0 */
5876 hRet = VarDecSub(pDecLeft, pDecRight, &result);
5877
5878 if (SUCCEEDED(hRet))
5879 {
5880 int non_zero = DEC_HI32(&result) | DEC_MID32(&result) | DEC_LO32(&result);
5881
5882 if ((DEC_SIGN(&result) & DECIMAL_NEG) && non_zero)
5883 hRet = (HRESULT)VARCMP_LT;
5884 else if (non_zero)
5885 hRet = (HRESULT)VARCMP_GT;
5886 else
5887 hRet = (HRESULT)VARCMP_EQ;
5888 }
5889 return hRet;
5890 }
5891
5892 /************************************************************************
5893 * VarDecCmpR8 (OLEAUT32.298)
5894 *
5895 * Compare a DECIMAL to a double
5896 *
5897 * PARAMS
5898 * pDecLeft [I] DECIMAL Source
5899 * dblRight [I] double to compare to pDecLeft
5900 *
5901 * RETURNS
5902 * Success: VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that dblRight
5903 * is less than, equal to or greater than pDecLeft respectively.
5904 * Failure: DISP_E_OVERFLOW, if overflow occurs during the comparison
5905 */
5906 HRESULT WINAPI VarDecCmpR8(const DECIMAL* pDecLeft, double dblRight)
5907 {
5908 HRESULT hRet;
5909 DECIMAL decRight;
5910
5911 hRet = VarDecFromR8(dblRight, &decRight);
5912
5913 if (SUCCEEDED(hRet))
5914 hRet = VarDecCmp(pDecLeft, &decRight);
5915
5916 return hRet;
5917 }
5918
5919 /* BOOL
5920 */
5921
5922 /************************************************************************
5923 * VarBoolFromUI1 (OLEAUT32.118)
5924 *
5925 * Convert a VT_UI1 to a VT_BOOL.
5926 *
5927 * PARAMS
5928 * bIn [I] Source
5929 * pBoolOut [O] Destination
5930 *
5931 * RETURNS
5932 * S_OK.
5933 */
5934 HRESULT WINAPI VarBoolFromUI1(BYTE bIn, VARIANT_BOOL *pBoolOut)
5935 {
5936 *pBoolOut = bIn ? VARIANT_TRUE : VARIANT_FALSE;
5937 return S_OK;
5938 }
5939
5940 /************************************************************************
5941 * VarBoolFromI2 (OLEAUT32.119)
5942 *
5943 * Convert a VT_I2 to a VT_BOOL.
5944 *
5945 * PARAMS
5946 * sIn [I] Source
5947 * pBoolOut [O] Destination
5948 *
5949 * RETURNS
5950 * S_OK.
5951 */
5952 HRESULT WINAPI VarBoolFromI2(SHORT sIn, VARIANT_BOOL *pBoolOut)
5953 {
5954 *pBoolOut = sIn ? VARIANT_TRUE : VARIANT_FALSE;
5955 return S_OK;
5956 }
5957
5958 /************************************************************************
5959 * VarBoolFromI4 (OLEAUT32.120)
5960 *
5961 * Convert a VT_I4 to a VT_BOOL.
5962 *
5963 * PARAMS
5964 * sIn [I] Source
5965 * pBoolOut [O] Destination
5966 *
5967 * RETURNS
5968 * S_OK.
5969 */
5970 HRESULT WINAPI VarBoolFromI4(LONG lIn, VARIANT_BOOL *pBoolOut)
5971 {
5972 *pBoolOut = lIn ? VARIANT_TRUE : VARIANT_FALSE;
5973 return S_OK;
5974 }
5975
5976 /************************************************************************
5977 * VarBoolFromR4 (OLEAUT32.121)
5978 *
5979 * Convert a VT_R4 to a VT_BOOL.
5980 *
5981 * PARAMS
5982 * fltIn [I] Source
5983 * pBoolOut [O] Destination
5984 *
5985 * RETURNS
5986 * S_OK.
5987 */
5988 HRESULT WINAPI VarBoolFromR4(FLOAT fltIn, VARIANT_BOOL *pBoolOut)
5989 {
5990 *pBoolOut = fltIn ? VARIANT_TRUE : VARIANT_FALSE;
5991 return S_OK;
5992 }
5993
5994 /************************************************************************
5995 * VarBoolFromR8 (OLEAUT32.122)
5996 *
5997 * Convert a VT_R8 to a VT_BOOL.
5998 *
5999 * PARAMS
6000 * dblIn [I] Source
6001 * pBoolOut [O] Destination
6002 *
6003 * RETURNS
6004 * S_OK.
6005 */
6006 HRESULT WINAPI VarBoolFromR8(double dblIn, VARIANT_BOOL *pBoolOut)
6007 {
6008 *pBoolOut = dblIn ? VARIANT_TRUE : VARIANT_FALSE;
6009 return S_OK;
6010 }
6011
6012 /************************************************************************
6013 * VarBoolFromDate (OLEAUT32.123)
6014 *
6015 * Convert a VT_DATE to a VT_BOOL.
6016 *
6017 * PARAMS
6018 * dateIn [I] Source
6019 * pBoolOut [O] Destination
6020 *
6021 * RETURNS
6022 * S_OK.
6023 */
6024 HRESULT WINAPI VarBoolFromDate(DATE dateIn, VARIANT_BOOL *pBoolOut)
6025 {
6026 *pBoolOut = dateIn ? VARIANT_TRUE : VARIANT_FALSE;
6027 return S_OK;
6028 }
6029
6030 /************************************************************************
6031 * VarBoolFromCy (OLEAUT32.124)
6032 *
6033 * Convert a VT_CY to a VT_BOOL.
6034 *
6035 * PARAMS
6036 * cyIn [I] Source
6037 * pBoolOut [O] Destination
6038 *
6039 * RETURNS
6040 * S_OK.
6041 */
6042 HRESULT WINAPI VarBoolFromCy(CY cyIn, VARIANT_BOOL *pBoolOut)
6043 {
6044 *pBoolOut = cyIn.int64 ? VARIANT_TRUE : VARIANT_FALSE;
6045 return S_OK;
6046 }
6047
6048 /************************************************************************
6049 * VARIANT_GetLocalisedText [internal]
6050 *
6051 * Get a localized string from the resources
6052 *
6053 */
6054 static BOOL VARIANT_GetLocalisedText(LANGID langId, DWORD dwId, WCHAR *lpszDest)
6055 {
6056 HRSRC hrsrc;
6057
6058 hrsrc = FindResourceExW( hProxyDll, (LPWSTR)RT_STRING,
6059 MAKEINTRESOURCEW((dwId >> 4) + 1), langId );
6060 if (hrsrc)
6061 {
6062 HGLOBAL hmem = LoadResource( hProxyDll, hrsrc );
6063
6064 if (hmem)
6065 {
6066 const WCHAR *p;
6067 unsigned int i;
6068
6069 p = LockResource( hmem );
6070 for (i = 0; i < (dwId & 0x0f); i++) p += *p + 1;
6071
6072 memcpy( lpszDest, p + 1, *p * sizeof(WCHAR) );
6073 lpszDest[*p] = '\0';
6074 TRACE("got %s for LANGID %08x\n", debugstr_w(lpszDest), langId);
6075 return TRUE;
6076 }
6077 }
6078 return FALSE;
6079 }
6080
6081 /************************************************************************
6082 * VarBoolFromStr (OLEAUT32.125)
6083 *
6084 * Convert a VT_BSTR to a VT_BOOL.
6085 *
6086 * PARAMS
6087 * strIn [I] Source
6088 * lcid [I] LCID for the conversion
6089 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6090 * pBoolOut [O] Destination
6091 *
6092 * RETURNS
6093 * Success: S_OK.
6094 * Failure: E_INVALIDARG, if pBoolOut is invalid.
6095 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6096 *
6097 * NOTES
6098 * - strIn will be recognised if it contains "#TRUE#" or "#FALSE#". Additionally,
6099 * it may contain (in any case mapping) the text "true" or "false".
6100 * - If dwFlags includes VAR_LOCALBOOL, then the text may also match the
6101 * localised text of "True" or "False" in the language specified by lcid.
6102 * - If none of these matches occur, the string is treated as a numeric string
6103 * and the boolean pBoolOut will be set according to whether the number is zero
6104 * or not. The dwFlags parameter is passed to VarR8FromStr() for this conversion.
6105 * - If the text is not numeric and does not match any of the above, then
6106 * DISP_E_TYPEMISMATCH is returned.
6107 */
6108 HRESULT WINAPI VarBoolFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, VARIANT_BOOL *pBoolOut)
6109 {
6110 /* Any VB/VBA programmers out there should recognise these strings... */
6111 static const WCHAR szFalse[] = { '#','F','A','L','S','E','#','\0' };
6112 static const WCHAR szTrue[] = { '#','T','R','U','E','#','\0' };
6113 WCHAR szBuff[64];
6114 LANGID langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6115 HRESULT hRes = S_OK;
6116
6117 if (!strIn || !pBoolOut)
6118 return DISP_E_TYPEMISMATCH;
6119
6120 /* Check if we should be comparing against localised text */
6121 if (dwFlags & VAR_LOCALBOOL)
6122 {
6123 /* Convert our LCID into a usable value */
6124 lcid = ConvertDefaultLocale(lcid);
6125
6126 langId = LANGIDFROMLCID(lcid);
6127
6128 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6129 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6130
6131 /* Note: Native oleaut32 always copies strIn and maps halfwidth characters.
6132 * I don't think this is needed unless any of the localised text strings
6133 * contain characters that can be so mapped. In the event that this is
6134 * true for a given language (possibly some Asian languages), then strIn
6135 * should be mapped here _only_ if langId is an Id for which this can occur.
6136 */
6137 }
6138
6139 /* Note that if we are not comparing against localised strings, langId
6140 * will have its default value of LANG_ENGLISH. This allows us to mimic
6141 * the native behaviour of always checking against English strings even
6142 * after we've checked for localised ones.
6143 */
6144 VarBoolFromStr_CheckLocalised:
6145 if (VARIANT_GetLocalisedText(langId, IDS_TRUE, szBuff))
6146 {
6147 /* Compare against localised strings, ignoring case */
6148 if (!strcmpiW(strIn, szBuff))
6149 {
6150 *pBoolOut = VARIANT_TRUE; /* Matched localised 'true' text */
6151 return hRes;
6152 }
6153 VARIANT_GetLocalisedText(langId, IDS_FALSE, szBuff);
6154 if (!strcmpiW(strIn, szBuff))
6155 {
6156 *pBoolOut = VARIANT_FALSE; /* Matched localised 'false' text */
6157 return hRes;
6158 }
6159 }
6160
6161 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6162 {
6163 /* We have checked the localised text, now check English */
6164 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6165 goto VarBoolFromStr_CheckLocalised;
6166 }
6167
6168 /* All checks against localised text have failed, try #TRUE#/#FALSE# */
6169 if (!strcmpW(strIn, szFalse))
6170 *pBoolOut = VARIANT_FALSE;
6171 else if (!strcmpW(strIn, szTrue))
6172 *pBoolOut = VARIANT_TRUE;
6173 else
6174 {
6175 double d;
6176
6177 /* If this string is a number, convert it as one */
6178 hRes = VarR8FromStr(strIn, lcid, dwFlags, &d);
6179 if (SUCCEEDED(hRes)) *pBoolOut = d ? VARIANT_TRUE : VARIANT_FALSE;
6180 }
6181 return hRes;
6182 }
6183
6184 /************************************************************************
6185 * VarBoolFromDisp (OLEAUT32.126)
6186 *
6187 * Convert a VT_DISPATCH to a VT_BOOL.
6188 *
6189 * PARAMS
6190 * pdispIn [I] Source
6191 * lcid [I] LCID for conversion
6192 * pBoolOut [O] Destination
6193 *
6194 * RETURNS
6195 * Success: S_OK.
6196 * Failure: E_INVALIDARG, if the source value is invalid
6197 * DISP_E_OVERFLOW, if the value will not fit in the destination
6198 * DISP_E_TYPEMISMATCH, if the type cannot be converted
6199 */
6200 HRESULT WINAPI VarBoolFromDisp(IDispatch* pdispIn, LCID lcid, VARIANT_BOOL *pBoolOut)
6201 {
6202 return VARIANT_FromDisp(pdispIn, lcid, pBoolOut, VT_BOOL, 0);
6203 }
6204
6205 /************************************************************************
6206 * VarBoolFromI1 (OLEAUT32.233)
6207 *
6208 * Convert a VT_I1 to a VT_BOOL.
6209 *
6210 * PARAMS
6211 * cIn [I] Source
6212 * pBoolOut [O] Destination
6213 *
6214 * RETURNS
6215 * S_OK.
6216 */
6217 HRESULT WINAPI VarBoolFromI1(signed char cIn, VARIANT_BOOL *pBoolOut)
6218 {
6219 *pBoolOut = cIn ? VARIANT_TRUE : VARIANT_FALSE;
6220 return S_OK;
6221 }
6222
6223 /************************************************************************
6224 * VarBoolFromUI2 (OLEAUT32.234)
6225 *
6226 * Convert a VT_UI2 to a VT_BOOL.
6227 *
6228 * PARAMS
6229 * usIn [I] Source
6230 * pBoolOut [O] Destination
6231 *
6232 * RETURNS
6233 * S_OK.
6234 */
6235 HRESULT WINAPI VarBoolFromUI2(USHORT usIn, VARIANT_BOOL *pBoolOut)
6236 {
6237 *pBoolOut = usIn ? VARIANT_TRUE : VARIANT_FALSE;
6238 return S_OK;
6239 }
6240
6241 /************************************************************************
6242 * VarBoolFromUI4 (OLEAUT32.235)
6243 *
6244 * Convert a VT_UI4 to a VT_BOOL.
6245 *
6246 * PARAMS
6247 * ulIn [I] Source
6248 * pBoolOut [O] Destination
6249 *
6250 * RETURNS
6251 * S_OK.
6252 */
6253 HRESULT WINAPI VarBoolFromUI4(ULONG ulIn, VARIANT_BOOL *pBoolOut)
6254 {
6255 *pBoolOut = ulIn ? VARIANT_TRUE : VARIANT_FALSE;
6256 return S_OK;
6257 }
6258
6259 /************************************************************************
6260 * VarBoolFromDec (OLEAUT32.236)
6261 *
6262 * Convert a VT_DECIMAL to a VT_BOOL.
6263 *
6264 * PARAMS
6265 * pDecIn [I] Source
6266 * pBoolOut [O] Destination
6267 *
6268 * RETURNS
6269 * Success: S_OK.
6270 * Failure: E_INVALIDARG, if pDecIn is invalid.
6271 */
6272 HRESULT WINAPI VarBoolFromDec(DECIMAL* pDecIn, VARIANT_BOOL *pBoolOut)
6273 {
6274 if (DEC_SCALE(pDecIn) > DEC_MAX_SCALE || (DEC_SIGN(pDecIn) & ~DECIMAL_NEG))
6275 return E_INVALIDARG;
6276
6277 if (DEC_HI32(pDecIn) || DEC_MID32(pDecIn) || DEC_LO32(pDecIn))
6278 *pBoolOut = VARIANT_TRUE;
6279 else
6280 *pBoolOut = VARIANT_FALSE;
6281 return S_OK;
6282 }
6283
6284 /************************************************************************
6285 * VarBoolFromI8 (OLEAUT32.370)
6286 *
6287 * Convert a VT_I8 to a VT_BOOL.
6288 *
6289 * PARAMS
6290 * ullIn [I] Source
6291 * pBoolOut [O] Destination
6292 *
6293 * RETURNS
6294 * S_OK.
6295 */
6296 HRESULT WINAPI VarBoolFromI8(LONG64 llIn, VARIANT_BOOL *pBoolOut)
6297 {
6298 *pBoolOut = llIn ? VARIANT_TRUE : VARIANT_FALSE;
6299 return S_OK;
6300 }
6301
6302 /************************************************************************
6303 * VarBoolFromUI8 (OLEAUT32.371)
6304 *
6305 * Convert a VT_UI8 to a VT_BOOL.
6306 *
6307 * PARAMS
6308 * ullIn [I] Source
6309 * pBoolOut [O] Destination
6310 *
6311 * RETURNS
6312 * S_OK.
6313 */
6314 HRESULT WINAPI VarBoolFromUI8(ULONG64 ullIn, VARIANT_BOOL *pBoolOut)
6315 {
6316 *pBoolOut = ullIn ? VARIANT_TRUE : VARIANT_FALSE;
6317 return S_OK;
6318 }
6319
6320 /* BSTR
6321 */
6322
6323 /* Write a number from a UI8 and sign */
6324 static WCHAR *VARIANT_WriteNumber(ULONG64 ulVal, WCHAR* szOut)
6325 {
6326 do
6327 {
6328 WCHAR ulNextDigit = ulVal % 10;
6329
6330 *szOut-- = '0' + ulNextDigit;
6331 ulVal = (ulVal - ulNextDigit) / 10;
6332 } while (ulVal);
6333
6334 szOut++;
6335 return szOut;
6336 }
6337
6338 /* Create a (possibly localised) BSTR from a UI8 and sign */
6339 static BSTR VARIANT_MakeBstr(LCID lcid, DWORD dwFlags, WCHAR *szOut)
6340 {
6341 WCHAR szConverted[256];
6342
6343 if (dwFlags & VAR_NEGATIVE)
6344 *--szOut = '-';
6345
6346 if (dwFlags & LOCALE_USE_NLS)
6347 {
6348 /* Format the number for the locale */
6349 szConverted[0] = '\0';
6350 GetNumberFormatW(lcid,
6351 dwFlags & LOCALE_NOUSEROVERRIDE,
6352 szOut, NULL, szConverted, sizeof(szConverted)/sizeof(WCHAR));
6353 szOut = szConverted;
6354 }
6355 return SysAllocStringByteLen((LPCSTR)szOut, strlenW(szOut) * sizeof(WCHAR));
6356 }
6357
6358 /* Create a (possibly localised) BSTR from a UI8 and sign */
6359 static HRESULT VARIANT_BstrFromUInt(ULONG64 ulVal, LCID lcid, DWORD dwFlags, BSTR *pbstrOut)
6360 {
6361 WCHAR szBuff[64], *szOut = szBuff + sizeof(szBuff)/sizeof(WCHAR) - 1;
6362
6363 if (!pbstrOut)
6364 return E_INVALIDARG;
6365
6366 /* Create the basic number string */
6367 *szOut-- = '\0';
6368 szOut = VARIANT_WriteNumber(ulVal, szOut);
6369
6370 *pbstrOut = VARIANT_MakeBstr(lcid, dwFlags, szOut);
6371 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6372 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6373 }
6374
6375 /******************************************************************************
6376 * VarBstrFromUI1 (OLEAUT32.108)
6377 *
6378 * Convert a VT_UI1 to a VT_BSTR.
6379 *
6380 * PARAMS
6381 * bIn [I] Source
6382 * lcid [I] LCID for the conversion
6383 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6384 * pbstrOut [O] Destination
6385 *
6386 * RETURNS
6387 * Success: S_OK.
6388 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6389 * E_OUTOFMEMORY, if memory allocation fails.
6390 */
6391 HRESULT WINAPI VarBstrFromUI1(BYTE bIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6392 {
6393 return VARIANT_BstrFromUInt(bIn, lcid, dwFlags, pbstrOut);
6394 }
6395
6396 /******************************************************************************
6397 * VarBstrFromI2 (OLEAUT32.109)
6398 *
6399 * Convert a VT_I2 to a VT_BSTR.
6400 *
6401 * PARAMS
6402 * sIn [I] Source
6403 * lcid [I] LCID for the conversion
6404 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6405 * pbstrOut [O] Destination
6406 *
6407 * RETURNS
6408 * Success: S_OK.
6409 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6410 * E_OUTOFMEMORY, if memory allocation fails.
6411 */
6412 HRESULT WINAPI VarBstrFromI2(short sIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6413 {
6414 ULONG64 ul64 = sIn;
6415
6416 if (sIn < 0)
6417 {
6418 ul64 = -sIn;
6419 dwFlags |= VAR_NEGATIVE;
6420 }
6421 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6422 }
6423
6424 /******************************************************************************
6425 * VarBstrFromI4 (OLEAUT32.110)
6426 *
6427 * Convert a VT_I4 to a VT_BSTR.
6428 *
6429 * PARAMS
6430 * lIn [I] Source
6431 * lcid [I] LCID for the conversion
6432 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6433 * pbstrOut [O] Destination
6434 *
6435 * RETURNS
6436 * Success: S_OK.
6437 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6438 * E_OUTOFMEMORY, if memory allocation fails.
6439 */
6440 HRESULT WINAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6441 {
6442 ULONG64 ul64 = lIn;
6443
6444 if (lIn < 0)
6445 {
6446 ul64 = (ULONG)-lIn;
6447 dwFlags |= VAR_NEGATIVE;
6448 }
6449 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6450 }
6451
6452 static BSTR VARIANT_BstrReplaceDecimal(const WCHAR * buff, LCID lcid, ULONG dwFlags)
6453 {
6454 BSTR bstrOut;
6455 WCHAR lpDecimalSep[16];
6456
6457 /* Native oleaut32 uses the locale-specific decimal separator even in the
6458 absence of the LOCALE_USE_NLS flag. For example, the Spanish/Latin
6459 American locales will see "one thousand and one tenth" as "1000,1"
6460 instead of "1000.1" (notice the comma). The following code checks for
6461 the need to replace the decimal separator, and if so, will prepare an
6462 appropriate NUMBERFMTW structure to do the job via GetNumberFormatW().
6463 */
6464 GetLocaleInfoW(lcid, LOCALE_SDECIMAL | (dwFlags & LOCALE_NOUSEROVERRIDE),
6465 lpDecimalSep, sizeof(lpDecimalSep) / sizeof(WCHAR));
6466 if (lpDecimalSep[0] == '.' && lpDecimalSep[1] == '\0')
6467 {
6468 /* locale is compatible with English - return original string */
6469 bstrOut = SysAllocString(buff);
6470 }
6471 else
6472 {
6473 WCHAR *p;
6474 WCHAR numbuff[256];
6475 WCHAR empty[] = {'\0'};
6476 NUMBERFMTW minFormat;
6477
6478 minFormat.NumDigits = 0;
6479 minFormat.LeadingZero = 0;
6480 minFormat.Grouping = 0;
6481 minFormat.lpDecimalSep = lpDecimalSep;
6482 minFormat.lpThousandSep = empty;
6483 minFormat.NegativeOrder = 1; /* NLS_NEG_LEFT */
6484
6485 /* count number of decimal digits in string */
6486 p = strchrW( buff, '.' );
6487 if (p) minFormat.NumDigits = strlenW(p + 1);
6488
6489 numbuff[0] = '\0';
6490 if (!GetNumberFormatW(lcid, 0, buff, &minFormat, numbuff, sizeof(numbuff) / sizeof(WCHAR)))
6491 {
6492 WARN("GetNumberFormatW() failed, returning raw number string instead\n");
6493 bstrOut = SysAllocString(buff);
6494 }
6495 else
6496 {
6497 TRACE("created minimal NLS string %s\n", debugstr_w(numbuff));
6498 bstrOut = SysAllocString(numbuff);
6499 }
6500 }
6501 return bstrOut;
6502 }
6503
6504 static HRESULT VARIANT_BstrFromReal(DOUBLE dblIn, LCID lcid, ULONG dwFlags,
6505 BSTR* pbstrOut, LPCWSTR lpszFormat)
6506 {
6507 WCHAR buff[256];
6508
6509 if (!pbstrOut)
6510 return E_INVALIDARG;
6511
6512 sprintfW( buff, lpszFormat, dblIn );
6513
6514 /* Negative zeroes are disallowed (some applications depend on this).
6515 If buff starts with a minus, and then nothing follows but zeroes
6516 and/or a period, it is a negative zero and is replaced with a
6517 canonical zero. This duplicates native oleaut32 behavior.
6518 */
6519 if (buff[0] == '-')
6520 {
6521 const WCHAR szAccept[] = {'0', '.', '\0'};
6522 if (strlenW(buff + 1) == strspnW(buff + 1, szAccept))
6523 { buff[0] = '0'; buff[1] = '\0'; }
6524 }
6525
6526 TRACE("created string %s\n", debugstr_w(buff));
6527 if (dwFlags & LOCALE_USE_NLS)
6528 {
6529 WCHAR numbuff[256];
6530
6531 /* Format the number for the locale */
6532 numbuff[0] = '\0';
6533 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6534 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
6535 TRACE("created NLS string %s\n", debugstr_w(numbuff));
6536 *pbstrOut = SysAllocString(numbuff);
6537 }
6538 else
6539 {
6540 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
6541 }
6542 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6543 }
6544
6545 /******************************************************************************
6546 * VarBstrFromR4 (OLEAUT32.111)
6547 *
6548 * Convert a VT_R4 to a VT_BSTR.
6549 *
6550 * PARAMS
6551 * fltIn [I] Source
6552 * lcid [I] LCID for the conversion
6553 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6554 * pbstrOut [O] Destination
6555 *
6556 * RETURNS
6557 * Success: S_OK.
6558 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6559 * E_OUTOFMEMORY, if memory allocation fails.
6560 */
6561 HRESULT WINAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6562 {
6563 return VARIANT_BstrFromReal(fltIn, lcid, dwFlags, pbstrOut, szFloatFormatW);
6564 }
6565
6566 /******************************************************************************
6567 * VarBstrFromR8 (OLEAUT32.112)
6568 *
6569 * Convert a VT_R8 to a VT_BSTR.
6570 *
6571 * PARAMS
6572 * dblIn [I] Source
6573 * lcid [I] LCID for the conversion
6574 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6575 * pbstrOut [O] Destination
6576 *
6577 * RETURNS
6578 * Success: S_OK.
6579 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6580 * E_OUTOFMEMORY, if memory allocation fails.
6581 */
6582 HRESULT WINAPI VarBstrFromR8(double dblIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6583 {
6584 return VARIANT_BstrFromReal(dblIn, lcid, dwFlags, pbstrOut, szDoubleFormatW);
6585 }
6586
6587 /******************************************************************************
6588 * VarBstrFromCy [OLEAUT32.113]
6589 *
6590 * Convert a VT_CY to a VT_BSTR.
6591 *
6592 * PARAMS
6593 * cyIn [I] Source
6594 * lcid [I] LCID for the conversion
6595 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6596 * pbstrOut [O] Destination
6597 *
6598 * RETURNS
6599 * Success: S_OK.
6600 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6601 * E_OUTOFMEMORY, if memory allocation fails.
6602 */
6603 HRESULT WINAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut)
6604 {
6605 WCHAR buff[256];
6606 VARIANT_DI decVal;
6607
6608 if (!pbstrOut)
6609 return E_INVALIDARG;
6610
6611 decVal.scale = 4;
6612 decVal.sign = 0;
6613 decVal.bitsnum[0] = cyIn.s.Lo;
6614 decVal.bitsnum[1] = cyIn.s.Hi;
6615 if (cyIn.s.Hi & 0x80000000UL) {
6616 DWORD one = 1;
6617
6618 /* Negative number! */
6619 decVal.sign = 1;
6620 decVal.bitsnum[0] = ~decVal.bitsnum[0];
6621 decVal.bitsnum[1] = ~decVal.bitsnum[1];
6622 VARIANT_int_add(decVal.bitsnum, 3, &one, 1);
6623 }
6624 decVal.bitsnum[2] = 0;
6625 VARIANT_DI_tostringW(&decVal, buff, sizeof(buff)/sizeof(buff[0]));
6626
6627 if (dwFlags & LOCALE_USE_NLS)
6628 {
6629 WCHAR cybuff[256];
6630
6631 /* Format the currency for the locale */
6632 cybuff[0] = '\0';
6633 GetCurrencyFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
6634 buff, NULL, cybuff, sizeof(cybuff) / sizeof(WCHAR));
6635 *pbstrOut = SysAllocString(cybuff);
6636 }
6637 else
6638 *pbstrOut = VARIANT_BstrReplaceDecimal(buff,lcid,dwFlags);
6639
6640 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6641 }
6642
6643 static inline int output_int_len(int o, int min_len, WCHAR *date, int date_len)
6644 {
6645 int len, tmp;
6646
6647 if(min_len >= date_len)
6648 return -1;
6649
6650 for(len=0, tmp=o; tmp; tmp/=10) len++;
6651 if(!len) len++;
6652 if(len >= date_len)
6653 return -1;
6654
6655 for(tmp=min_len-len; tmp>0; tmp--)
6656 *date++ = '0';
6657 for(tmp=len; tmp>0; tmp--, o/=10)
6658 date[tmp-1] = '0' + o%10;
6659 return min_len>len ? min_len : len;
6660 }
6661
6662 /* format date string, similar to GetDateFormatW function but works on bigger range of dates */
6663 BOOL get_date_format(LCID lcid, DWORD flags, const SYSTEMTIME *st,
6664 const WCHAR *fmt, WCHAR *date, int date_len)
6665 {
6666 static const LCTYPE dayname[] = {
6667 LOCALE_SDAYNAME7, LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3,
6668 LOCALE_SDAYNAME4, LOCALE_SDAYNAME5, LOCALE_SDAYNAME6
6669 };
6670 static const LCTYPE sdayname[] = {
6671 LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2,
6672 LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5,
6673 LOCALE_SABBREVDAYNAME6
6674 };
6675 static const LCTYPE monthname[] = {
6676 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
6677 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
6678 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12
6679 };
6680 static const LCTYPE smonthname[] = {
6681 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
6682 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
6683 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
6684 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12
6685 };
6686
6687 if(flags & ~(LOCALE_NOUSEROVERRIDE|VAR_DATEVALUEONLY))
6688 FIXME("ignoring flags %x\n", flags);
6689 flags &= LOCALE_NOUSEROVERRIDE;
6690
6691 while(*fmt && date_len) {
6692 int count = 1;
6693
6694 switch(*fmt) {
6695 case 'd':
6696 case 'M':
6697 case 'y':
6698 case 'g':
6699 while(*fmt == *(fmt+count))
6700 count++;
6701 fmt += count-1;
6702 }
6703
6704 switch(*fmt) {
6705 case 'd':
6706 if(count >= 4)
6707 count = GetLocaleInfoW(lcid, dayname[st->wDayOfWeek] | flags, date, date_len)-1;
6708 else if(count == 3)
6709 count = GetLocaleInfoW(lcid, sdayname[st->wDayOfWeek] | flags, date, date_len)-1;
6710 else
6711 count = output_int_len(st->wDay, count, date, date_len);
6712 break;
6713 case 'M':
6714 if(count >= 4)
6715 count = GetLocaleInfoW(lcid, monthname[st->wMonth-1] | flags, date, date_len)-1;
6716 else if(count == 3)
6717 count = GetLocaleInfoW(lcid, smonthname[st->wMonth-1] | flags, date, date_len)-1;
6718 else
6719 count = output_int_len(st->wMonth, count, date, date_len);
6720 break;
6721 case 'y':
6722 if(count >= 3)
6723 count = output_int_len(st->wYear, 0, date, date_len);
6724 else
6725 count = output_int_len(st->wYear%100, count, date, date_len);
6726 break;
6727 case 'g':
6728 if(count == 2) {
6729 FIXME("Should be using GetCalendarInfo(CAL_SERASTRING), defaulting to 'AD'\n");
6730
6731 *date++ = 'A';
6732 date_len--;
6733 if(date_len)
6734 *date = 'D';
6735 else
6736 count = -1;
6737 break;
6738 }
6739 /* fall through */
6740 default:
6741 *date = *fmt;
6742 }
6743
6744 if(count < 0)
6745 break;
6746 fmt++;
6747 date += count;
6748 date_len -= count;
6749 }
6750
6751 if(!date_len)
6752 return FALSE;
6753 *date++ = 0;
6754 return TRUE;
6755 }
6756
6757 /******************************************************************************
6758 * VarBstrFromDate [OLEAUT32.114]
6759 *
6760 * Convert a VT_DATE to a VT_BSTR.
6761 *
6762 * PARAMS
6763 * dateIn [I] Source
6764 * lcid [I] LCID for the conversion
6765 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6766 * pbstrOut [O] Destination
6767 *
6768 * RETURNS
6769 * Success: S_OK.
6770 * Failure: E_INVALIDARG, if pbstrOut or dateIn is invalid.
6771 * E_OUTOFMEMORY, if memory allocation fails.
6772 */
6773 HRESULT WINAPI VarBstrFromDate(DATE dateIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6774 {
6775 SYSTEMTIME st;
6776 DWORD dwFormatFlags = dwFlags & LOCALE_NOUSEROVERRIDE;
6777 WCHAR date[128], fmt_buff[80], *time;
6778
6779 TRACE("(%g,0x%08x,0x%08x,%p)\n", dateIn, lcid, dwFlags, pbstrOut);
6780
6781 if (!pbstrOut || !VariantTimeToSystemTime(dateIn, &st))
6782 return E_INVALIDARG;
6783
6784 *pbstrOut = NULL;
6785
6786 if (dwFlags & VAR_CALENDAR_THAI)
6787 st.wYear += 553; /* Use the Thai buddhist calendar year */
6788 else if (dwFlags & (VAR_CALENDAR_HIJRI|VAR_CALENDAR_GREGORIAN))
6789 FIXME("VAR_CALENDAR_HIJRI/VAR_CALENDAR_GREGORIAN not handled\n");
6790
6791 if (dwFlags & LOCALE_USE_NLS)
6792 dwFlags &= ~(VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY);
6793 else
6794 {
6795 double whole = dateIn < 0 ? ceil(dateIn) : floor(dateIn);
6796 double partial = dateIn - whole;
6797
6798 if (whole == 0.0)
6799 dwFlags |= VAR_TIMEVALUEONLY;
6800 else if (partial > -1e-12 && partial < 1e-12)
6801 dwFlags |= VAR_DATEVALUEONLY;
6802 }
6803
6804 if (dwFlags & VAR_TIMEVALUEONLY)
6805 date[0] = '\0';
6806 else
6807 if (!GetLocaleInfoW(lcid, LOCALE_SSHORTDATE, fmt_buff, sizeof(fmt_buff)/sizeof(WCHAR)) ||
6808 !get_date_format(lcid, dwFlags, &st, fmt_buff, date, sizeof(date)/sizeof(WCHAR)))
6809 return E_INVALIDARG;
6810
6811 if (!(dwFlags & VAR_DATEVALUEONLY))
6812 {
6813 time = date + strlenW(date);
6814 if (time != date)
6815 *time++ = ' ';
6816 if (!GetTimeFormatW(lcid, dwFormatFlags, &st, NULL, time,
6817 sizeof(date)/sizeof(WCHAR)-(time-date)))
6818 return E_INVALIDARG;
6819 }
6820
6821 *pbstrOut = SysAllocString(date);
6822 if (*pbstrOut)
6823 TRACE("returning %s\n", debugstr_w(*pbstrOut));
6824 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6825 }
6826
6827 /******************************************************************************
6828 * VarBstrFromBool (OLEAUT32.116)
6829 *
6830 * Convert a VT_BOOL to a VT_BSTR.
6831 *
6832 * PARAMS
6833 * boolIn [I] Source
6834 * lcid [I] LCID for the conversion
6835 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6836 * pbstrOut [O] Destination
6837 *
6838 * RETURNS
6839 * Success: S_OK.
6840 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6841 * E_OUTOFMEMORY, if memory allocation fails.
6842 *
6843 * NOTES
6844 * If dwFlags includes VARIANT_LOCALBOOL, this function converts to the
6845 * localised text of "True" or "False". To convert a bool into a
6846 * numeric string of "0" or "-1", use VariantChangeTypeTypeEx().
6847 */
6848 HRESULT WINAPI VarBstrFromBool(VARIANT_BOOL boolIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6849 {
6850 WCHAR szBuff[64];
6851 DWORD dwResId = IDS_TRUE;
6852 LANGID langId;
6853
6854 TRACE("%d,0x%08x,0x%08x,%p\n", boolIn, lcid, dwFlags, pbstrOut);
6855
6856 if (!pbstrOut)
6857 return E_INVALIDARG;
6858
6859 /* VAR_BOOLONOFF and VAR_BOOLYESNO are internal flags used
6860 * for variant formatting */
6861 switch (dwFlags & (VAR_LOCALBOOL|VAR_BOOLONOFF|VAR_BOOLYESNO))
6862 {
6863 case VAR_BOOLONOFF:
6864 dwResId = IDS_ON;
6865 break;
6866 case VAR_BOOLYESNO:
6867 dwResId = IDS_YES;
6868 break;
6869 case VAR_LOCALBOOL:
6870 break;
6871 default:
6872 lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),SORT_DEFAULT);
6873 }
6874
6875 lcid = ConvertDefaultLocale(lcid);
6876 langId = LANGIDFROMLCID(lcid);
6877 if (PRIMARYLANGID(langId) == LANG_NEUTRAL)
6878 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6879
6880 if (boolIn == VARIANT_FALSE)
6881 dwResId++; /* Use negative form */
6882
6883 VarBstrFromBool_GetLocalised:
6884 if (VARIANT_GetLocalisedText(langId, dwResId, szBuff))
6885 {
6886 *pbstrOut = SysAllocString(szBuff);
6887 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
6888 }
6889
6890 if (langId != MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT))
6891 {
6892 langId = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
6893 goto VarBstrFromBool_GetLocalised;
6894 }
6895
6896 /* Should never get here */
6897 WARN("Failed to load bool text!\n");
6898 return E_OUTOFMEMORY;
6899 }
6900
6901 /******************************************************************************
6902 * VarBstrFromI1 (OLEAUT32.229)
6903 *
6904 * Convert a VT_I1 to a VT_BSTR.
6905 *
6906 * PARAMS
6907 * cIn [I] Source
6908 * lcid [I] LCID for the conversion
6909 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6910 * pbstrOut [O] Destination
6911 *
6912 * RETURNS
6913 * Success: S_OK.
6914 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6915 * E_OUTOFMEMORY, if memory allocation fails.
6916 */
6917 HRESULT WINAPI VarBstrFromI1(signed char cIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6918 {
6919 ULONG64 ul64 = cIn;
6920
6921 if (cIn < 0)
6922 {
6923 ul64 = -cIn;
6924 dwFlags |= VAR_NEGATIVE;
6925 }
6926 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
6927 }
6928
6929 /******************************************************************************
6930 * VarBstrFromUI2 (OLEAUT32.230)
6931 *
6932 * Convert a VT_UI2 to a VT_BSTR.
6933 *
6934 * PARAMS
6935 * usIn [I] Source
6936 * lcid [I] LCID for the conversion
6937 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6938 * pbstrOut [O] Destination
6939 *
6940 * RETURNS
6941 * Success: S_OK.
6942 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6943 * E_OUTOFMEMORY, if memory allocation fails.
6944 */
6945 HRESULT WINAPI VarBstrFromUI2(USHORT usIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6946 {
6947 return VARIANT_BstrFromUInt(usIn, lcid, dwFlags, pbstrOut);
6948 }
6949
6950 /******************************************************************************
6951 * VarBstrFromUI4 (OLEAUT32.231)
6952 *
6953 * Convert a VT_UI4 to a VT_BSTR.
6954 *
6955 * PARAMS
6956 * ulIn [I] Source
6957 * lcid [I] LCID for the conversion
6958 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6959 * pbstrOut [O] Destination
6960 *
6961 * RETURNS
6962 * Success: S_OK.
6963 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6964 * E_OUTOFMEMORY, if memory allocation fails.
6965 */
6966 HRESULT WINAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6967 {
6968 return VARIANT_BstrFromUInt(ulIn, lcid, dwFlags, pbstrOut);
6969 }
6970
6971 /******************************************************************************
6972 * VarBstrFromDec (OLEAUT32.232)
6973 *
6974 * Convert a VT_DECIMAL to a VT_BSTR.
6975 *
6976 * PARAMS
6977 * pDecIn [I] Source
6978 * lcid [I] LCID for the conversion
6979 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
6980 * pbstrOut [O] Destination
6981 *
6982 * RETURNS
6983 * Success: S_OK.
6984 * Failure: E_INVALIDARG, if pbstrOut is invalid.
6985 * E_OUTOFMEMORY, if memory allocation fails.
6986 */
6987 HRESULT WINAPI VarBstrFromDec(DECIMAL* pDecIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
6988 {
6989 WCHAR buff[256];
6990 VARIANT_DI temp;
6991
6992 if (!pbstrOut)
6993 return E_INVALIDARG;
6994
6995 VARIANT_DIFromDec(pDecIn, &temp);
6996 VARIANT_DI_tostringW(&temp, buff, 256);
6997
6998 if (dwFlags & LOCALE_USE_NLS)
6999 {
7000 WCHAR numbuff[256];
7001
7002 /* Format the number for the locale */
7003 numbuff[0] = '\0';
7004 GetNumberFormatW(lcid, dwFlags & LOCALE_NOUSEROVERRIDE,
7005 buff, NULL, numbuff, sizeof(numbuff) / sizeof(WCHAR));
7006 TRACE("created NLS string %s\n", debugstr_w(numbuff));
7007 *pbstrOut = SysAllocString(numbuff);
7008 }
7009 else
7010 {
7011 *pbstrOut = VARIANT_BstrReplaceDecimal(buff, lcid, dwFlags);
7012 }
7013
7014 TRACE("returning %s\n", debugstr_w(*pbstrOut));
7015 return *pbstrOut ? S_OK : E_OUTOFMEMORY;
7016 }
7017
7018 /************************************************************************
7019 * VarBstrFromI8 (OLEAUT32.370)
7020 *
7021 * Convert a VT_I8 to a VT_BSTR.
7022 *
7023 * PARAMS
7024 * llIn [I] Source
7025 * lcid [I] LCID for the conversion
7026 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7027 * pbstrOut [O] Destination
7028 *
7029 * RETURNS
7030 * Success: S_OK.
7031 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7032 * E_OUTOFMEMORY, if memory allocation fails.
7033 */
7034 HRESULT WINAPI VarBstrFromI8(LONG64 llIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7035 {
7036 ULONG64 ul64 = llIn;
7037
7038 if (llIn < 0)
7039 {
7040 ul64 = -llIn;
7041 dwFlags |= VAR_NEGATIVE;
7042 }
7043 return VARIANT_BstrFromUInt(ul64, lcid, dwFlags, pbstrOut);
7044 }
7045
7046 /************************************************************************
7047 * VarBstrFromUI8 (OLEAUT32.371)
7048 *
7049 * Convert a VT_UI8 to a VT_BSTR.
7050 *
7051 * PARAMS
7052 * ullIn [I] Source
7053 * lcid [I] LCID for the conversion
7054 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7055 * pbstrOut [O] Destination
7056 *
7057 * RETURNS
7058 * Success: S_OK.
7059 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7060 * E_OUTOFMEMORY, if memory allocation fails.
7061 */
7062 HRESULT WINAPI VarBstrFromUI8(ULONG64 ullIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7063 {
7064 return VARIANT_BstrFromUInt(ullIn, lcid, dwFlags, pbstrOut);
7065 }
7066
7067 /************************************************************************
7068 * VarBstrFromDisp (OLEAUT32.115)
7069 *
7070 * Convert a VT_DISPATCH to a BSTR.
7071 *
7072 * PARAMS
7073 * pdispIn [I] Source
7074 * lcid [I] LCID for conversion
7075 * dwFlags [I] Flags controlling the conversion (VAR_ flags from "oleauto.h")
7076 * pbstrOut [O] Destination
7077 *
7078 * RETURNS
7079 * Success: S_OK.
7080 * Failure: E_INVALIDARG, if the source value is invalid
7081 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7082 */
7083 HRESULT WINAPI VarBstrFromDisp(IDispatch* pdispIn, LCID lcid, ULONG dwFlags, BSTR* pbstrOut)
7084 {
7085 return VARIANT_FromDisp(pdispIn, lcid, pbstrOut, VT_BSTR, dwFlags);
7086 }
7087
7088 /**********************************************************************
7089 * VarBstrCat (OLEAUT32.313)
7090 *
7091 * Concatenate two BSTR values.
7092 *
7093 * PARAMS
7094 * pbstrLeft [I] Source
7095 * pbstrRight [I] Value to concatenate
7096 * pbstrOut [O] Destination
7097 *
7098 * RETURNS
7099 * Success: S_OK.
7100 * Failure: E_INVALIDARG, if pbstrOut is invalid.
7101 * E_OUTOFMEMORY, if memory allocation fails.
7102 */
7103 HRESULT WINAPI VarBstrCat(BSTR pbstrLeft, BSTR pbstrRight, BSTR *pbstrOut)
7104 {
7105 unsigned int lenLeft, lenRight;
7106
7107 TRACE("%s,%s,%p\n",
7108 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7109 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), pbstrOut);
7110
7111 if (!pbstrOut)
7112 return E_INVALIDARG;
7113
7114 /* use byte length here to properly handle ansi-allocated BSTRs */
7115 lenLeft = pbstrLeft ? SysStringByteLen(pbstrLeft) : 0;
7116 lenRight = pbstrRight ? SysStringByteLen(pbstrRight) : 0;
7117
7118 *pbstrOut = SysAllocStringByteLen(NULL, lenLeft + lenRight);
7119 if (!*pbstrOut)
7120 return E_OUTOFMEMORY;
7121
7122 (*pbstrOut)[0] = '\0';
7123
7124 if (pbstrLeft)
7125 memcpy(*pbstrOut, pbstrLeft, lenLeft);
7126
7127 if (pbstrRight)
7128 memcpy((CHAR*)*pbstrOut + lenLeft, pbstrRight, lenRight);
7129
7130 TRACE("%s\n", debugstr_wn(*pbstrOut, SysStringLen(*pbstrOut)));
7131 return S_OK;
7132 }
7133
7134 /**********************************************************************
7135 * VarBstrCmp (OLEAUT32.314)
7136 *
7137 * Compare two BSTR values.
7138 *
7139 * PARAMS
7140 * pbstrLeft [I] Source
7141 * pbstrRight [I] Value to compare
7142 * lcid [I] LCID for the comparison
7143 * dwFlags [I] Flags to pass directly to CompareStringW().
7144 *
7145 * RETURNS
7146 * VARCMP_LT, VARCMP_EQ or VARCMP_GT indicating that pbstrLeft is less
7147 * than, equal to or greater than pbstrRight respectively.
7148 *
7149 * NOTES
7150 * VARCMP_NULL is NOT returned if either string is NULL unlike MSDN
7151 * states. A NULL BSTR pointer is equivalent to an empty string.
7152 * If LCID is equal to 0, a byte by byte comparison is performed.
7153 */
7154 HRESULT WINAPI VarBstrCmp(BSTR pbstrLeft, BSTR pbstrRight, LCID lcid, DWORD dwFlags)
7155 {
7156 HRESULT hres;
7157 int ret;
7158
7159 TRACE("%s,%s,%d,%08x\n",
7160 debugstr_wn(pbstrLeft, SysStringLen(pbstrLeft)),
7161 debugstr_wn(pbstrRight, SysStringLen(pbstrRight)), lcid, dwFlags);
7162
7163 if (!pbstrLeft || !*pbstrLeft)
7164 {
7165 if (pbstrRight && *pbstrRight)
7166 return VARCMP_LT;
7167 }
7168 else if (!pbstrRight || !*pbstrRight)
7169 return VARCMP_GT;
7170
7171 if (lcid == 0)
7172 {
7173 unsigned int lenLeft = SysStringByteLen(pbstrLeft);
7174 unsigned int lenRight = SysStringByteLen(pbstrRight);
7175 ret = memcmp(pbstrLeft, pbstrRight, min(lenLeft, lenRight));
7176 if (ret < 0)
7177 return VARCMP_LT;
7178 if (ret > 0)
7179 return VARCMP_GT;
7180 if (lenLeft < lenRight)
7181 return VARCMP_LT;
7182 if (lenLeft > lenRight)
7183 return VARCMP_GT;
7184 return VARCMP_EQ;
7185 }
7186 else
7187 {
7188 unsigned int lenLeft = SysStringLen(pbstrLeft);
7189 unsigned int lenRight = SysStringLen(pbstrRight);
7190
7191 if (lenLeft == 0 || lenRight == 0)
7192 {
7193 if (lenLeft == 0 && lenRight == 0) return VARCMP_EQ;
7194 return lenLeft < lenRight ? VARCMP_LT : VARCMP_GT;
7195 }
7196
7197 hres = CompareStringW(lcid, dwFlags, pbstrLeft, lenLeft,
7198 pbstrRight, lenRight) - CSTR_LESS_THAN;
7199 TRACE("%d\n", hres);
7200 return hres;
7201 }
7202 }
7203
7204 /*
7205 * DATE
7206 */
7207
7208 /******************************************************************************
7209 * VarDateFromUI1 (OLEAUT32.88)
7210 *
7211 * Convert a VT_UI1 to a VT_DATE.
7212 *
7213 * PARAMS
7214 * bIn [I] Source
7215 * pdateOut [O] Destination
7216 *
7217 * RETURNS
7218 * S_OK.
7219 */
7220 HRESULT WINAPI VarDateFromUI1(BYTE bIn, DATE* pdateOut)
7221 {
7222 return VarR8FromUI1(bIn, pdateOut);
7223 }
7224
7225 /******************************************************************************
7226 * VarDateFromI2 (OLEAUT32.89)
7227 *
7228 * Convert a VT_I2 to a VT_DATE.
7229 *
7230 * PARAMS
7231 * sIn [I] Source
7232 * pdateOut [O] Destination
7233 *
7234 * RETURNS
7235 * S_OK.
7236 */
7237 HRESULT WINAPI VarDateFromI2(short sIn, DATE* pdateOut)
7238 {
7239 return VarR8FromI2(sIn, pdateOut);
7240 }
7241
7242 /******************************************************************************
7243 * VarDateFromI4 (OLEAUT32.90)
7244 *
7245 * Convert a VT_I4 to a VT_DATE.
7246 *
7247 * PARAMS
7248 * lIn [I] Source
7249 * pdateOut [O] Destination
7250 *
7251 * RETURNS
7252 * S_OK.
7253 */
7254 HRESULT WINAPI VarDateFromI4(LONG lIn, DATE* pdateOut)
7255 {
7256 return VarDateFromR8(lIn, pdateOut);
7257 }
7258
7259 /******************************************************************************
7260 * VarDateFromR4 (OLEAUT32.91)
7261 *
7262 * Convert a VT_R4 to a VT_DATE.
7263 *
7264 * PARAMS
7265 * fltIn [I] Source
7266 * pdateOut [O] Destination
7267 *
7268 * RETURNS
7269 * S_OK.
7270 */
7271 HRESULT WINAPI VarDateFromR4(FLOAT fltIn, DATE* pdateOut)
7272 {
7273 return VarR8FromR4(fltIn, pdateOut);
7274 }
7275
7276 /******************************************************************************
7277 * VarDateFromR8 (OLEAUT32.92)
7278 *
7279 * Convert a VT_R8 to a VT_DATE.
7280 *
7281 * PARAMS
7282 * dblIn [I] Source
7283 * pdateOut [O] Destination
7284 *
7285 * RETURNS
7286 * S_OK.
7287 */
7288 HRESULT WINAPI VarDateFromR8(double dblIn, DATE* pdateOut)
7289 {
7290 if (dblIn <= (DATE_MIN - 1.0) || dblIn >= (DATE_MAX + 1.0)) return DISP_E_OVERFLOW;
7291 *pdateOut = (DATE)dblIn;
7292 return S_OK;
7293 }
7294
7295 /**********************************************************************
7296 * VarDateFromDisp (OLEAUT32.95)
7297 *
7298 * Convert a VT_DISPATCH to a VT_DATE.
7299 *
7300 * PARAMS
7301 * pdispIn [I] Source
7302 * lcid [I] LCID for conversion
7303 * pdateOut [O] Destination
7304 *
7305 * RETURNS
7306 * Success: S_OK.
7307 * Failure: E_INVALIDARG, if the source value is invalid
7308 * DISP_E_OVERFLOW, if the value will not fit in the destination
7309 * DISP_E_TYPEMISMATCH, if the type cannot be converted
7310 */
7311 HRESULT WINAPI VarDateFromDisp(IDispatch* pdispIn, LCID lcid, DATE* pdateOut)
7312 {
7313 return VARIANT_FromDisp(pdispIn, lcid, pdateOut, VT_DATE, 0);
7314 }
7315
7316 /******************************************************************************
7317 * VarDateFromBool (OLEAUT32.96)
7318 *
7319 * Convert a VT_BOOL to a VT_DATE.
7320 *
7321 * PARAMS
7322 * boolIn [I] Source
7323 * pdateOut [O] Destination
7324 *
7325 * RETURNS
7326 * S_OK.
7327 */
7328 HRESULT WINAPI VarDateFromBool(VARIANT_BOOL boolIn, DATE* pdateOut)
7329 {
7330 return VarR8FromBool(boolIn, pdateOut);
7331 }
7332
7333 /**********************************************************************
7334 * VarDateFromCy (OLEAUT32.93)
7335 *
7336 * Convert a VT_CY to a VT_DATE.
7337 *
7338 * PARAMS
7339 * lIn [I] Source
7340 * pdateOut [O] Destination
7341 *
7342 * RETURNS
7343 * S_OK.
7344 */
7345 HRESULT WINAPI VarDateFromCy(CY cyIn, DATE* pdateOut)
7346 {
7347 return VarR8FromCy(cyIn, pdateOut);
7348 }
7349
7350 /* Date string parsing */
7351 #define DP_TIMESEP 0x01 /* Time separator ( _must_ remain 0x1, used as a bitmask) */
7352 #define DP_DATESEP 0x02 /* Date separator */
7353 #define DP_MONTH 0x04 /* Month name */
7354 #define DP_AM 0x08 /* AM */
7355 #define DP_PM 0x10 /* PM */
7356
7357 typedef struct tagDATEPARSE
7358 {
7359 DWORD dwCount; /* Number of fields found so far (maximum 6) */
7360 DWORD dwParseFlags; /* Global parse flags (DP_ Flags above) */
7361 DWORD dwFlags[6]; /* Flags for each field */
7362 DWORD dwValues[6]; /* Value of each field */
7363 } DATEPARSE;
7364
7365 #define TIMEFLAG(i) ((dp.dwFlags[i] & DP_TIMESEP) << i)
7366
7367 #define IsLeapYear(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
7368
7369 /* Determine if a day is valid in a given month of a given year */
7370 static BOOL VARIANT_IsValidMonthDay(DWORD day, DWORD month, DWORD year)
7371 {
7372 static const BYTE days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
7373
7374 if (day && month && month < 13)
7375 {
7376 if (day <= days[month] || (month == 2 && day == 29 && IsLeapYear(year)))
7377 return TRUE;
7378 }
7379 return FALSE;
7380 }
7381
7382 /* Possible orders for 3 numbers making up a date */
7383 #define ORDER_MDY 0x01
7384 #define ORDER_YMD 0x02
7385 #define ORDER_YDM 0x04
7386 #define ORDER_DMY 0x08
7387 #define ORDER_MYD 0x10 /* Synthetic order, used only for funky 2 digit dates */
7388
7389 /* Determine a date for a particular locale, from 3 numbers */
7390 static inline HRESULT VARIANT_MakeDate(DATEPARSE *dp, DWORD iDate,
7391 DWORD offset, SYSTEMTIME *st)
7392 {
7393 DWORD dwAllOrders, dwTry, dwCount = 0, v1, v2, v3;
7394
7395 if (!dp->dwCount)
7396 {
7397 v1 = 30; /* Default to (Variant) 0 date part */
7398 v2 = 12;
7399 v3 = 1899;
7400 goto VARIANT_MakeDate_OK;
7401 }
7402
7403 v1 = dp->dwValues[offset + 0];
7404 v2 = dp->dwValues[offset + 1];
7405 if (dp->dwCount == 2)
7406 {
7407 SYSTEMTIME current;
7408 GetSystemTime(&current);
7409 v3 = current.wYear;
7410 }
7411 else
7412 v3 = dp->dwValues[offset + 2];
7413
7414 TRACE("(%d,%d,%d,%d,%d)\n", v1, v2, v3, iDate, offset);
7415
7416 /* If one number must be a month (Because a month name was given), then only
7417 * consider orders with the month in that position.
7418 * If we took the current year as 'v3', then only allow a year in that position.
7419 */
7420 if (dp->dwFlags[offset + 0] & DP_MONTH)
7421 {
7422 dwAllOrders = ORDER_MDY;
7423 }
7424 else if (dp->dwFlags[offset + 1] & DP_MONTH)
7425 {
7426 dwAllOrders = ORDER_DMY;
7427 if (dp->dwCount > 2)
7428 dwAllOrders |= ORDER_YMD;
7429 }
7430 else if (dp->dwCount > 2 && dp->dwFlags[offset + 2] & DP_MONTH)
7431 {
7432 dwAllOrders = ORDER_YDM;
7433 }
7434 else
7435 {
7436 dwAllOrders = ORDER_MDY|ORDER_DMY;
7437 if (dp->dwCount > 2)
7438 dwAllOrders |= (ORDER_YMD|ORDER_YDM);
7439 }
7440
7441 VARIANT_MakeDate_Start:
7442 TRACE("dwAllOrders is 0x%08x\n", dwAllOrders);
7443
7444 while (dwAllOrders)
7445 {
7446 DWORD dwTemp;
7447
7448 if (dwCount == 0)
7449 {
7450 /* First: Try the order given by iDate */
7451 switch (iDate)
7452 {
7453 case 0: dwTry = dwAllOrders & ORDER_MDY; break;
7454 case 1: dwTry = dwAllOrders & ORDER_DMY; break;
7455 default: dwTry = dwAllOrders & ORDER_YMD; break;
7456 }
7457 }
7458 else if (dwCount == 1)
7459 {
7460 /* Second: Try all the orders compatible with iDate */
7461 switch (iDate)
7462 {
7463 case 0: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7464 case 1: dwTry = dwAllOrders & ~(ORDER_MDY|ORDER_YDM|ORDER_MYD); break;
7465 default: dwTry = dwAllOrders & ~(ORDER_DMY|ORDER_YDM); break;
7466 }
7467 }
7468 else
7469 {
7470 /* Finally: Try any remaining orders */
7471 dwTry = dwAllOrders;
7472 }
7473
7474 TRACE("Attempt %d, dwTry is 0x%08x\n", dwCount, dwTry);
7475
7476 dwCount++;
7477 if (!dwTry)
7478 continue;
7479
7480 #define DATE_SWAP(x,y) do { dwTemp = x; x = y; y = dwTemp; } while (0)
7481
7482 if (dwTry & ORDER_MDY)
7483 {
7484 if (VARIANT_IsValidMonthDay(v2,v1,v3))
7485 {
7486 DATE_SWAP(v1,v2);
7487 goto VARIANT_MakeDate_OK;
7488 }
7489 dwAllOrders &= ~ORDER_MDY;
7490 }
7491 if (dwTry & ORDER_YMD)
7492 {
7493 if (VARIANT_IsValidMonthDay(v3,v2,v1))
7494 {
7495 DATE_SWAP(v1,v3);
7496 goto VARIANT_MakeDate_OK;
7497 }
7498 dwAllOrders &= ~ORDER_YMD;
7499 }
7500 if (dwTry & ORDER_YDM)
7501 {
7502 if (VARIANT_IsValidMonthDay(v2,v3,v1))
7503 {
7504 DATE_SWAP(v1,v2);
7505 DATE_SWAP(v2,v3);
7506 goto VARIANT_MakeDate_OK;
7507 }
7508 dwAllOrders &= ~ORDER_YDM;
7509 }
7510 if (dwTry & ORDER_DMY)
7511 {
7512 if (VARIANT_IsValidMonthDay(v1,v2,v3))
7513 goto VARIANT_MakeDate_OK;
7514 dwAllOrders &= ~ORDER_DMY;
7515 }
7516 if (dwTry & ORDER_MYD)
7517 {
7518 /* Only occurs if we are trying a 2 year date as M/Y not D/M */
7519 if (VARIANT_IsValidMonthDay(v3,v1,v2))
7520 {
7521 DATE_SWAP(v1,v3);
7522 DATE_SWAP(v2,v3);
7523 goto VARIANT_MakeDate_OK;
7524 }
7525 dwAllOrders &= ~ORDER_MYD;
7526 }
7527 }
7528
7529 if (dp->dwCount == 2)
7530 {
7531 /* We couldn't make a date as D/M or M/D, so try M/Y or Y/M */
7532 v3 = 1; /* 1st of the month */
7533 dwAllOrders = ORDER_YMD|ORDER_MYD;
7534 dp->dwCount = 0; /* Don't return to this code path again */
7535 dwCount = 0;
7536 goto VARIANT_MakeDate_Start;
7537 }
7538
7539 /* No valid dates were able to be constructed */
7540 return DISP_E_TYPEMISMATCH;
7541
7542 VARIANT_MakeDate_OK:
7543
7544 /* Check that the time part is ok */
7545 if (st->wHour > 23 || st->wMinute > 59 || st->wSecond > 59)
7546 return DISP_E_TYPEMISMATCH;
7547
7548 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7549 if (st->wHour < 12 && (dp->dwParseFlags & DP_PM))
7550 st->wHour += 12;
7551 else if (st->wHour == 12 && (dp->dwParseFlags & DP_AM))
7552 st->wHour = 0;
7553 TRACE("Time %d %d %d\n", st->wHour, st->wMinute, st->wSecond);
7554
7555 st->wDay = v1;
7556 st->wMonth = v2;
7557 /* FIXME: For 2 digit dates, I'm not sure if 30 is hard coded or not. It may
7558 * be retrieved from:
7559 * HKCU\Control Panel\International\Calendars\TwoDigitYearMax
7560 * But Wine doesn't have/use that key as at the time of writing.
7561 */
7562 st->wYear = v3 < 30 ? 2000 + v3 : v3 < 100 ? 1900 + v3 : v3;
7563 TRACE("Returning date %d/%d/%d\n", v1, v2, st->wYear);
7564 return S_OK;
7565 }
7566
7567 /******************************************************************************
7568 * VarDateFromStr [OLEAUT32.94]
7569 *
7570 * Convert a VT_BSTR to at VT_DATE.
7571 *
7572 * PARAMS
7573 * strIn [I] String to convert
7574 * lcid [I] Locale identifier for the conversion
7575 * dwFlags [I] Flags affecting the conversion (VAR_ flags from "oleauto.h")
7576 * pdateOut [O] Destination for the converted value
7577 *
7578 * RETURNS
7579 * Success: S_OK. pdateOut contains the converted value.
7580 * FAILURE: An HRESULT error code indicating the problem.
7581 *
7582 * NOTES
7583 * Any date format that can be created using the date formats from lcid
7584 * (Either from kernel Nls functions, variant conversion or formatting) is a
7585 * valid input to this function. In addition, a few more esoteric formats are
7586 * also supported for compatibility with the native version. The date is
7587 * interpreted according to the date settings in the control panel, unless
7588 * the date is invalid in that format, in which the most compatible format
7589 * that produces a valid date will be used.
7590 */
7591 HRESULT WINAPI VarDateFromStr(OLECHAR* strIn, LCID lcid, ULONG dwFlags, DATE* pdateOut)
7592 {
7593 static const USHORT ParseDateTokens[] =
7594 {
7595 LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME4,
7596 LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8,
7597 LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12,
7598 LOCALE_SMONTHNAME13,
7599 LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3,
7600 LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
7601 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9,
7602 LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12,
7603 LOCALE_SABBREVMONTHNAME13,
7604 LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
7605 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7,
7606 LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3,
7607 LOCALE_SABBREVDAYNAME4, LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6,
7608 LOCALE_SABBREVDAYNAME7,
7609 LOCALE_S1159, LOCALE_S2359,
7610 LOCALE_SDATE
7611 };
7612 static const BYTE ParseDateMonths[] =
7613 {
7614 1,2,3,4,5,6,7,8,9,10,11,12,13,
7615 1,2,3,4,5,6,7,8,9,10,11,12,13
7616 };
7617 unsigned int i;
7618 BSTR tokens[sizeof(ParseDateTokens)/sizeof(ParseDateTokens[0])];
7619 DATEPARSE dp;
7620 DWORD dwDateSeps = 0, iDate = 0;
7621 HRESULT hRet = S_OK;
7622
7623 if ((dwFlags & (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY)) ==
7624 (VAR_TIMEVALUEONLY|VAR_DATEVALUEONLY))
7625 return E_INVALIDARG;
7626
7627 if (!strIn)
7628 return DISP_E_TYPEMISMATCH;
7629
7630 *pdateOut = 0.0;
7631
7632 TRACE("(%s,0x%08x,0x%08x,%p)\n", debugstr_w(strIn), lcid, dwFlags, pdateOut);
7633
7634 memset(&dp, 0, sizeof(dp));
7635
7636 GetLocaleInfoW(lcid, LOCALE_IDATE|LOCALE_RETURN_NUMBER|(dwFlags & LOCALE_NOUSEROVERRIDE),
7637 (LPWSTR)&iDate, sizeof(iDate)/sizeof(WCHAR));
7638 TRACE("iDate is %d\n", iDate);
7639
7640 /* Get the month/day/am/pm tokens for this locale */
7641 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7642 {
7643 WCHAR buff[128];
7644 LCTYPE lctype = ParseDateTokens[i] | (dwFlags & LOCALE_NOUSEROVERRIDE);
7645
7646 /* FIXME: Alternate calendars - should use GetCalendarInfo() and/or
7647 * GetAltMonthNames(). We should really cache these strings too.
7648 */
7649 buff[0] = '\0';
7650 GetLocaleInfoW(lcid, lctype, buff, sizeof(buff)/sizeof(WCHAR));
7651 tokens[i] = SysAllocString(buff);
7652 TRACE("token %d is %s\n", i, debugstr_w(tokens[i]));
7653 }
7654
7655 /* Parse the string into our structure */
7656 while (*strIn)
7657 {
7658 if (isdigitW(*strIn))
7659 {
7660 if (dp.dwCount >= 6)
7661 {
7662 hRet = DISP_E_TYPEMISMATCH;
7663 break;
7664 }
7665 dp.dwValues[dp.dwCount] = strtoulW(strIn, &strIn, 10);
7666 dp.dwCount++;
7667 strIn--;
7668 }
7669 else if (isalphaW(*strIn))
7670 {
7671 BOOL bFound = FALSE;
7672
7673 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7674 {
7675 DWORD dwLen = strlenW(tokens[i]);
7676 if (dwLen && !strncmpiW(strIn, tokens[i], dwLen))
7677 {
7678 if (i <= 25)
7679 {
7680 if (dp.dwCount >= 6)
7681 hRet = DISP_E_TYPEMISMATCH;
7682 else
7683 {
7684 dp.dwValues[dp.dwCount] = ParseDateMonths[i];
7685 dp.dwFlags[dp.dwCount] |= (DP_MONTH|DP_DATESEP);
7686 dp.dwCount++;
7687 }
7688 }
7689 else if (i > 39 && i < 42)
7690 {
7691 if (!dp.dwCount || dp.dwParseFlags & (DP_AM|DP_PM))
7692 hRet = DISP_E_TYPEMISMATCH;
7693 else
7694 {
7695 dp.dwFlags[dp.dwCount - 1] |= (i == 40 ? DP_AM : DP_PM);
7696 dp.dwParseFlags |= (i == 40 ? DP_AM : DP_PM);
7697 }
7698 }
7699 strIn += (dwLen - 1);
7700 bFound = TRUE;
7701 break;
7702 }
7703 }
7704
7705 if (!bFound)
7706 {
7707 if ((*strIn == 'a' || *strIn == 'A' || *strIn == 'p' || *strIn == 'P') &&
7708 (dp.dwCount && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7709 {
7710 /* Special case - 'a' and 'p' are recognised as short for am/pm */
7711 if (*strIn == 'a' || *strIn == 'A')
7712 {
7713 dp.dwFlags[dp.dwCount - 1] |= DP_AM;
7714 dp.dwParseFlags |= DP_AM;
7715 }
7716 else
7717 {
7718 dp.dwFlags[dp.dwCount - 1] |= DP_PM;
7719 dp.dwParseFlags |= DP_PM;
7720 }
7721 strIn++;
7722 }
7723 else
7724 {
7725 TRACE("No matching token for %s\n", debugstr_w(strIn));
7726 hRet = DISP_E_TYPEMISMATCH;
7727 break;
7728 }
7729 }
7730 }
7731 else if (*strIn == ':' || *strIn == '.')
7732 {
7733 if (!dp.dwCount || !strIn[1])
7734 hRet = DISP_E_TYPEMISMATCH;
7735 else
7736 if (tokens[42][0] == *strIn)
7737 {
7738 dwDateSeps++;
7739 if (dwDateSeps > 2)
7740 hRet = DISP_E_TYPEMISMATCH;
7741 else
7742 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7743 }
7744 else
7745 dp.dwFlags[dp.dwCount - 1] |= DP_TIMESEP;
7746 }
7747 else if (*strIn == '-' || *strIn == '/')
7748 {
7749 dwDateSeps++;
7750 if (dwDateSeps > 2 || !dp.dwCount || !strIn[1])
7751 hRet = DISP_E_TYPEMISMATCH;
7752 else
7753 dp.dwFlags[dp.dwCount - 1] |= DP_DATESEP;
7754 }
7755 else if (*strIn == ',' || isspaceW(*strIn))
7756 {
7757 if (*strIn == ',' && !strIn[1])
7758 hRet = DISP_E_TYPEMISMATCH;
7759 }
7760 else
7761 {
7762 hRet = DISP_E_TYPEMISMATCH;
7763 }
7764 strIn++;
7765 }
7766
7767 if (!dp.dwCount || dp.dwCount > 6 ||
7768 (dp.dwCount == 1 && !(dp.dwParseFlags & (DP_AM|DP_PM))))
7769 hRet = DISP_E_TYPEMISMATCH;
7770
7771 if (SUCCEEDED(hRet))
7772 {
7773 SYSTEMTIME st;
7774 DWORD dwOffset = 0; /* Start of date fields in dp.dwValues */
7775
7776 st.wDayOfWeek = st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
7777
7778 /* Figure out which numbers correspond to which fields.
7779 *
7780 * This switch statement works based on the fact that native interprets any
7781 * fields that are not joined with a time separator ('.' or ':') as date
7782 * fields. Thus we construct a value from 0-32 where each set bit indicates
7783 * a time field. This encapsulates the hundreds of permutations of 2-6 fields.
7784 * For valid permutations, we set dwOffset to point to the first date field
7785 * and shorten dp.dwCount by the number of time fields found. The real
7786 * magic here occurs in VARIANT_MakeDate() above, where we determine what
7787 * each date number must represent in the context of iDate.
7788 */
7789 TRACE("0x%08x\n", TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4));
7790
7791 switch (TIMEFLAG(0)|TIMEFLAG(1)|TIMEFLAG(2)|TIMEFLAG(3)|TIMEFLAG(4))
7792 {
7793 case 0x1: /* TT TTDD TTDDD */
7794 if (dp.dwCount > 3 &&
7795 ((dp.dwFlags[2] & (DP_AM|DP_PM)) || (dp.dwFlags[3] & (DP_AM|DP_PM)) ||
7796 (dp.dwFlags[4] & (DP_AM|DP_PM))))
7797 hRet = DISP_E_TYPEMISMATCH;
7798 else if (dp.dwCount != 2 && dp.dwCount != 4 && dp.dwCount != 5)
7799 hRet = DISP_E_TYPEMISMATCH;
7800 st.wHour = dp.dwValues[0];
7801 st.wMinute = dp.dwValues[1];
7802 dp.dwCount -= 2;
7803 dwOffset = 2;
7804 break;
7805
7806 case 0x3: /* TTT TTTDD TTTDDD */
7807 if (dp.dwCount > 4 &&
7808 ((dp.dwFlags[3] & (DP_AM|DP_PM)) || (dp.dwFlags[4] & (DP_AM|DP_PM)) ||
7809 (dp.dwFlags[5] & (DP_AM|DP_PM))))
7810 hRet = DISP_E_TYPEMISMATCH;
7811 else if (dp.dwCount != 3 && dp.dwCount != 5 && dp.dwCount != 6)
7812 hRet = DISP_E_TYPEMISMATCH;
7813 st.wHour = dp.dwValues[0];
7814 st.wMinute = dp.dwValues[1];
7815 st.wSecond = dp.dwValues[2];
7816 dwOffset = 3;
7817 dp.dwCount -= 3;
7818 break;
7819
7820 case 0x4: /* DDTT */
7821 if (dp.dwCount != 4 ||
7822 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7823 hRet = DISP_E_TYPEMISMATCH;
7824
7825 st.wHour = dp.dwValues[2];
7826 st.wMinute = dp.dwValues[3];
7827 dp.dwCount -= 2;
7828 break;
7829
7830 case 0x0: /* T DD DDD TDDD TDDD */
7831 if (dp.dwCount == 1 && (dp.dwParseFlags & (DP_AM|DP_PM)))
7832 {
7833 st.wHour = dp.dwValues[0]; /* T */
7834 dp.dwCount = 0;
7835 break;
7836 }
7837 else if (dp.dwCount > 4 || (dp.dwCount < 3 && dp.dwParseFlags & (DP_AM|DP_PM)))
7838 {
7839 hRet = DISP_E_TYPEMISMATCH;
7840 }
7841 else if (dp.dwCount == 3)
7842 {
7843 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDD */
7844 {
7845 dp.dwCount = 2;
7846 st.wHour = dp.dwValues[0];
7847 dwOffset = 1;
7848 break;
7849 }
7850 if (dp.dwFlags[2] & (DP_AM|DP_PM)) /* DDT */
7851 {
7852 dp.dwCount = 2;
7853 st.wHour = dp.dwValues[2];
7854 break;
7855 }
7856 else if (dp.dwParseFlags & (DP_AM|DP_PM))
7857 hRet = DISP_E_TYPEMISMATCH;
7858 }
7859 else if (dp.dwCount == 4)
7860 {
7861 dp.dwCount = 3;
7862 if (dp.dwFlags[0] & (DP_AM|DP_PM)) /* TDDD */
7863 {
7864 st.wHour = dp.dwValues[0];
7865 dwOffset = 1;
7866 }
7867 else if (dp.dwFlags[3] & (DP_AM|DP_PM)) /* DDDT */
7868 {
7869 st.wHour = dp.dwValues[3];
7870 }
7871 else
7872 hRet = DISP_E_TYPEMISMATCH;
7873 break;
7874 }
7875 /* .. fall through .. */
7876
7877 case 0x8: /* DDDTT */
7878 if ((dp.dwCount == 2 && (dp.dwParseFlags & (DP_AM|DP_PM))) ||
7879 (dp.dwCount == 5 && ((dp.dwFlags[0] & (DP_AM|DP_PM)) ||
7880 (dp.dwFlags[1] & (DP_AM|DP_PM)) || (dp.dwFlags[2] & (DP_AM|DP_PM)))) ||
7881 dp.dwCount == 4 || dp.dwCount == 6)
7882 hRet = DISP_E_TYPEMISMATCH;
7883 st.wHour = dp.dwValues[3];
7884 st.wMinute = dp.dwValues[4];
7885 if (dp.dwCount == 5)
7886 dp.dwCount -= 2;
7887 break;
7888
7889 case 0xC: /* DDTTT */
7890 if (dp.dwCount != 5 ||
7891 (dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)))
7892 hRet = DISP_E_TYPEMISMATCH;
7893 st.wHour = dp.dwValues[2];
7894 st.wMinute = dp.dwValues[3];
7895 st.wSecond = dp.dwValues[4];
7896 dp.dwCount -= 3;
7897 break;
7898
7899 case 0x18: /* DDDTTT */
7900 if ((dp.dwFlags[0] & (DP_AM|DP_PM)) || (dp.dwFlags[1] & (DP_AM|DP_PM)) ||
7901 (dp.dwFlags[2] & (DP_AM|DP_PM)))
7902 hRet = DISP_E_TYPEMISMATCH;
7903 st.wHour = dp.dwValues[3];
7904 st.wMinute = dp.dwValues[4];
7905 st.wSecond = dp.dwValues[5];
7906 dp.dwCount -= 3;
7907 break;
7908
7909 default:
7910 hRet = DISP_E_TYPEMISMATCH;
7911 break;
7912 }
7913
7914 if (SUCCEEDED(hRet))
7915 {
7916 hRet = VARIANT_MakeDate(&dp, iDate, dwOffset, &st);
7917
7918 if (dwFlags & VAR_TIMEVALUEONLY)
7919 {
7920 st.wYear = 1899;
7921 st.wMonth = 12;
7922 st.wDay = 30;
7923 }
7924 else if (dwFlags & VAR_DATEVALUEONLY)
7925 st.wHour = st.wMinute = st.wSecond = 0;
7926
7927 /* Finally, convert the value to a VT_DATE */
7928 if (SUCCEEDED(hRet))
7929 hRet = SystemTimeToVariantTime(&st, pdateOut) ? S_OK : DISP_E_TYPEMISMATCH;
7930 }
7931 }
7932
7933 for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++)
7934 SysFreeString(tokens[i]);
7935 return hRet;
7936 }
7937
7938 /******************************************************************************
7939 * VarDateFromI1 (OLEAUT32.221)
7940 *
7941 * Convert a VT_I1 to a VT_DATE.
7942 *
7943 * PARAMS
7944 * cIn [I] Source
7945 * pdateOut [O] Destination
7946 *
7947 * RETURNS
7948 * S_OK.
7949 */
7950 HRESULT WINAPI VarDateFromI1(signed char cIn, DATE* pdateOut)
7951 {
7952 return VarR8FromI1(cIn, pdateOut);
7953 }
7954
7955 /******************************************************************************
7956 * VarDateFromUI2 (OLEAUT32.222)
7957 *
7958 * Convert a VT_UI2 to a VT_DATE.
7959 *
7960 * PARAMS
7961 * uiIn [I] Source
7962 * pdateOut [O] Destination
7963 *
7964 * RETURNS
7965 * S_OK.
7966 */
7967 HRESULT WINAPI VarDateFromUI2(USHORT uiIn, DATE* pdateOut)
7968 {
7969 return VarR8FromUI2(uiIn, pdateOut);
7970 }
7971
7972 /******************************************************************************
7973 * VarDateFromUI4 (OLEAUT32.223)
7974 *
7975 * Convert a VT_UI4 to a VT_DATE.
7976 *
7977 * PARAMS
7978 * ulIn [I] Source
7979 * pdateOut [O] Destination
7980 *
7981 * RETURNS
7982 * S_OK.
7983 */
7984 HRESULT WINAPI VarDateFromUI4(ULONG ulIn, DATE* pdateOut)
7985 {
7986 return VarDateFromR8(ulIn, pdateOut);
7987 }
7988
7989 /**********************************************************************
7990 * VarDateFromDec (OLEAUT32.224)
7991 *
7992 * Convert a VT_DECIMAL to a VT_DATE.
7993 *
7994 * PARAMS
7995 * pdecIn [I] Source
7996 * pdateOut [O] Destination
7997 *
7998 * RETURNS
7999 * S_OK.
8000 */
8001 HRESULT WINAPI VarDateFromDec(DECIMAL *pdecIn, DATE* pdateOut)
8002 {
8003 return VarR8FromDec(pdecIn, pdateOut);
8004 }
8005
8006 /******************************************************************************
8007 * VarDateFromI8 (OLEAUT32.364)
8008 *
8009 * Convert a VT_I8 to a VT_DATE.
8010 *
8011 * PARAMS
8012 * llIn [I] Source
8013 * pdateOut [O] Destination
8014 *
8015 * RETURNS
8016 * Success: S_OK.
8017 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8018 */
8019 HRESULT WINAPI VarDateFromI8(LONG64 llIn, DATE* pdateOut)
8020 {
8021 if (llIn < DATE_MIN || llIn > DATE_MAX) return DISP_E_OVERFLOW;
8022 *pdateOut = (DATE)llIn;
8023 return S_OK;
8024 }
8025
8026 /******************************************************************************
8027 * VarDateFromUI8 (OLEAUT32.365)
8028 *
8029 * Convert a VT_UI8 to a VT_DATE.
8030 *
8031 * PARAMS
8032 * ullIn [I] Source
8033 * pdateOut [O] Destination
8034 *
8035 * RETURNS
8036 * Success: S_OK.
8037 * Failure: DISP_E_OVERFLOW, if the value will not fit in the destination
8038 */
8039 HRESULT WINAPI VarDateFromUI8(ULONG64 ullIn, DATE* pdateOut)
8040 {
8041 if (ullIn > DATE_MAX) return DISP_E_OVERFLOW;
8042 *pdateOut = (DATE)ullIn;
8043 return S_OK;
8044 }