1/*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*	CFBigNumber.c
25	Copyright (c) 2012-2013, Apple Inc. All rights reserved.
26	Responsibility: Christopher Kane
27	Original author: Zhi Feng Huang
28*/
29
30#include <CoreFoundation/CFBigNumber.h>
31#include <limits.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdio.h>
35#include "CFInternal.h"
36
37
38typedef struct {
39    int64_t high;
40    uint64_t low;
41} CFSInt128Struct;
42
43#define kCFNumberSInt128Type 17
44
45CF_EXPORT CFNumberType _CFNumberGetType2(CFNumberRef number);
46
47#if __LP64__
48
49#ifndef _INT128_T
50#define _INT128_T
51typedef __int128_t  int128_t;
52#endif
53
54#ifndef _UINT128_T
55#define _UINT128_T
56typedef __uint128_t uint128_t;
57#endif
58
59#ifndef INT128_MIN
60#define INT128_MIN  ((__int128_t)0 - ((__int128_t)1 << 126) - ((__int128_t)1 << 126))
61#endif
62
63#ifndef INT128_MAX
64#define INT128_MAX  ((__int128_t)-1 + ((__int128_t)1 << 126) + ((__int128_t)1 << 126))
65#endif
66
67#ifndef UINT128_MAX
68#define UINT128_MAX (((__uint128_t)1 << 127) - (__uint128_t)1 + ((__uint128_t)1 << 127))
69#endif
70
71#endif
72
73
74#define BIG_DIGITS_LIMIT    1000000000L
75#define BIG_DIGITS_LIMIT_2  ((uint64_t)BIG_DIGITS_LIMIT * (uint64_t)BIG_DIGITS_LIMIT)
76#define BIG_DIGITS_LIMIT_3  ((__uint128_t)BIG_DIGITS_LIMIT_2 * (__uint128_t)BIG_DIGITS_LIMIT)
77#define BIG_DIGITS_LIMIT_4  ((__uint128_t)BIG_DIGITS_LIMIT_3 * (__uint128_t)BIG_DIGITS_LIMIT)
78
79#define GET_FIFTH_DIGIT(A)  (A / BIG_DIGITS_LIMIT_4)
80#define GET_FOURTH_DIGIT(A) (A / BIG_DIGITS_LIMIT_3)
81#define GET_THIRD_DIGIT(A)  (A / BIG_DIGITS_LIMIT_2)
82#define GET_SECOND_DIGIT(A) (A / BIG_DIGITS_LIMIT)
83
84#define GET_REMAINDER_FIFTH_DIGIT(A,B)  (A - B * BIG_DIGITS_LIMIT_4)
85#define GET_REMAINDER_FOURTH_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT_3)
86#define GET_REMAINDER_THIRD_DIGIT(A,B)  (A - B * BIG_DIGITS_LIMIT_2)
87#define GET_REMAINDER_SECOND_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT)
88
89
90void _CFBigNumInitWithInt8(_CFBigNum *r, int8_t inNum) {
91    memset(r, 0, sizeof(*r));
92    uint8_t unsignInNum = inNum;
93    if (inNum < 0) {
94        r->sign = -1;
95        unsignInNum = -1 * inNum;
96    }
97    r->digits[0] = unsignInNum;
98}
99
100void _CFBigNumInitWithInt16(_CFBigNum *r, int16_t inNum) {
101    memset(r, 0, sizeof(*r));
102    uint16_t unsignInNum = inNum;
103    if (inNum < 0) {
104        r->sign = -1;
105        unsignInNum = -1 * inNum;
106    }
107    r->digits[0] = unsignInNum;
108}
109
110void _CFBigNumInitWithInt32(_CFBigNum *r, int32_t inNum) {
111    memset(r, 0, sizeof(*r));
112    uint32_t unsignInNum = inNum;
113    if (inNum < 0) {
114        r->sign = -1;
115        unsignInNum = -1 * inNum;
116    }
117    uint32_t dig0 = GET_SECOND_DIGIT(unsignInNum);
118    r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, dig0);
119    r->digits[1] = dig0;
120}
121
122void _CFBigNumInitWithInt64(_CFBigNum *r, int64_t inNum) {
123    memset(r, 0, sizeof(*r));
124    uint64_t unsignInNum = inNum;
125    if (inNum < 0) {
126        r->sign = -1;
127        unsignInNum = -1 * inNum;
128    }
129    uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum);
130    unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (uint64_t)dig2);
131    uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum);
132    r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (uint64_t)dig1);
133    r->digits[1] = dig1;
134    r->digits[2] = dig2;
135}
136
137#ifdef __LP64__
138void _CFBigNumInitWithInt128(_CFBigNum *r, __int128_t inNum) {
139    memset(r, 0, sizeof(*r));
140    __uint128_t unsignInNum = inNum;
141    if (inNum < 0) {
142        r->sign = -1;
143        unsignInNum = -1 * inNum;
144    }
145    uint32_t dig4 = GET_FIFTH_DIGIT(unsignInNum);
146    unsignInNum = GET_REMAINDER_FIFTH_DIGIT(unsignInNum, (__uint128_t)dig4);
147    uint32_t dig3 = GET_FOURTH_DIGIT(unsignInNum);
148    unsignInNum = GET_REMAINDER_FOURTH_DIGIT(unsignInNum, (__uint128_t)dig3);
149    uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum);
150    unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (__uint128_t)dig2);
151    uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum);
152    r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (__uint128_t)dig1);
153    r->digits[1] = dig1;
154    r->digits[2] = dig2;
155    r->digits[3] = dig3;
156    r->digits[4] = dig4;
157}
158#endif
159
160void _CFBigNumInitWithUInt8(_CFBigNum *r, uint8_t inNum) {
161    memset(r, 0, sizeof(*r));
162    uint8_t unsignInNum = inNum;
163    r->digits[0] = unsignInNum;
164}
165
166void _CFBigNumInitWithUInt16(_CFBigNum *r, uint16_t inNum) {
167    memset(r, 0, sizeof(*r));
168    uint16_t unsignInNum = inNum;
169    r->digits[0] = unsignInNum;
170}
171
172void _CFBigNumInitWithUInt32(_CFBigNum *r, uint32_t inNum) {
173    memset(r, 0, sizeof(*r));
174    uint32_t unsignInNum = inNum;
175    uint32_t dig0 = GET_SECOND_DIGIT(unsignInNum);
176    r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, dig0);
177    r->digits[1] = dig0;
178}
179
180void _CFBigNumInitWithUInt64(_CFBigNum *r, uint64_t inNum) {
181    memset(r, 0, sizeof(*r));
182    uint64_t unsignInNum = inNum;
183    uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum);
184    unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (uint64_t)dig2);
185    uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum);
186    r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (uint64_t)dig1);
187    r->digits[1] = dig1;
188    r->digits[2] = dig2;
189}
190
191#ifdef __LP64__
192void _CFBigNumInitWithUInt128(_CFBigNum *r, __uint128_t inNum) {
193    memset(r, 0, sizeof(*r));
194    __uint128_t unsignInNum = inNum;
195    uint32_t dig4 = GET_FIFTH_DIGIT(unsignInNum);
196    unsignInNum = GET_REMAINDER_FIFTH_DIGIT(unsignInNum, (__uint128_t)dig4);
197    uint32_t dig3 = GET_FOURTH_DIGIT(unsignInNum);
198    unsignInNum = GET_REMAINDER_FOURTH_DIGIT(unsignInNum, (__uint128_t)dig3);
199    uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum);
200    unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (__uint128_t)dig2);
201    uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum);
202    r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (__uint128_t)dig1);
203    r->digits[1] = dig1;
204    r->digits[2] = dig2;
205    r->digits[3] = dig3;
206    r->digits[4] = dig4;
207}
208#endif
209
210
211int8_t _CFBigNumGetInt8(const _CFBigNum *num) {
212    int8_t result = num->digits[0];
213    if (num->sign < 0) {
214        result = -1 * result;
215    }
216    return result;
217}
218
219int16_t _CFBigNumGetInt16(const _CFBigNum *num) {
220    int16_t result = num->digits[0];
221    if (num->sign < 0) {
222        result = -1 * result;
223    }
224    return result;
225}
226
227int32_t _CFBigNumGetInt32(const _CFBigNum *num) {
228    int32_t result = num->digits[0];
229    result += num->digits[1] * BIG_DIGITS_LIMIT;
230    if (num->sign < 0) {
231        result = -1 * result;
232    }
233    return result;
234}
235
236int64_t _CFBigNumGetInt64(const _CFBigNum *num) {
237    int64_t result = num->digits[0];
238    result += (int64_t)num->digits[1] * BIG_DIGITS_LIMIT;
239    result += (int64_t)num->digits[2] * BIG_DIGITS_LIMIT_2;
240    if (num->sign < 0) {
241        result = -1 * result;
242    }
243    return result;
244}
245
246#if __LP64__
247__int128_t _CFBigNumGetInt128(const _CFBigNum *num) {
248    __int128_t result = num->digits[0];
249    result += (__int128_t)num->digits[1] * BIG_DIGITS_LIMIT;
250    result += (__int128_t)num->digits[2] * BIG_DIGITS_LIMIT_2;
251    result += (__int128_t)num->digits[3] * BIG_DIGITS_LIMIT_3;
252    result += (__int128_t)num->digits[4] * BIG_DIGITS_LIMIT_4;
253    if (num->sign < 0) {
254        result = -1 * result;
255    }
256    return result;
257}
258#endif
259
260uint8_t _CFBigNumGetUInt8(const _CFBigNum *num) {
261    uint8_t result = num->digits[0];
262    return result;
263}
264
265uint16_t _CFBigNumGetUInt16(const _CFBigNum *num) {
266    uint16_t result = num->digits[0];
267    return result;
268}
269
270uint32_t _CFBigNumGetUInt32(const _CFBigNum *num) {
271    uint32_t result = num->digits[0];
272    result += num->digits[1] * BIG_DIGITS_LIMIT;
273    return result;
274}
275
276uint64_t _CFBigNumGetUInt64(const _CFBigNum *num) {
277    uint64_t result = num->digits[0];
278    result += (uint64_t)num->digits[1] * BIG_DIGITS_LIMIT;
279    result += (uint64_t)num->digits[2] * BIG_DIGITS_LIMIT_2;
280    return result;
281}
282
283#if __LP64__
284__uint128_t _CFBigNumGetUInt128(const _CFBigNum *num) {
285    __uint128_t result = num->digits[0];
286    result += (__uint128_t)num->digits[1] * BIG_DIGITS_LIMIT;
287    result += (__uint128_t)num->digits[2] * BIG_DIGITS_LIMIT_2;
288    result += (__uint128_t)num->digits[3] * BIG_DIGITS_LIMIT_3;
289    result += (__uint128_t)num->digits[4] * BIG_DIGITS_LIMIT_4;
290    return result;
291}
292#endif
293
294
295void _CFBigNumInitWithCFNumber(_CFBigNum *r, CFNumberRef inNum) {
296    uint8_t bytes[128 + 16];
297    memset(bytes, 0, sizeof(bytes));
298    // round bytes up to next multiple of 16; compiler attributes won't always guarantee big alignment
299    void *bytesa = (uint8_t *)(((uintptr_t)bytes / 16) * 16 + 16);
300    CFNumberType type = _CFNumberGetType2(inNum);
301    CFNumberGetValue(inNum, type, bytesa);
302    _CFBigNumInitWithBytes(r, bytesa, type);
303}
304
305void _CFBigNumInitWithBytes(_CFBigNum *r, const void *bytes, CFNumberType type) {
306    switch (type) {
307    case kCFNumberSInt8Type:
308        _CFBigNumInitWithInt8(r, *(int8_t *)bytes);
309        return;
310    case kCFNumberSInt16Type:
311        _CFBigNumInitWithInt16(r, *(int16_t *)bytes);
312        return;
313    case kCFNumberSInt32Type:
314        _CFBigNumInitWithInt32(r, *(int32_t *)bytes);
315        return;
316    case kCFNumberSInt64Type:
317        _CFBigNumInitWithInt64(r, *(int64_t *)bytes);
318        return;
319    case kCFNumberCharType:
320        _CFBigNumInitWithInt8(r, *(int8_t *)bytes);
321        return;
322    case kCFNumberShortType:
323        _CFBigNumInitWithInt16(r, *(int16_t *)bytes);
324        return;
325    case kCFNumberIntType:
326        _CFBigNumInitWithInt32(r, *(int32_t *)bytes);
327        return;
328    case kCFNumberLongType:
329        if (sizeof(long) == 8) {
330            _CFBigNumInitWithInt64(r, *(int64_t *)bytes);
331        } else {
332            _CFBigNumInitWithInt32(r, *(int32_t *)bytes);
333        }
334        return;
335    case kCFNumberLongLongType:
336        _CFBigNumInitWithInt64(r, *(int64_t *)bytes);
337        return;
338    case kCFNumberCFIndexType:
339        if (sizeof(CFIndex) == 8) {
340            _CFBigNumInitWithInt64(r, *(int64_t *)bytes);
341        } else {
342            _CFBigNumInitWithInt32(r, *(int32_t *)bytes);
343        }
344        return;
345    case kCFNumberNSIntegerType:
346        if (sizeof(long) == 8) { // NSInteger follows long
347            _CFBigNumInitWithInt64(r, *(int64_t *)bytes);
348        } else {
349            _CFBigNumInitWithInt32(r, *(int32_t *)bytes);
350        }
351        return;
352#if __LP64__
353    case kCFNumberSInt128Type: {
354        CFSInt128Struct s;
355        memmove(&s, bytes, sizeof(CFSInt128Struct)); // the hard way because bytes might not be aligned
356        __int128_t val = (__int128_t)s.low + ((__int128_t)s.high << 64);
357        _CFBigNumInitWithInt128(r, val);
358        return;
359    }
360#endif
361    default:
362        return;
363    }
364}
365
366CFNumberRef _CFNumberCreateWithBigNum(const _CFBigNum *input) {
367    if (0 == input->digits[4] && 0 == input->digits[3] && 0 == input->digits[2] && 0 == input->digits[1]) {
368        // This bumps up the size of the most negative n-bit value to the next larger size; oh well
369        if (input->digits[0] <= INT8_MAX) {
370            int8_t num = _CFBigNumGetInt8(input);
371            CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt8Type, (const void *)&num);
372            return result;
373        } else if (input->digits[0] <= INT16_MAX) {
374            int16_t num = _CFBigNumGetInt16(input);
375            CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt16Type, (const void *)&num);
376            return result;
377        }
378    }
379    _CFBigNum maxlimit, minlimit;
380    if (0 == input->digits[4] && 0 == input->digits[3] && 0 == input->digits[2]) {
381        _CFBigNumInitWithInt32(&maxlimit, INT32_MAX);
382        _CFBigNumInitWithInt32(&minlimit, INT32_MIN);
383        CFComparisonResult cr = _CFBigNumCompare(input, &maxlimit);
384        CFComparisonResult crn = _CFBigNumCompare(input, &minlimit);
385        if ((kCFCompareLessThan == cr || kCFCompareEqualTo == cr) && (kCFCompareLessThan != crn)) {
386            int32_t num = _CFBigNumGetInt32(input);
387            CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, (const void *)&num);
388            return result;
389        }
390    }
391    if (0 == input->digits[4] && 0 == input->digits[3]) {
392        _CFBigNumInitWithInt64(&maxlimit, INT64_MAX);
393        _CFBigNumInitWithInt64(&minlimit, INT64_MIN);
394        CFComparisonResult cr = _CFBigNumCompare(input, &maxlimit);
395        CFComparisonResult crn = _CFBigNumCompare(input, &minlimit);
396        if ((kCFCompareLessThan == cr || kCFCompareEqualTo == cr) && (kCFCompareLessThan != crn)) {
397            int64_t num = _CFBigNumGetInt64(input);
398            CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt64Type, (const void *)&num);
399            return result;
400        }
401    }
402#if __LP64__
403    _CFBigNumInitWithInt128(&maxlimit, INT128_MAX);
404    _CFBigNumInitWithInt128(&minlimit, INT128_MIN);
405    CFComparisonResult cr = _CFBigNumCompare(input, &maxlimit);
406    CFComparisonResult crn = _CFBigNumCompare(input, &minlimit);
407    if ((kCFCompareLessThan == cr || kCFCompareEqualTo == cr) && (kCFCompareLessThan != crn)) {
408        __int128_t num = _CFBigNumGetInt128(input);
409        CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt128Type, (const void *)&num);
410        return result;
411    }
412#endif
413    return NULL;
414}
415
416CFComparisonResult _CFBigNumCompare(const _CFBigNum *a, const _CFBigNum *b) {
417    Boolean sameSign = a->sign == b->sign;
418    if (sameSign) {
419        Boolean negative = a->sign < 0;
420        for (CFIndex i = sizeof(a->digits) / sizeof(a->digits[0]); i--;) {
421            if (a->digits[i] < b->digits[i]) {
422                return !negative ? kCFCompareLessThan : kCFCompareGreaterThan;
423            }
424            if (a->digits[i] > b->digits[i]) {
425                return negative ? kCFCompareLessThan : kCFCompareGreaterThan;
426            }
427        }
428        return kCFCompareEqualTo;
429    }
430    return (a->sign < b->sign) ? kCFCompareLessThan : kCFCompareGreaterThan;
431}
432
433// abs(a) < abs(b)
434// do not care about the sign
435static Boolean _CFBigNumAbsoluteLessThan(const _CFBigNum *a, const _CFBigNum *b) {
436    for (CFIndex i = sizeof(a->digits) / sizeof(a->digits[0]); i--;) {
437        if (a->digits[i] < b->digits[i]) {
438            return true;
439        }
440        if (a->digits[i] > b->digits[i]) {
441            return false;
442        }
443    }
444    return false;
445}
446
447// r = a * -1
448void _CFBigNumNeg(_CFBigNum *r, const _CFBigNum *a) {
449    memmove(r, a, sizeof(*a));
450    Boolean aIsZero = true;
451    for (CFIndex i = 0; i < sizeof(a->digits) / sizeof(a->digits[0]); i++) {
452        if (a->digits[i] != 0) {
453            aIsZero = false;
454            break;
455        }
456    }
457    // if a is zero, we do not flip the sign
458    if (!aIsZero) {
459        // 0  -> -1
460        // -1 -> 0
461        r->sign = r->sign * r->sign - 1;
462    }
463}
464
465uint8_t _CFBigNumAdd(_CFBigNum *r, const _CFBigNum *a, const _CFBigNum *b) {
466    uint8_t carry = 0;
467    Boolean sameSign = a->sign == b->sign;
468    if (sameSign) {
469        for (CFIndex i = 0; i < sizeof(a->digits) / sizeof(a->digits[0]); i++) {
470            uint32_t result = a->digits[i] + b->digits[i] + carry;
471            if (result > BIG_DIGITS_LIMIT) {
472                carry = 1;
473                result -= BIG_DIGITS_LIMIT;
474            } else {
475                carry = 0;
476            }
477            r->digits[i] = result;
478        }
479        r->sign = a->sign;
480        return carry;
481    } else {
482        // the algorithm here is to find the larger one and do the subtraction and then neg the result if necessary
483        const _CFBigNum *bigNum = NULL;
484        const _CFBigNum *smallNum = NULL;
485        if (_CFBigNumAbsoluteLessThan(a, b)) {
486            bigNum = b;
487            smallNum = a;
488        } else {
489            bigNum = a;
490            smallNum = b;
491        }
492        for (int i = 0; i < sizeof(a->digits) / sizeof(a->digits[0]); i++) {
493            int64_t result = (int64_t)bigNum->digits[i] - (int64_t)smallNum->digits[i] - carry;
494            if (result < 0) {
495                carry = 1;
496                result += BIG_DIGITS_LIMIT;
497            } else {
498                carry = 0;
499            }
500            r->digits[i] = result;
501        }
502        if (bigNum->sign < 0) {
503            r->sign = -1;
504        } else {
505            r->sign = 0;
506        }
507        return carry;
508    }
509}
510
511uint8_t _CFBigNumSub(_CFBigNum *r, const _CFBigNum *a, const _CFBigNum *b) {
512    _CFBigNum nb;
513    _CFBigNumNeg(&nb, b);
514    return _CFBigNumAdd(r, a, &nb);
515}
516
517
518void _CFBigNumToCString(const _CFBigNum *vp, Boolean leading_zeros, Boolean leading_plus, char *buffer, size_t buflen) {
519    if (vp->sign < 0) {
520        *buffer++ = '-';
521        buflen--;
522    } else if (leading_plus) {
523        *buffer++ = '+';
524        buflen--;
525    }
526    char tmp[46];
527    snprintf(tmp, sizeof(tmp), "%09u%09u%09u%09u%09u", vp->digits[4], vp->digits[3], vp->digits[2], vp->digits[1], vp->digits[0]);
528    if (leading_zeros) {
529        memset(buffer, '0', buflen);
530        uint32_t tocopy = __CFMin(sizeof(tmp), buflen);
531        memmove(buffer + buflen - tocopy, tmp + sizeof(tmp) - tocopy, tocopy); // copies trailing nul from tmp to nul-terminate
532    } else {
533        char *s = tmp;
534        while (*s == '0') s++;
535        if (*s == 0) s--; // if tmp is all zeros, copy out at least one zero
536        strlcpy(buffer, s, buflen);
537    }
538}
539
540void _CFBigNumFromCString(_CFBigNum *r, const char *string) {
541    memset(r, 0, sizeof(*r));
542    char *copy = (char *)calloc(strlen(string)+1, sizeof(char));
543    memcpy(copy, string, strlen(string)+1);
544    char *working = copy;
545    if (*working == '-') {
546        r->sign = -1;
547        working++;
548    } else if (*working == '+') {
549        working++;
550    }
551    while (*working == '0') {
552        working++;
553    }
554
555    size_t length = strlen(working);
556    if (length == 0) { // the number is zero
557        return;
558    }
559    int curDigit = 0;
560    while (curDigit + 1 < sizeof(r->digits) / sizeof(r->digits[0]) && 9 < length) {
561        uint32_t digit = atol(working+length-9);
562        r->digits[curDigit] = digit;
563        *(working+length-9) = 0;
564        length -= 9;
565        curDigit++;
566    }
567    uint32_t digit = atol(working);
568    r->digits[curDigit] = digit;
569    free(copy);
570}
571
572char *_CFBigNumCopyDescription(const _CFBigNum *num) {
573    char *result = (char *)calloc(1024, sizeof(char));
574    sprintf(result, "sign:%s 1st:%u 2nd:%u 3rd:%u 4th:%u 5th:%u", num->sign < 0 ? "-" : "+", num->digits[0], num->digits[1], num->digits[2], num->digits[3], num->digits[4]);
575    return result;
576}
577
578