Changeset 9986 for trunk/src/NTDLL/large_int.c
- Timestamp:
- Apr 7, 2003, 8:40:53 PM (22 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/NTDLL/large_int.c
r9684 r9986 3 3 * 4 4 * Copyright 2000 Alexandre Julliard 5 * Copyright 2003 Thomas Mertes 5 6 * 6 7 * This library is free software; you can redistribute it and/or … … 185 186 * This function computes (a * b) >> (64 + shift) 186 187 * 187 * This allows replacing a division by a longlong constant 188 * by a multiplication by the inverse constant. 189 * 190 * If 'c' is the constant divisor, the constants 'b' and 'shift' 191 * must be chosen such that b = 2^(64+shift) / c. 192 * Then we have RtlExtendedMagicDivide(a,b,shift) == a * b / 2^(64+shift) == a / c. 193 * 194 * I'm too lazy to implement it right now... 195 */ 196 /* LONGLONG WINAPI RtlExtendedMagicDivide( LONGLONG a, LONGLONG b, INT shift ) 197 * { 198 * return 0; 199 * } 200 */ 188 * RETURNS 189 * (a * b) >> (64 + shift) 190 * 191 * NOTES 192 * This allows replacing a division by a longlong constant 193 * by a multiplication by the inverse constant. 194 * 195 * If 'c' is the constant divisor, the constants 'b' and 'shift' 196 * must be chosen such that b = 2^(64+shift) / c. 197 * Then we have RtlExtendedMagicDivide(a,b,shift) == a * b / 2^(64+shift) == a / c. 198 * 199 * The Parameter b although defined as LONGLONG is used as ULONGLONG. 200 */ 201 #define LOWER_32(A) ((A) & 0xffffffff) 202 #define UPPER_32(A) ((A) >> 32) 203 LONGLONG WINAPI RtlExtendedMagicDivide( 204 LONGLONG a, /* [I] Dividend to be divided by the constant divisor */ 205 LONGLONG b, /* [I] Constant computed manually as 2^(64+shift) / divisor */ 206 INT shift) /* [I] Constant shift chosen to make b as big as possible for 64 bits */ 207 { 208 ULONGLONG a_high; 209 ULONGLONG a_low; 210 ULONGLONG b_high; 211 ULONGLONG b_low; 212 ULONGLONG ah_bl; 213 ULONGLONG al_bh; 214 LONGLONG result; 215 int positive; 216 217 if (a < 0) { 218 a_high = UPPER_32((ULONGLONG) -a); 219 a_low = LOWER_32((ULONGLONG) -a); 220 positive = 0; 221 } else { 222 a_high = UPPER_32((ULONGLONG) a); 223 a_low = LOWER_32((ULONGLONG) a); 224 positive = 1; 225 } /* if */ 226 b_high = UPPER_32((ULONGLONG) b); 227 b_low = LOWER_32((ULONGLONG) b); 228 229 ah_bl = a_high * b_low; 230 al_bh = a_low * b_high; 231 232 result = (LONGLONG) ((a_high * b_high + 233 UPPER_32(ah_bl) + 234 UPPER_32(al_bh) + 235 UPPER_32(LOWER_32(ah_bl) + LOWER_32(al_bh) + UPPER_32(a_low * b_low))) >> shift); 236 237 if (positive) { 238 return result; 239 } else { 240 return -result; 241 } /* if */ 242 } 243 244 245 /****************************************************************************** 246 * RtlLargeIntegerToChar [NTDLL.@] 247 * 248 * Convert an unsigned large integer to a character string. 249 * 250 * RETURNS 251 * Success: STATUS_SUCCESS. str contains the converted number 252 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16. 253 * STATUS_BUFFER_OVERFLOW, if str would be larger than length. 254 * STATUS_ACCESS_VIOLATION, if str is NULL. 255 * 256 * NOTES 257 * Instead of base 0 it uses 10 as base. 258 * Writes at most length characters to the string str. 259 * Str is '\0' terminated when length allowes it. 260 * When str fits exactly in length characters the '\0' is ommitted. 261 * If value_ptr is NULL it crashes, as the native function does. 262 * 263 * DIFFERENCES 264 * - Accept base 0 as 10 instead of crashing as native function does. 265 * - The native function does produce garbage or STATUS_BUFFER_OVERFLOW for 266 * base 2, 8 and 16 when the value is larger than 0xFFFFFFFF. 267 */ 268 NTSTATUS WINAPI RtlLargeIntegerToChar( 269 const ULONGLONG *value_ptr, /* [I] Pointer to the value to be converted */ 270 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */ 271 ULONG length, /* [I] Length of the str buffer in bytes */ 272 PCHAR str) /* [O] Destination for the converted value */ 273 { 274 ULONGLONG value = *value_ptr; 275 CHAR buffer[65]; 276 PCHAR pos; 277 CHAR digit; 278 ULONG len; 279 280 if (base == 0) { 281 base = 10; 282 } else if (base != 2 && base != 8 && base != 10 && base != 16) { 283 return STATUS_INVALID_PARAMETER; 284 } /* if */ 285 286 pos = &buffer[64]; 287 *pos = '\0'; 288 289 do { 290 pos--; 291 digit = value % base; 292 value = value / base; 293 if (digit < 10) { 294 *pos = '0' + digit; 295 } else { 296 *pos = 'A' + digit - 10; 297 } /* if */ 298 } while (value != 0L); 299 300 len = &buffer[64] - pos; 301 if (len > length) { 302 return STATUS_BUFFER_OVERFLOW; 303 } else if (str == NULL) { 304 return STATUS_ACCESS_VIOLATION; 305 } else if (len == length) { 306 memcpy(str, pos, len); 307 } else { 308 memcpy(str, pos, len + 1); 309 } /* if */ 310 return STATUS_SUCCESS; 311 } 312 313 314 /************************************************************************** 315 * RtlInt64ToUnicodeString (NTDLL.@) 316 * 317 * Convert a large unsigned integer to a '\0' terminated unicode string. 318 * 319 * RETURNS 320 * Success: STATUS_SUCCESS. str contains the converted number 321 * Failure: STATUS_INVALID_PARAMETER, if base is not 0, 2, 8, 10 or 16. 322 * STATUS_BUFFER_OVERFLOW, if str is too small to hold the string 323 * (with the '\0' termination). In this case str->Length 324 * is set to the length, the string would have (which can 325 * be larger than the MaximumLength). 326 * 327 * NOTES 328 * Instead of base 0 it uses 10 as base. 329 * If str is NULL it crashes, as the native function does. 330 * 331 * DIFFERENCES 332 * - Accept base 0 as 10 instead of crashing as native function does. 333 * - Do not return STATUS_BUFFER_OVERFLOW when the string is long enough. 334 * The native function does this when the string would be longer than 31 335 * characters even when the string parameter is long enough. 336 * - The native function does produce garbage or STATUS_BUFFER_OVERFLOW for 337 * base 2, 8 and 16 when the value is larger than 0xFFFFFFFF. 338 */ 339 NTSTATUS WINAPI RtlInt64ToUnicodeString( 340 ULONGLONG value, /* [I] Value to be converted */ 341 ULONG base, /* [I] Number base for conversion (allowed 0, 2, 8, 10 or 16) */ 342 UNICODE_STRING *str) /* [O] Destination for the converted value */ 343 { 344 WCHAR buffer[65]; 345 PWCHAR pos; 346 WCHAR digit; 347 348 if (base == 0) { 349 base = 10; 350 } else if (base != 2 && base != 8 && base != 10 && base != 16) { 351 return STATUS_INVALID_PARAMETER; 352 } /* if */ 353 354 pos = &buffer[64]; 355 *pos = '\0'; 356 357 do { 358 pos--; 359 digit = value % base; 360 value = value / base; 361 if (digit < 10) { 362 *pos = '0' + digit; 363 } else { 364 *pos = 'A' + digit - 10; 365 } /* if */ 366 } while (value != 0L); 367 368 str->Length = (&buffer[64] - pos) * sizeof(WCHAR); 369 if (str->Length >= str->MaximumLength) { 370 return STATUS_BUFFER_OVERFLOW; 371 } else { 372 memcpy(str->Buffer, pos, str->Length + sizeof(WCHAR)); 373 } /* if */ 374 return STATUS_SUCCESS; 375 } 201 376 202 377 … … 244 419 return a % b; 245 420 } 246
Note:
See TracChangeset
for help on using the changeset viewer.