GME
13
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one or more 00003 * contributor license agreements. See the NOTICE file distributed with 00004 * this work for additional information regarding copyright ownership. 00005 * The ASF licenses this file to You under the Apache License, Version 2.0 00006 * (the "License"); you may not use this file except in compliance with 00007 * the License. You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* 00019 * $Id: XMLBigDecimal.cpp 557254 2007-07-18 13:28:54Z amassari $ 00020 */ 00021 00022 // --------------------------------------------------------------------------- 00023 // Includes 00024 // --------------------------------------------------------------------------- 00025 #include <xercesc/util/XMLBigDecimal.hpp> 00026 #include <xercesc/util/XMLBigInteger.hpp> 00027 #include <xercesc/util/TransService.hpp> 00028 #include <xercesc/util/NumberFormatException.hpp> 00029 #include <xercesc/util/XMLChar.hpp> 00030 #include <xercesc/util/OutOfMemoryException.hpp> 00031 #include <xercesc/util/Janitor.hpp> 00032 00033 XERCES_CPP_NAMESPACE_BEGIN 00034 00051 typedef JanitorMemFunCall<XMLBigDecimal> CleanupType; 00052 00053 XMLBigDecimal::XMLBigDecimal(const XMLCh* const strValue, 00054 MemoryManager* const manager) 00055 : fSign(0) 00056 , fTotalDigits(0) 00057 , fScale(0) 00058 , fRawDataLen(0) 00059 , fRawData(0) 00060 , fIntVal(0) 00061 , fMemoryManager(manager) 00062 { 00063 if ((!strValue) || (!*strValue)) 00064 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_emptyString, fMemoryManager); 00065 00066 CleanupType cleanup(this, &XMLBigDecimal::cleanUp); 00067 00068 try 00069 { 00070 fRawDataLen = XMLString::stringLen(strValue); 00071 fRawData = (XMLCh*) fMemoryManager->allocate 00072 ( 00073 ((fRawDataLen*2) + 2) * sizeof(XMLCh) //fRawData and fIntVal 00074 ); 00075 memcpy(fRawData, strValue, fRawDataLen * sizeof(XMLCh)); 00076 fRawData[fRawDataLen] = chNull; 00077 fIntVal = fRawData + fRawDataLen + 1; 00078 parseDecimal(strValue, fIntVal, fSign, (int&) fTotalDigits, (int&) fScale, fMemoryManager); 00079 } 00080 catch(const OutOfMemoryException&) 00081 { 00082 cleanup.release(); 00083 00084 throw; 00085 } 00086 00087 cleanup.release(); 00088 } 00089 00090 XMLBigDecimal::~XMLBigDecimal() 00091 { 00092 cleanUp(); 00093 } 00094 00095 void XMLBigDecimal::cleanUp() 00096 { 00097 if (fRawData) 00098 fMemoryManager->deallocate(fRawData); //XMLString::release(&fRawData); 00099 } 00100 00101 void XMLBigDecimal::setDecimalValue(const XMLCh* const strValue) 00102 { 00103 fScale = fTotalDigits = 0; 00104 XMLSize_t valueLen = XMLString::stringLen(strValue); 00105 00106 if (valueLen > fRawDataLen) 00107 { 00108 fMemoryManager->deallocate(fRawData); 00109 fRawData = (XMLCh*) fMemoryManager->allocate 00110 ( 00111 ((valueLen * 2) + 4) * sizeof(XMLCh) 00112 );//XMLString::replicate(strValue, fMemoryManager); 00113 } 00114 00115 memcpy(fRawData, strValue, valueLen * sizeof(XMLCh)); 00116 fRawData[valueLen] = chNull; 00117 fRawDataLen = valueLen; 00118 fIntVal = fRawData + fRawDataLen + 1; 00119 parseDecimal(strValue, fIntVal, fSign, (int&) fTotalDigits, (int&) fScale, fMemoryManager); 00120 00121 } 00122 00123 /*** 00124 * 3.2.3 decimal 00125 * 00126 * . the preceding optional "+" sign is prohibited. 00127 * . The decimal point is required. 00128 * . Leading and trailing zeroes are prohibited subject to the following: 00129 * there must be at least one digit to the right and to the left of the decimal point which may be a zero. 00130 * 00131 ***/ 00132 XMLCh* XMLBigDecimal::getCanonicalRepresentation(const XMLCh* const rawData 00133 , MemoryManager* const memMgr) 00134 { 00135 00136 XMLCh* retBuf = (XMLCh*) memMgr->allocate( (XMLString::stringLen(rawData)+1) * sizeof(XMLCh)); 00137 ArrayJanitor<XMLCh> janName(retBuf, memMgr); 00138 int sign, totalDigits, fractDigits; 00139 00140 try 00141 { 00142 parseDecimal(rawData, retBuf, sign, totalDigits, fractDigits, memMgr); 00143 } 00144 catch (const NumberFormatException&) 00145 { 00146 return 0; 00147 } 00148 00149 00150 //Extra space reserved in case strLen is zero 00151 XMLSize_t strLen = XMLString::stringLen(retBuf); 00152 XMLCh* retBuffer = (XMLCh*) memMgr->allocate( (strLen + 4) * sizeof(XMLCh)); 00153 00154 if ( (sign == 0) || (totalDigits == 0)) 00155 { 00156 retBuffer[0] = chDigit_0; 00157 retBuffer[1] = chPeriod; 00158 retBuffer[2] = chDigit_0; 00159 retBuffer[3] = chNull; 00160 } 00161 else 00162 { 00163 XMLCh* retPtr = retBuffer; 00164 00165 if (sign == -1) 00166 { 00167 *retPtr++ = chDash; 00168 } 00169 00170 if (fractDigits == totalDigits) // no integer 00171 { 00172 *retPtr++ = chDigit_0; 00173 *retPtr++ = chPeriod; 00174 XMLString::copyNString(retPtr, retBuf, strLen); 00175 retPtr += strLen; 00176 *retPtr = chNull; 00177 } 00178 else if (fractDigits == 0) // no fraction 00179 { 00180 XMLString::copyNString(retPtr, retBuf, strLen); 00181 retPtr += strLen; 00182 *retPtr++ = chPeriod; 00183 *retPtr++ = chDigit_0; 00184 *retPtr = chNull; 00185 } 00186 else // normal 00187 { 00188 int intLen = totalDigits - fractDigits; 00189 XMLString::copyNString(retPtr, retBuf, intLen); 00190 retPtr += intLen; 00191 *retPtr++ = chPeriod; 00192 XMLString::copyNString(retPtr, &(retBuf[intLen]), fractDigits); 00193 retPtr += fractDigits; 00194 *retPtr = chNull; 00195 } 00196 00197 } 00198 00199 return retBuffer; 00200 } 00201 00202 void XMLBigDecimal::parseDecimal(const XMLCh* const toParse 00203 , XMLCh* const retBuffer 00204 , int& sign 00205 , int& totalDigits 00206 , int& fractDigits 00207 , MemoryManager* const manager) 00208 { 00209 //init 00210 retBuffer[0] = chNull; 00211 totalDigits = 0; 00212 fractDigits = 0; 00213 00214 // Strip leading white space, if any. 00215 const XMLCh* startPtr = toParse; 00216 while (XMLChar1_0::isWhitespace(*startPtr)) 00217 startPtr++; 00218 00219 // If we hit the end, then return failure 00220 if (!*startPtr) 00221 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_WSString, manager); 00222 00223 // Strip tailing white space, if any. 00224 const XMLCh* endPtr = toParse + XMLString::stringLen(toParse); 00225 while (XMLChar1_0::isWhitespace(*(endPtr - 1))) 00226 endPtr--; 00227 00228 // '+' or '-' is allowed only at the first position 00229 // and is NOT included in the return parsed string 00230 sign = 1; 00231 if (*startPtr == chDash) 00232 { 00233 sign = -1; 00234 startPtr++; 00235 if (startPtr == endPtr) 00236 { 00237 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, manager); 00238 } 00239 } 00240 else if (*startPtr == chPlus) 00241 { 00242 startPtr++; 00243 if (startPtr == endPtr) 00244 { 00245 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, manager); 00246 } 00247 } 00248 00249 // Strip leading zeros 00250 while (*startPtr == chDigit_0) 00251 startPtr++; 00252 00253 // containning zero, only zero, nothing but zero 00254 // it is a zero, indeed 00255 if (startPtr >= endPtr) 00256 { 00257 sign = 0; 00258 return; 00259 } 00260 00261 XMLCh* retPtr = (XMLCh*) retBuffer; 00262 00263 // Scan data 00264 bool dotSignFound = false; 00265 while (startPtr < endPtr) 00266 { 00267 if (*startPtr == chPeriod) 00268 { 00269 if (!dotSignFound) 00270 { 00271 dotSignFound = true; 00272 fractDigits = (int)(endPtr - startPtr - 1); 00273 startPtr++; 00274 continue; 00275 } 00276 else // '.' is allowed only once 00277 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_2ManyDecPoint, manager); 00278 } 00279 00280 // If not valid decimal digit, then an error 00281 if ((*startPtr < chDigit_0) || (*startPtr > chDigit_9)) 00282 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, manager); 00283 00284 // copy over 00285 *retPtr++ = *startPtr++; 00286 totalDigits++; 00287 } 00288 00289 /*** 00290 E2-44 totalDigits 00291 00292 ... by restricting it to numbers that are expressible as i x 10^-n 00293 where i and n are integers such that |i| < 10^totalDigits and 0 <= n <= totalDigits. 00294 00295 normalization: remove all trailing zero after the '.' 00296 and adjust the scaleValue as well. 00297 ***/ 00298 while ((fractDigits > 0) && (*(retPtr-1) == chDigit_0)) 00299 { 00300 retPtr--; 00301 fractDigits--; 00302 totalDigits--; 00303 } 00304 // 0.0 got past the check for zero because of the decimal point, so we need to double check it here 00305 if(totalDigits==0) 00306 sign = 0; 00307 00308 *retPtr = chNull; //terminated 00309 return; 00310 } 00311 00312 void XMLBigDecimal::parseDecimal(const XMLCh* const toParse 00313 , MemoryManager* const manager) 00314 { 00315 00316 // Strip leading white space, if any. 00317 const XMLCh* startPtr = toParse; 00318 while (XMLChar1_0::isWhitespace(*startPtr)) 00319 startPtr++; 00320 00321 // If we hit the end, then return failure 00322 if (!*startPtr) 00323 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_WSString, manager); 00324 00325 // Strip tailing white space, if any. 00326 const XMLCh* endPtr = toParse + XMLString::stringLen(toParse); 00327 while (XMLChar1_0::isWhitespace(*(endPtr - 1))) 00328 endPtr--; 00329 00330 // '+' or '-' is allowed only at the first position 00331 // and is NOT included in the return parsed string 00332 00333 if (*startPtr == chDash) 00334 { 00335 startPtr++; 00336 if (startPtr == endPtr) 00337 { 00338 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, manager); 00339 } 00340 } 00341 else if (*startPtr == chPlus) 00342 { 00343 startPtr++; 00344 if (startPtr == endPtr) 00345 { 00346 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, manager); 00347 } 00348 } 00349 00350 // Strip leading zeros 00351 while (*startPtr == chDigit_0) 00352 startPtr++; 00353 00354 // containning zero, only zero, nothing but zero 00355 // it is a zero, indeed 00356 if (startPtr >= endPtr) 00357 { 00358 return; 00359 } 00360 00361 // Scan data 00362 bool dotSignFound = false; 00363 while (startPtr < endPtr) 00364 { 00365 if (*startPtr == chPeriod) 00366 { 00367 if (!dotSignFound) 00368 { 00369 dotSignFound = true; 00370 startPtr++; 00371 continue; 00372 } 00373 else // '.' is allowed only once 00374 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_2ManyDecPoint, manager); 00375 } 00376 00377 // If not valid decimal digit, then an error 00378 if ((*startPtr < chDigit_0) || (*startPtr > chDigit_9)) 00379 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_Inv_chars, manager); 00380 00381 startPtr++; 00382 00383 } 00384 00385 return; 00386 } 00387 00388 int XMLBigDecimal::compareValues( const XMLBigDecimal* const lValue 00389 , const XMLBigDecimal* const rValue 00390 , MemoryManager* const manager) 00391 { 00392 if ((!lValue) || (!rValue) ) 00393 ThrowXMLwithMemMgr(NumberFormatException, XMLExcepts::XMLNUM_null_ptr, manager); 00394 00395 return lValue->toCompare(*rValue); 00396 } 00397 00405 int XMLBigDecimal::toCompare(const XMLBigDecimal& other) const 00406 { 00407 /*** 00408 * different sign 00409 */ 00410 int lSign = this->getSign(); 00411 if (lSign != other.getSign()) 00412 return (lSign > other.getSign() ? 1 : -1); 00413 00414 /*** 00415 * same sign, zero 00416 */ 00417 if (lSign == 0) // optimization 00418 return 0; 00419 00420 /*** 00421 * same sign, non-zero 00422 */ 00423 unsigned int lIntDigit = this->getTotalDigit() - this->getScale(); 00424 unsigned int rIntDigit = other.getTotalDigit() - other.getScale(); 00425 00426 if (lIntDigit > rIntDigit) 00427 { 00428 return 1 * lSign; 00429 } 00430 else if (lIntDigit < rIntDigit) 00431 { 00432 return -1 * lSign; 00433 } 00434 else // compare fraction 00435 { 00436 int res = XMLString::compareString 00437 ( this->getValue() 00438 , other.getValue() 00439 ); 00440 00441 if (res > 0) 00442 return 1 * lSign; 00443 else if (res < 0) 00444 return -1 * lSign; 00445 else 00446 return 0; 00447 } 00448 00449 } 00450 00451 00452 /*** 00453 * Support for Serialization/De-serialization 00454 ***/ 00455 00456 IMPL_XSERIALIZABLE_TOCREATE(XMLBigDecimal) 00457 00458 XMLBigDecimal::XMLBigDecimal(MemoryManager* const manager) 00459 : fSign(0) 00460 , fTotalDigits(0) 00461 , fScale(0) 00462 , fRawDataLen(0) 00463 , fRawData(0) 00464 , fIntVal(0) 00465 , fMemoryManager(manager) 00466 { 00467 } 00468 00469 void XMLBigDecimal::serialize(XSerializeEngine& serEng) 00470 { 00471 //REVISIT: may not need to call base since it does nothing 00472 XMLNumber::serialize(serEng); 00473 00474 if (serEng.isStoring()) 00475 { 00476 serEng<<fSign; 00477 serEng<<fTotalDigits; 00478 serEng<<fScale; 00479 00480 serEng.writeString(fRawData); 00481 serEng.writeString(fIntVal); 00482 00483 } 00484 else 00485 { 00486 serEng>>fSign; 00487 serEng>>fTotalDigits; 00488 serEng>>fScale; 00489 00490 XMLCh* rawdataStr; 00491 serEng.readString(rawdataStr); 00492 ArrayJanitor<XMLCh> rawdataName(rawdataStr, serEng.getMemoryManager()); 00493 fRawDataLen = XMLString::stringLen(rawdataStr); 00494 00495 XMLCh* intvalStr; 00496 serEng.readString(intvalStr); 00497 ArrayJanitor<XMLCh> intvalName(intvalStr, serEng.getMemoryManager()); 00498 XMLSize_t intvalStrLen = XMLString::stringLen(intvalStr); 00499 00500 if (fRawData) 00501 fMemoryManager->deallocate(fRawData); 00502 00503 fRawData = (XMLCh*) fMemoryManager->allocate 00504 ( 00505 ((fRawDataLen + intvalStrLen) + 4) * sizeof(XMLCh) 00506 ); 00507 00508 memcpy(fRawData, rawdataStr, fRawDataLen * sizeof(XMLCh)); 00509 fRawData[fRawDataLen] = chNull; 00510 fIntVal = fRawData + fRawDataLen + 1; 00511 memcpy(fIntVal, intvalStr, intvalStrLen * sizeof(XMLCh)); 00512 fIntVal[intvalStrLen] = chNull; 00513 00514 } 00515 00516 } 00517 00518 XERCES_CPP_NAMESPACE_END 00519