| // Copyright 2014 PDFium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Original code by Matt McCutchen, see the LICENSE file. |
| |
| #include "BigUnsignedInABase.hh" |
| |
| BigUnsignedInABase::BigUnsignedInABase(const Digit *d, Index l, Base base) |
| : NumberlikeArray<Digit>(d, l), base(base) { |
| // Check the base |
| if (base < 2) |
| abort(); |
| |
| // Validate the digits. |
| for (Index i = 0; i < l; i++) |
| if (blk[i] >= base) |
| abort(); |
| |
| // Eliminate any leading zeros we may have been passed. |
| zapLeadingZeros(); |
| } |
| |
| namespace { |
| unsigned int bitLen(unsigned int x) { |
| unsigned int len = 0; |
| while (x > 0) { |
| x >>= 1; |
| len++; |
| } |
| return len; |
| } |
| unsigned int ceilingDiv(unsigned int a, unsigned int b) { |
| return (a + b - 1) / b; |
| } |
| } |
| |
| BigUnsignedInABase::BigUnsignedInABase(const BigUnsigned &x, Base base) { |
| // Check the base |
| if (base < 2) |
| abort(); |
| this->base = base; |
| |
| // Get an upper bound on how much space we need |
| int maxBitLenOfX = x.getLength() * BigUnsigned::N; |
| int minBitsPerDigit = bitLen(base) - 1; |
| int maxDigitLenOfX = ceilingDiv(maxBitLenOfX, minBitsPerDigit); |
| len = maxDigitLenOfX; // Another change to comply with `staying in bounds'. |
| allocate(len); // Get the space |
| |
| BigUnsigned x2(x), buBase(base); |
| Index digitNum = 0; |
| |
| while (!x2.isZero()) { |
| // Get last digit. This is like `lastDigit = x2 % buBase, x2 /= buBase'. |
| BigUnsigned lastDigit(x2); |
| lastDigit.divideWithRemainder(buBase, x2); |
| // Save the digit. |
| blk[digitNum] = lastDigit.toUnsignedShort(); |
| // Move on. We can't run out of room: we figured it out above. |
| digitNum++; |
| } |
| |
| // Save the actual length. |
| len = digitNum; |
| } |
| |
| BigUnsignedInABase::operator BigUnsigned() const { |
| BigUnsigned ans(0), buBase(base), temp; |
| Index digitNum = len; |
| while (digitNum > 0) { |
| digitNum--; |
| temp.multiply(ans, buBase); |
| ans.add(temp, BigUnsigned(blk[digitNum])); |
| } |
| return ans; |
| } |
| |
| BigUnsignedInABase::BigUnsignedInABase(const std::string &s, Base base) { |
| // Check the base. |
| if (base > 36) |
| abort(); |
| // Save the base. |
| // This pattern is seldom seen in C++, but the analogous ``this.'' is common in Java. |
| this->base = base; |
| |
| // `s.length()' is a `size_t', while `len' is a `NumberlikeArray::Index', |
| // also known as an `unsigned int'. Some compilers warn without this cast. |
| len = Index(s.length()); |
| allocate(len); |
| |
| Index digitNum, symbolNumInString; |
| for (digitNum = 0; digitNum < len; digitNum++) { |
| symbolNumInString = len - 1 - digitNum; |
| char theSymbol = s[symbolNumInString]; |
| if (theSymbol >= '0' && theSymbol <= '9') |
| blk[digitNum] = theSymbol - '0'; |
| else if (theSymbol >= 'A' && theSymbol <= 'Z') |
| blk[digitNum] = theSymbol - 'A' + 10; |
| else if (theSymbol >= 'a' && theSymbol <= 'z') |
| blk[digitNum] = theSymbol - 'a' + 10; |
| else |
| abort(); |
| |
| if (blk[digitNum] >= base) |
| abort(); |
| } |
| zapLeadingZeros(); |
| } |
| |
| BigUnsignedInABase::operator std::string() const { |
| if (base > 36) |
| abort(); |
| if (len == 0) |
| return std::string("0"); |
| // Some compilers don't have push_back, so use a char * buffer instead. |
| char *s = new char[len + 1]; |
| s[len] = '\0'; |
| Index digitNum, symbolNumInString; |
| for (symbolNumInString = 0; symbolNumInString < len; symbolNumInString++) { |
| digitNum = len - 1 - symbolNumInString; |
| Digit theDigit = blk[digitNum]; |
| if (theDigit < 10) |
| s[symbolNumInString] = char('0' + theDigit); |
| else |
| s[symbolNumInString] = char('A' + theDigit - 10); |
| } |
| std::string s2(s); |
| delete [] s; |
| return s2; |
| } |